24

応答ストリームを傍受するために、単純なOWINミドルウェアを作成しようとしています。私がやろうとしているのは、元のストリームをカスタム Stream ベースのクラスに置き換えることです。これにより、応答ストリームへの書き込みをインターセプトできるようになります。

ただし、チェーン内の内部ミドルウェア コンポーネントによって応答が完全に書き込まれたタイミングがわからないため、いくつかの問題に直面しています。StreamのDisposeオーバーライドが呼び出されることはありません。そのため、応答ストリームの最後に発生するはずの処理をいつ実行するかわかりません。

サンプルコードは次のとおりです。

public sealed class CustomMiddleware: OwinMiddleware
{
    public CustomMiddleware(OwinMiddleware next)
        : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        var request = context.Request;
        var response = context.Response;

        // capture response stream

        var vr = new MemoryStream();
        var responseStream = new ResponseStream(vr, response.Body);

        response.OnSendingHeaders(state =>
        {
            var resp = (state as IOwinContext).Response;
            var contentLength = resp.Headers.ContentLength;

            // contentLength == null for Chunked responses

        }, context);

        // invoke the next middleware in the pipeline

        await Next.Invoke(context);
    }
}

public sealed class ResponseStream : Stream
{
    private readonly Stream stream_; // MemoryStream
    private readonly Stream output_; // Owin response
    private long writtenBytes_ = 0L;

    public ResponseStream(Stream stream, Stream output)
    {
        stream_ = stream;
        output_ = output;
    }

    ... // System.IO.Stream implementation

    public override void Write(byte[] buffer, int offset, int count)
    {
        // capture writes to the response stream in our local stream
        stream_.Write(buffer, offset, count);

        // write to the real output stream
        output_.Write(buffer, offset, count);

        // update the number of bytes written

        writtenBytes_ += count;

        // how do we know the response is complete ?
        // we could check that the number of bytes written
        // is equal to the content length, but content length
        // is not available for Chunked responses.
    }

    protected override void Dispose(bool disposing)
    {
        // we could perform our processing
        // when the stream is disposed of.
        // however, this method is never called by
        // the OWIN/Katana infrastructure.
    }
}

上記のコードのコメントで触れたように、応答が完全かどうかを検出するために考えられる 2 つの戦略があります。

a) 応答ストリームに書き込まれたバイト数を記録し、それを予想される応答の長さに関連付けることができます。ただし、Chunked Transfer Encoding を使用する応答の場合、長さは不明です。

Disposeb) が応答ストリームで呼び出されたときに、応答ストリームが完了したと判断できます。ただし、OWIN/Katana インフラストラクチャは、置き換えられたストリームで Dispose を呼び出すことはありません。

基になる HTTP プロトコルを操作することが実現可能なアプローチであるかどうかを確認するために、不透明なストリーミングを調査してきましたが、Katana が不透明なストリーミングをサポートしているかどうかはわかりません。

私が望むものを達成する方法はありますか?

4

1 に答える 1