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