15

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

4

3 回答 3

19

我喜欢服务堆栈,这个小代码足以从内存流中返回 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();
    }
}
于 2012-03-23T17:18:14.160 回答
16

从鸟瞰的角度来看, 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对象的实现,以了解上述这些接口的实际实现。

于 2011-06-06T07:44:10.947 回答
4

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

服务器端

服务:

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 (Kudos to Henning Dieterichs)

对 mythz 和 ServiceStack 的任何贡献者表示敬意。伟大的项目!

于 2013-10-08T15:34:42.757 回答