之前做的WPF项目有遇到过需要从服务端下载图片到本地的指定目录的情况,客户端页面绑定这个图片所在目录的路径,用来加载这个图片,而图片路径保存在本地的数据库中。
关于这些产品文字信息图片路径信息都是存在本地需要定时更新的,一般在登录客户端时后台会开启线程去检索本地表数据是否是最新的,如果有更新则需要从服务端下载最新的数据。那么图片或者其他文件也是一样的情况,需要更新或者新增到指定目录下。
这里的做法是将这些图片或者文件保存在服务器一个指定的共享目录下,通过api获取到图片并保存在本地目录。
服务端API:
1定义一个ContentTypeCondition类,用来传递下载文件的参数信,如下:其中PackageFileName 是图片的路径,从数据库取得,后面会提到前端下载的逻辑
public class ContentTypeCondition
{
public string ID
{
get;
set;
}
public string ContentType
{
get;
set;
}
public string ConfigFileName
{
get;
set;
}
public string PackageFileName
{
get;
set;
}
}
在对应的Controller下写下下载文件的Method(DownloadContentFile),代码如下:
[HttpGet]
public HttpResponseMessage DownloadContentFile([FromUri]ContentTypeCondition entity)
{
string file = Path.Combine(C2Global.Server.Architect.Common.GlobalServerConfig.ProductPath, entity.PackageFileName);
if (!FileProvider.Exists(file))
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
FileStream fileStream = FileProvider.Open(file);
try
{
var response = new HttpResponseMessage();
response.Content = new StreamContent(fileStream);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "test.zip";
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentLength = FileProvider.GetLength(file);
return response;
}
catch (Exception ex)
{
fileStream.Close();
return null;
}
}
这段代码中,首先是给文件所在服务器的路径赋值(Path.Combine),然后判断这个文件是否存在,如果存在则读取这个文件返回FileStream类型,最后定义返回的httpreponsemessage,并将content的内容和headers信息赋值。
这里面封装了一个FileProvider类,这个类包含文件的基本操作(文件是否存在,文件的长度,打开文件为FileStream),代码如下:
public interface IFileProvider
{
bool Exists(string name);
FileStream Open(string name);
long GetLength(string name);
}
public IFileProvider FileProvider { get; set; }
public DownloadFileController()
{
FileProvider = new FileProviderUtilty();
}
public class FileProviderUtilty : IFileProvider
{
private readonly string _filesDirectory;
private string fileName = string.Empty;
public bool Exists(string name)
{
//string fileName = GetFilePath(name);
//make sure we dont access directories outside of our store for security reasons
bool exitsFile = File.Exists(name);
return exitsFile;
}
public FileStream Open(string path)
{
return File.Open(path, FileMode.Open, FileAccess.Read,FileShare.Read);
}
public long GetLength(string name)
{
return new FileInfo(name).Length;
}
//private string GetFilePath(string name)
//{
// string file= ConfigurationManager.AppSettings[name];
// return file;
//}
}
至此服务端API就算完成了
前端调用过程
我这里定义了一个对象ContentDownloadInfoDto 用来传递下载文件的信息参数(主要是传递服务端文件路径和客户端保存文件的路径)
具体调用过程如下:
///
/// 下载product图片
///
///
///
public virtual bool DownloadContentFile(ContentDownloadInfoDto downloadInfo)
{
ContentTypeCondition condition = new ContentTypeCondition();
condition.PackageFileName = HttpUtility.UrlEncode(downloadInfo.PackageFileName, Encoding.UTF8);
if (string.IsNullOrEmpty(condition.PackageFileName))
{
return false;
}
string url = GlobalClientConfig.BaseURI + DownloadFileWebAPI.WEB_API_NAME + "/" + DownloadFileWebAPI.DOWNLOAD_PRODUCT_PACKAGE + "/";
Stream configFileStream = RestServiceProxy.GetFile(condition, url);
if (configFileStream.Length == 0)
{
return false;
}
else
{
FileHelper.SaveFileFromStream(configFileStream, downloadInfo.TargetPackageFileName);
return true;
}
}
其中封装了RestServiceProxy 调用API的一个类,内含各种访问API的方法,这个在这边不做赘述
在前端调用服务端API后,获取到Stream类型的返回值,再通过封装的FileHelper.SaveFileFromStream保存到目标路径下(TargetPackageFileName)
FileHelper代码如下:
public class FileHelper
{
public static void SaveFileFromStream(Stream s, string file)
{
//get folder name
string folder = file.Substring(0, file.LastIndexOf("\\"));
if(!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
// Create a FileStream object to write a stream to a file
using (FileStream fileStream = System.IO.File.Create(file, (int)s.Length))
{
// Fill the bytes[] array with the stream data
byte[] bytesInStream = new byte[s.Length];
s.Read(bytesInStream, 0, (int)bytesInStream.Length);
// Use FileStream object to write to the specified file
fileStream.Write(bytesInStream, 0, bytesInStream.Length);
}
}
}