[英]Download files with ServiceStack Rest-API
I'm quite new to REST-services in general and I'm playing around with ServiceStack (which is awesome!).总的来说,我对 REST 服务很陌生,我正在使用 ServiceStack(这太棒了!)。 I have some services running and now I want to be able to download files (zip) via the service.
我有一些服务正在运行,现在我希望能够通过该服务下载文件 (zip)。
My idea is to set a route (/download) to receive files and download them with the client to store them locally.我的想法是设置一个路由(/download)来接收文件并用客户端下载它们以将它们存储在本地。
My current approach looks like this:我目前的方法是这样的:
[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;
}
}
I'd like to change this implementation to send data as stream.我想更改此实现以将数据作为流发送。 I stumbled upon IStreamWriterAsync, but couldn't really find documentation on usage for this.
我偶然发现了 IStreamWriterAsync,但无法真正找到有关此用法的文档。 I'd also like to be able to handle client-side download with the ServiceStack C#-Client.
我还希望能够使用 ServiceStack C#-Client 处理客户端下载。
What would be a good strategy do implement my plan?实施我的计划的好策略是什么?
Edit: Something like that?编辑:类似的东西?
[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();
}
}
An easy way to download a file is to return the fileInfo in a HttpResult, eg:下载文件的一种简单方法是在 HttpResult 中返回 fileInfo,例如:
return new HttpResult(new FileInfo(fileFullPath), asAttachment:true);
Or by using the Virtual File System或者通过使用虚拟文件系统
return new HttpResult(
VirtualFileSources.GetFile(virtualPath), asAttachment:true);
Both of these APIs already write the file bytes as a Stream so there's no need to try manually doing it yourself.这两个 API 都已经将文件字节写为 Stream,因此无需尝试自己手动执行。
Note: HttpResult
is just a server wrapper object not the response body itself so it should never be used in an IReturn<T>
interface whose purpose is to tell clients what Response Type the Service returns.注意:
HttpResult
只是一个服务器包装器对象,而不是响应主体本身,因此它永远不应该用在IReturn<T>
接口中,该接口的目的是告诉客户端服务返回什么响应类型。
The IReturn<T>
should specify what the Response Body is, in this case since it's not a Response DTO it can be either: IReturn<T>
应该指定响应主体是什么,在这种情况下,因为它不是响应 DTO,它可以是:
IReturn<byte[]> or IReturn<Stream>
Or you can just leave it unspecified as you'll still be able to download it using the ServiceClient's raw data APIs :或者您可以不指定它,因为您仍然可以使用ServiceClient 的原始数据 API下载它:
With IReturn<Stream>
interface:使用
IReturn<Stream>
接口:
using (Stream stream = client.Get(new DownloadRequest())) {
...
}
Or you can just easily download the response as a Stream without the IReturn<T>
by specifying how you want to access the raw data on the call-site, eg:或者,您可以通过指定您希望如何访问调用站点上的原始数据,轻松地将响应下载为 Stream 而不使用
IReturn<T>
,例如:
Stream stream = client.Get<Stream>(new DownloadRequest());
byte[] bytes = client.Get<byte[]>("/download");
If you want to also access the Response HTTP Headers you can also request the raw HttpWebResponse
to be returned which will let you access the Response HTTP Headers:如果您还想访问响应 HTTP 标头,您还可以请求返回原始
HttpWebResponse
,这将允许您访问响应 HTTP 标头:
using (var webRes = client.Get<HttpWebResponse>(new DownloadRequest()))
using (var stream = webRes.GetResponseStream())
{
var contentDisposition = webRes.Headers[HttpHeaders.ContentDisposition];
}
Alternatively you can also use HTTP Utils to download arbitrary files, eg:或者,您也可以使用HTTP Utils下载任意文件,例如:
string info = null;
var bytes = baseUrl.CombineWith("download").GetBytesFromUrl(
responseFilter: res => info = res.Headers[HttpHeaders.ContentDisposition]);
Have a look at this article.看看这篇文章。 Basically, just return a
Stream
.基本上,只需返回一个
Stream
。 You can use fi.OpenRead and return that stream.您可以使用fi.OpenRead并返回该流。
To combine headers and stream, an option is a custom return type instead, something like this要组合标题和流,一个选项是自定义返回类型,就像这样
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();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.