Max*_*lle 19 c# stream owin katana owin-middleware
我正在尝试编写一个简单的OWIN中间件,以拦截响应流.我要做的是用自定义的基于Stream的类替换原始流,在那里我将能够拦截对响应流的写入.
但是,我遇到了一些问题,因为我无法知道响应是否已被链中的内部中间件组件完全写入.Dispose永远不会调用Stream 的覆盖.所以我不知道什么时候进行我的处理,这应该发生在响应流的末尾.
这是一个示例代码:
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.
    }
}
正如我在上面代码的评论中提到的那样,我可以想到两种策略来检测响应是否完整.
a)我可以记录写入响应流的字节数,并将其与预期的响应长度相关联.但是,在使用Chunked Transfer Encoding的响应的情况下,长度是未知的.
b)在响应流Dispose上调用时,我可以决定响应流是否完整.但是,OWIN/Katana基础结构从不在已替换的流上调用Dispose.
我一直在研究Opaque Streaming,以便了解操纵底层HTTP协议是否是一种可行的方法,但我似乎没有发现Katana是否支持Opaque Streaming.
有没有办法实现我想要的?
Bad*_*dri 36
我不认为你需要一个子类流,但接下来就是你如何阅读响应.确保这个中间件是OWIN管道中的第一个,这样它就是最后一个检查响应的中间件.
using AppFunc = Func<IDictionary<string, object>, Task>;
public class CustomMiddleware
{
    private readonly AppFunc next;
    public CustomMiddleware(AppFunc next)
    {
        this.next = next;
    }
    public async Task Invoke(IDictionary<string, object> env)
    {
        IOwinContext context = new OwinContext(env);
        // Buffer the response
        var stream = context.Response.Body;
        var buffer = new MemoryStream();
        context.Response.Body = buffer;
        await this.next(env);
        buffer.Seek(0, SeekOrigin.Begin);
        var reader = new StreamReader(buffer);
        string responseBody = await reader.ReadToEndAsync();
        // Now, you can access response body.
        Debug.WriteLine(responseBody);
        // You need to do this so that the response we buffered
        // is flushed out to the client application.
        buffer.Seek(0, SeekOrigin.Begin);
        await buffer.CopyToAsync(stream);
    }
}
据我所知,BTW源于此OwinMiddleware并不是一种好习惯,因为这OwinMiddleware是针对Katana的.但是,它与你的问题无关.
| 归档时间: | 
 | 
| 查看次数: | 12683 次 | 
| 最近记录: |