3

ASP.NET Core 1.0 プロジェクトで、元のフレームワークの Http Response Stream を自分のものに置き換えるカスタム ミドルウェアを作成したいので、読み取り/シーク/書き込み操作を実行できます (最初の 2 つは元のフレームワークでは実行できません)。 stream) を追加のコード、つまりアクションまたはフィルターで使用します。

私は次のコードから始めました:

public class ReplaceStreamMiddleware
{
    protected RequestDelegate NextMiddleware;

    public ReplaceStreamMiddleware(RequestDelegate next)
    {
        NextMiddleware = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {       
        using (var responseStream = new MemoryStream())
        {
            var fullResponse = httpContext.Response.Body;
            httpContext.Response.Body = responseStream;
            await NextMiddleware.Invoke(httpContext);
            responseStream.Seek(0, SeekOrigin.Begin);
            await responseStream.CopyToAsync(fullResponse);
        }   
    }
}

次のコードの問題は、呼び出し時にストリームが既に閉じられている場合があるため、例外Cannot access a closed Stream. がスローされることです。fullResponseawait responseStream.CopyToAsync(fullResponse);

この奇妙な動作は、ブラウザにページをロードしてから完全にロードする前に更新すると簡単に観察できます。

私が知りたいのですが:

  1. なぜこれが起こるのですか?
  2. それを防ぐ方法は?
  3. 私の解決策は良い考えですか、それとも応答ストリームを置き換える別の方法がありますか?
4

1 に答える 1

8

例外はあなたのものではありませんCopyToAsync。コードの呼び出し元の 1 つからのものです。

で元の応答ストリームを復元していませんHttpContext。したがって、ミドルウェアを呼び出す人は誰でも、閉じられた を返しますMemoryStream

ここにいくつかの作業コードがあります:

app.Use(async (httpContext, next) =>
{
    using (var memoryResponse = new MemoryStream())
    {
        var originalResponse = httpContext.Response.Body;
        try
        {
            httpContext.Response.Body = memoryResponse;

            await next.Invoke();

            memoryResponse.Seek(0, SeekOrigin.Begin);
            await memoryResponse.CopyToAsync(originalResponse);
        }
        finally
        {
            // This is what you're missing
            httpContext.Response.Body = originalResponse;
        }
    }
});

app.Run(async (context) =>
{
    context.Response.ContentType = "text/other";
    await context.Response.WriteAsync("Hello World!");
});
于 2016-07-09T23:23:22.520 に答える