Поддерживает ли ServiceStack двоичные ответы?

Есть ли какой-либо механизм в службах ServiceStack для возврата потоковых/больших двоичных данных? Поддержка WCF MTOM неудобна, но эффективна при возврате больших объемов данных без накладных расходов на преобразование текста.

Ответ 1

С высоты птичьего полета ServiceStack может возвращать любой из:

  • Любой объект DTO → сериализован для Response ContentType
  • HttpResult, HttpError, CompressedResult (IHttpResult) для персонализированного HTTP-ответа

Следующие типы не преобразуются и записываются непосредственно в поток ответов:

  • Строка
  • Поток
  • IStreamWriter
  • byte [] - с типом содержимого application/octet-stream.

Подробнее

В дополнение к возврату простых объектов С# 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 для реализации этих выше интерфейсов в реальном мире.

Ответ 2

Мне нравится стек службы, этого кода litle достаточно, чтобы вернуть отчет 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();
    }
}

Ответ 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" в этом проекте здесь: Копировать поток с отчетностью о ходе выполнения (Kudos Хеннинг Дитерихс)

И пригодился мифцу и любому вкладчику ServiceStack. Отличный проект!