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