Asp.net core 如何检索当前响应正文长度?

Asp.net core 如何检索当前响应正文长度?,asp.net-core,Asp.net Core,我需要检索响应正文长度 当我看到它时,据说: Stream.Position{get}和Stream.Length{get}返回写入的累积字节数 这正是我需要的,但是httpContext.Response.Body.Length引发了NotSupportedException并说“流不可查找” 我应该使用一个委托流来计算每次写入的字节数吗?我假设您试图从中间件中获取ContentLength 下面是一个中间件示例。它应该在任何响应生成中间件(如useMVC或useStaticFiles)之前添

我需要检索响应正文长度

当我看到它时,据说:

Stream.Position{get}和Stream.Length{get}返回写入的累积字节数

这正是我需要的,但是
httpContext.Response.Body.Length
引发了
NotSupportedException
并说“流不可查找”


我应该使用一个委托流来计算每次写入的字节数吗?

我假设您试图从中间件中获取ContentLength

下面是一个中间件示例。它应该在任何响应生成中间件(如useMVC或useStaticFiles)之前添加到管道(startup.cs)

public class ContentLengthMiddleware
{
    RequestDelegate _next;

    public ContentLengthMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        using (var buffer = new MemoryStream())
        {
            var request = context.Request;
            var response = context.Response;

            var bodyStream = response.Body;
            response.Body = buffer;

            await _next(context);
            Debug.WriteLine($"{request.Path} ({response.ContentType}) Content-Length: {response.ContentLength ?? buffer.Length}");
            buffer.Position = 0;
            await buffer.CopyToAsync(bodyStream);
        }
    }
}
返回静态文件(png、js等)时,由于我无法理解的原因,响应正文将为空,但设置了ContentLength,这就是我使用
response.ContentLength??buffer.Length


(mod注意:很抱歉两个问题的答案重复。另一个答案发布错误,打开的选项卡太多。我将其删除并在此处重新发布了答案)。

以下是用于在流写入期间跟踪内容长度的代码。
ContentLengthTracker
类用于在其他类之间共享内容长度值。 该守则载于

使用系统;
使用System.IO;
使用系统线程;
使用System.Threading.Tasks;
公共类ContentLengthTracker
{
公共长内容长度{get;set;}
}
公共类ContentLength跟踪流:流
{
私有只读流\u内部;
私有只读ContentLengthTracker\u tracker;
公共ContentLengthTrackingStream(流内部,ContentLengthTracker)
{
if(内部==null)
{
抛出新ArgumentNullException(nameof(内部));
}
if(tracker==null)
{
抛出新的ArgumentNullException(nameof(tracker));
}
_内部=内部;
_跟踪器=跟踪器;
}
公共覆盖布尔可读取
=>\u inner.CanRead;
公共覆盖布尔搜索
=>\u inner.CanSeek;
公共覆盖布尔可写
=>\u inner.CanWrite;
公共覆盖长长度
=>\u内部长度;
公众优先多头仓位
{
get=>\u内部位置;
set=>\u inner.Position=值;
}
公共覆盖boolcantimeout
=>\u内部。可超时;
公共覆盖int读取超时
{
get=>\u inner.ReadTimeout;
set=>\u inner.ReadTimeout=value;
}
公共覆盖int WriteTimeout
{
get=>\u inner.WriteTimeout;
set=>\u inner.WriteTimeout=value;
}
公共内容长度跟踪器
=>\u跟踪器;
公共覆盖无效刷新()
=>_inner.Flush();
公共覆盖任务FlusAsync(CancellationToken CancellationToken)
=>\u内部.FlushAsync(取消令牌);
公共重写整型读取(字节[]缓冲区、整型偏移量、整型计数)
=>\u内部读取(缓冲区、偏移量、计数);
公共异步重写任务ReadAsync(字节[]缓冲区、整数偏移量、整数计数、取消令牌取消令牌)
=>等待_inner.ReadAsync(缓冲区、偏移量、计数、取消令牌);
公共重写IAsyncResult起始(字节[]缓冲区、整数偏移量、整数计数、异步回调、对象状态)
=>\u inner.BeginRead(缓冲区、偏移量、计数、回调、状态);
公共覆盖int EndRead(IAsyncResult asyncResult)
{
任务任务=异步结果作为任务;
如果(任务!=null)
{
返回task.GetAwaiter().GetResult();
}
返回_inner.EndRead(asyncResult);
}
公共覆盖长寻道(长偏移,参见原始坐标系)
=>\u内部搜索(偏移、原点);
公共覆盖无效设置长度(长值)
=>\u内部设置长度(值);
公共重写无效写入(字节[]缓冲区、整数偏移量、整数计数)
{
_tracker.ContentLength+=计数-偏移量;
_写(缓冲区、偏移量、计数);
}
公共重写IAsyncResult BeginWrite(字节[]缓冲区、整数偏移量、整数计数、异步回调、对象状态)
{
//\u tracker.ContentLength+=count-offset;//这是不正确的
_tracker.ContentLength+=计数;
return\u internal.BeginWrite(缓冲区、偏移量、计数、回调、状态);
}
公共重写void EndWrite(IAsyncResult asyncResult)
=>\u内部.EndWrite(异步结果);
公共覆盖任务WriteAsync(字节[]缓冲区、整数偏移量、整数计数、取消令牌取消令牌)
{
//\u tracker.ContentLength+=count-offset;//这是不正确的
_tracker.ContentLength+=计数;
返回_inner.WriteAsync(缓冲区、偏移量、计数、取消令牌);
}
公共重写无效写字节(字节值)
{
_ContentLength++;
_内部.WriteByte(值);
}
受保护的覆盖无效处置(布尔处置)
{
如果(处置)
{
_depose();
}
}
}

