【问题标题】:Does ServiceStack support binary responses?ServiceStack 是否支持二进制响应?
【发布时间】:2011-09-08 21:24:09
【问题描述】:

ServiceStack 服务中是否有任何机制来返回流式/大型二进制数据? WCF 的 MTOM 支持很笨拙,但可以有效地返回大量数据而没有文本转换开销。

【问题讨论】:

    标签: servicestack


    【解决方案1】:

    我喜欢服务堆栈,这个小代码足以从内存流中返回 Excel 报告

    public class ExcelFileResult : IHasOptions, IStreamWriter
    {
        private readonly Stream _responseStream;
        public IDictionary<string, string> Options { get; private set; }
    
        public ExcelFileResult(Stream responseStream)
        {
            _responseStream = responseStream;
    
            Options = new Dictionary<string, string> {
                 {"Content-Type", "application/octet-stream"},
                 {"Content-Disposition", "attachment; filename=\"report.xls\";"}
             };
        }
    
        public void WriteTo(Stream responseStream)
        {
            if (_responseStream == null) 
                return;
    
            _responseStream.WriteTo(responseStream);
            responseStream.Flush();
        }
    }
    

    【讨论】:

    • _responseStream.WriteTo 来自哪里?这不是 Stream 方法。
    • ServiceStack 提供附加功能作为许多 BCL 类的扩展方法。 Stream.WriteTo 位于 ServiceStack.Text.StreamExtensions.WriteTo
    • IoC(控制反转)(又名 DI - 依赖注入)通过构造函数参数。
    【解决方案2】:

    鸟瞰ServiceStack可以返回任何一个:

    • 任何 DTO 对象 -> 序列化为 Response ContentType
    • 用于自定义 HTTP 响应的 HttpResult、HttpError、CompressedResult (IHttpResult)

    以下类型不会被转换并直接写入响应流:

    • 字符串
    • IStreamWriter
    • byte[] - 使用 application/octet-stream 内容类型。

    详情

    除了返回普通的 C# 对象之外,ServiceStack 还允许您返回任何 Stream 或 IStreamWriter(在写入响应流的方式上更灵活一些):

    public interface IStreamWriter
    {
        void WriteTo(Stream stream);
    }
    

    虽然两者都允许您直接写入 Response OutputStream 而无需任何额外的转换开销。

    如果您想同时自定义 HTTP 标头,您只需要实现IHasOptions,其中任何字典条目都会写入响应 HttpHeaders。

    public interface IHasOptions
    {
        IDictionary<string, string> Options { get; }
    }
    

    除此之外,IHttpResult 允许对 HTTP 输出进行更细粒度的控制,您可以在其中提供自定义 Http 响应状态代码。您可以参考HttpResult 对象的实现,了解上述这些接口的实际实现。

    【讨论】:

    • 因此基本概念与类似 MTOM 的 WCF 服务相同,其中原始二进制(或其他)响应是服务的“真实”结果,任何其他元数据都必须返回标题。
    • 没错,流按原样写入 ResponseStream(即没有包装器),元数据写入标头。
    【解决方案3】:

    我有一个类似的要求,也要求我跟踪流文件下载的进度。我大致是这样做的:

    服务器端

    服务:

    public object Get(FooRequest request)
    {
        var stream = ...//some Stream
        return new StreamedResult(stream);
    }
    

    StreamedResult 类:

    public class StreamedResult : IHasOptions, IStreamWriter
    {
        public IDictionary<string, string> Options { get; private set; }
        Stream _responseStream;
    
        public StreamedResult(Stream responseStream)
        {
            _responseStream = responseStream;
    
            long length = -1;
            try { length = _responseStream.Length; }
            catch (NotSupportedException) { }
    
            Options = new Dictionary<string, string>
            {
                {"Content-Type", "application/octet-stream"},
                { "X-Api-Length", length.ToString() }
            };
        }
    
        public void WriteTo(Stream responseStream)
        {
            if (_responseStream == null)
                return;
    
            using (_responseStream)
            {
                _responseStream.WriteTo(responseStream);
                responseStream.Flush();
            }
        }
    }
    

    客户端

    string path = Path.GetTempFileName();//in reality, wrap this in try... so as not to leave hanging tmp files
    var response = client.Get<HttpWebResponse>("/foo/bar");
    
    long length;
    if (!long.TryParse(response.GetResponseHeader("X-Api-Length"), out length))
        length = -1;
    
    using (var fs = System.IO.File.OpenWrite(path))
        fs.CopyFrom(response.GetResponseStream(), new CopyFromArguments(new ProgressChange((x, y) => { Console.WriteLine(">> {0} {1}".Fmt(x, y)); }), TimeSpan.FromMilliseconds(100), length));
    

    “CopyFrom”扩展方法是直接从本项目中的源代码文件“StreamHelper.cs”借用的:Copy a Stream with Progress Reporting(感谢 Henning Dieterichs)

    感谢mythz 和ServiceStack 的任何贡献者。很棒的项目!

    【讨论】:

      猜你喜欢
      • 2021-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-11
      • 2010-09-08
      • 1970-01-01
      • 2015-09-03
      相关资源
      最近更新 更多