使用ServiceStack Rest-API下载文件

时间:2017-12-08 09:29:02

标签: c# rest file download servicestack

我对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();
    }
}

2 个答案:

答案 0 :(得分:2)

下载文件的简便方法是在HttpResult中返回fileInfo,例如:

return new HttpResult(new FileInfo(fileFullPath), asAttachment:true);

或使用Virtual File System

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();
    }
}