好奇的是,您需要它的场景是什么?获取此信息的一种方法可能是注册当前响应的
OnSendingHeaders
回调。示例:
httpContext.Response.OnSendingHeaders(callback:(state)=>{var length:(httpContext)state.ContentLength;},state:httpContext)
。我想我错过了你文章的最后一行…当然,即使这样也行……您可以编写一个中间件,在管道中很早就注册,并用一个委托流包装响应体……@KiranChalla我需要计算消耗带宽的内容长度。超过配额后,其他请求将被阻止/减慢。
OnSendingHeaders
回调不起作用:
ContentLength
属性设置为
null
。这与
OnResponseCompleted
回调相同。诚然,在某些情况下,内容长度可以为null(
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

public class ContentLengthTracker
{
    public long ContentLength { get; set; }
}

public class ContentLengthTrackingStream : Stream
{
    private readonly Stream _inner;
    private readonly ContentLengthTracker _tracker;

    public ContentLengthTrackingStream(Stream inner, ContentLengthTracker tracker)
    {
        if (inner == null)
        {
            throw new ArgumentNullException(nameof(inner));
        }

        if (tracker == null)
        {
            throw new ArgumentNullException(nameof(tracker));
        }

        _inner = inner;
        _tracker = tracker;
    }

    public override bool CanRead
        => _inner.CanRead;

    public override bool CanSeek
        => _inner.CanSeek;

    public override bool CanWrite
        => _inner.CanWrite;

    public override long Length
        => _inner.Length;

    public override long Position
    {
        get => _inner.Position;
        set => _inner.Position = value;
    }

    public override bool CanTimeout
        => _inner.CanTimeout;

    public override int ReadTimeout
    {
        get => _inner.ReadTimeout;
        set => _inner.ReadTimeout = value;
    }

    public override int WriteTimeout
    {
        get => _inner.WriteTimeout;
        set => _inner.WriteTimeout = value;
    }

    public ContentLengthTracker Tracker
        => _tracker;

    public override void Flush()
        => _inner.Flush();

    public override Task FlushAsync(CancellationToken cancellationToken)
        => _inner.FlushAsync(cancellationToken);

    public override int Read(byte[] buffer, int offset, int count)
        => _inner.Read(buffer, offset, count);

    public async override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        => await _inner.ReadAsync(buffer, offset, count, cancellationToken);

    public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        => _inner.BeginRead(buffer, offset, count, callback, state);

    public override int EndRead(IAsyncResult asyncResult)
    {
        Task<int> task = asyncResult as Task<int>;
        if (task != null)
        {
            return task.GetAwaiter().GetResult();
        }

        return _inner.EndRead(asyncResult);
    }

    public override long Seek(long offset, SeekOrigin origin)
        => _inner.Seek(offset, origin);

    public override void SetLength(long value)
       => _inner.SetLength(value);

    public override void Write(byte[] buffer, int offset, int count)
    {
        _tracker.ContentLength += count - offset;
        _inner.Write(buffer, offset, count);
    }

    public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
    {
        // _tracker.ContentLength += count - offset; // This is incorrect
        _tracker.ContentLength += count;
        return _inner.BeginWrite(buffer, offset, count, callback, state);
    }

    public override void EndWrite(IAsyncResult asyncResult)
        => _inner.EndWrite(asyncResult);

    public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
    {
        // _tracker.ContentLength += count - offset; // This is incorrect
        _tracker.ContentLength += count;
        return _inner.WriteAsync(buffer, offset, count, cancellationToken);
    }

    public override void WriteByte(byte value)
    {
        _tracker.ContentLength++;
        _inner.WriteByte(value);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _inner.Dispose();
        }
    }
}