我对REST服务一般都很陌生,而且我正在玩ServiceStack(非常棒!)。我有一些服务正在运行,现在我希望能够通过该服务下载文件(zip)。
我的想法是设置一个路由(/下载)来接收文件并通过客户端下载它们以在本地存储它们。
我目前的做法如下:
[Route("/download")]
public class DownloadRequest : IReturn<HttpResult>
{
}
public class FileDownloadService : Service
{
public object Any(DownloadRequest request)
{
string fileFullPath = @"C:\Users\marcel\Downloads\test.zip";
string mimeType = "application/zip";
FileInfo fi = new FileInfo(fileFullPath);
byte[] reportBytes = File.ReadAllBytes(fi.FullName);
HttpResult result = new HttpResult(reportBytes, mimeType);
result.Headers.Add("Content-Disposition", "attachment;filename=Download.zip;");
return result;
}
}
我想更改此实现以将数据作为流发送。我偶然发现了IStreamWriterAsync,但无法找到有关此用法的文档。我还希望能够使用ServiceStack C#-Client处理客户端下载。
实施我的计划会有什么好策略?
编辑:那样的东西?
[Route("/download")]
public class DownloadRequest : IReturn<Stream>
{
}
public class FileDownloadService : Service, IHasOptions
{
public IDictionary<string, string> Options { get; private set; }
public Stream Any(DownloadRequest request)
{
string fileFullPath = @"C:\Users\marcel\Downloads\test.zip";
FileInfo fi = new FileInfo(fileFullPath);
Options = new Dictionary<string, string>
{
{"Content-Type","application/zip" },
{"Content-Disposition", "attachment;filename=Download.zip;" }
};
return fi.OpenRead();
}
}
答案 0 :(得分:2)
下载文件的简便方法是在HttpResult中返回fileInfo,例如:
return new HttpResult(new FileInfo(fileFullPath), asAttachment:true);
return new HttpResult(
VirtualFileSources.GetFile(virtualPath), asAttachment:true);
这两个API都已将文件字节写为Stream,因此无需亲自手动执行。
注意:HttpResult
只是一个服务器包装器对象,而不是响应主体本身,因此在IReturn<T>
接口中永远不应该,其目的是告诉客户端什么是Response输入服务返回。
IReturn<T>
应该指定响应主体是什么,在这种情况下,因为它不是响应DTO,它可以是:
IReturn<byte[]> or IReturn<Stream>
或者您可以不指定,因为您仍然可以使用ServiceClient's raw data APIs下载它:
使用IReturn<Stream>
界面:
using (Stream stream = client.Get(new DownloadRequest())) {
...
}
或者您可以通过指定如何访问呼叫站点上的原始数据,轻松地将响应作为流而不是IReturn<T>
下载,例如:
Stream stream = client.Get<Stream>(new DownloadRequest());
byte[] bytes = client.Get<byte[]>("/download");
如果您还想访问Response HTTP Headers,您还可以请求返回原始HttpWebResponse
,这将允许您访问Response HTTP Headers:
using (var webRes = client.Get<HttpWebResponse>(new DownloadRequest()))
using (var stream = webRes.GetResponseStream())
{
var contentDisposition = webRes.Headers[HttpHeaders.ContentDisposition];
}
或者您也可以使用HTTP Utils下载任意文件,例如:
string info = null;
var bytes = baseUrl.CombineWith("download").GetBytesFromUrl(
responseFilter: res => info = res.Headers[HttpHeaders.ContentDisposition]);
答案 1 :(得分:1)
查看this文章。基本上,只需返回Stream
。您可以使用fi.OpenRead并返回该流。
要组合标题和流,选项是自定义返回类型,类似于此
public class DownloadFileResult : IStreamWriterAsync, IHasOptions
{
private readonly Stream _stream;
public IDictionary<string, string> Options { get; }
public DownloadFileResult(Stream responseStream, string mime, string filename)
{
_stream = responseStream;
Options = new Dictionary<string, string>()
{
{"Content-Disposition", $"attachment; filename=\"{filename}\";"},
{"Content-Type", mime}
};
}
public async Task WriteToAsync(Stream responseStream, CancellationToken token)
{
if (_stream == null) {
return;
}
await _stream.CopyToAsync(responseStream);
responseStream.Flush();
}
}