ServiceStack サービスにストリーミング/大きなバイナリ データを返すメカニズムはありますか? WCF の MTOM サポートは扱いにくいですが、テキスト変換のオーバーヘッドなしで大量のデータを返すのに効果的です。
3 に答える
私はサービス スタックが大好きです。メモリ ストリームから 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();
}
}
概観すると、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 ヘッダーをカスタマイズする場合は、ディクショナリ エントリが応答 HttpHeaders に書き込まれるIHasOptionsを実装する必要があります。
public interface IHasOptions
{
IDictionary<string, string> Options { get; }
}
さらに、IHttpResult を使用すると、カスタムの HTTP 応答ステータス コードを指定できる HTTP 出力をさらに細かく制御できます。上記のインターフェイスの実際の実装については、 HttpResultオブジェクトの実装を参照できます。
同様の要件があり、ストリーミング ファイルのダウンロードの進行状況も追跡する必要がありました。私は大まかに次のようにしました:
サーバー側:
サービス:
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」から直接借用したものです:進行状況レポートを使用してストリームをコピーする(Henning Dieterichs に敬意を表します)
そして、mythz と ServiceStack への貢献者に敬意を表します。素晴らしいプロジェクトです!