You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取SignalR Core接收消息的实际大小?优先支持IHubFilter实现

跟踪SignalR Core传入消息的实际大小

可以通过自定义HubProtocol包装器结合IHubFilter实现消息大小的跟踪,以下是具体方案:

1. 实现自定义HubProtocol包装器

这个包装器会在解析消息时记录原始消息的字节长度,并将长度存入HubCallerContext的Items集合,供后续过滤器调用:

public class SizeTrackingHubProtocol : IHubProtocol
{
    private readonly IHubProtocol _innerProtocol;

    public SizeTrackingHubProtocol(IHubProtocol innerProtocol)
    {
        _innerProtocol = innerProtocol;
    }

    public string Name => _innerProtocol.Name;
    public int Version => _innerProtocol.Version;
    public TransferFormat TransferFormat => _innerProtocol.TransferFormat;

    public ReadOnlyMemory<byte> GetMessageBytes(HubMessage message)
    {
        return _innerProtocol.GetMessageBytes(message);
    }

    public HubMessage ParseMessage(ReadOnlySequence<byte> input, IInvocationBinder binder)
    {
        var messageSize = input.Length;
        if (HubCallerContext.Current is { } context)
        {
            context.Items["IncomingMessageSize"] = messageSize;
        }

        return _innerProtocol.ParseMessage(input, binder);
    }

    public async ValueTask<HubMessage> ParseMessageAsync(Stream input, IInvocationBinder binder, CancellationToken cancellationToken = default)
    {
        var memoryStream = new MemoryStream();
        await input.CopyToAsync(memoryStream, cancellationToken);
        memoryStream.Position = 0;
        var messageSize = memoryStream.Length;

        if (HubCallerContext.Current is { } context)
        {
            context.Items["IncomingMessageSize"] = messageSize;
        }

        return await _innerProtocol.ParseMessageAsync(memoryStream, binder, cancellationToken);
    }
}

2. 实现IHubFilter获取并跟踪消息大小

在过滤器中从HubCallerContext.Items取出记录的消息大小,即可完成日志记录、统计等跟踪操作:

public class MessageSizeTrackingFilter : IHubFilter
{
    private readonly ILogger<MessageSizeTrackingFilter> _logger;

    public MessageSizeTrackingFilter(ILogger<MessageSizeTrackingFilter> logger)
    {
        _logger = logger;
    }

    public async ValueTask<object> OnInvokingAsync(HubInvocationContext invocationContext, Func<ValueTask<object>> next)
    {
        if (invocationContext.Context.Items.TryGetValue("IncomingMessageSize", out var sizeObj) && sizeObj is long messageSize)
        {
            // 此处可根据需求处理消息大小,比如日志记录、指标上报
            _logger.LogInformation("收到SignalR消息,大小:{Size}字节,调用方法:{Method}", messageSize, invocationContext.HubMethodName);
        }

        return await next();
    }
}

3. 注册自定义组件

在Program.cs中注册自定义的HubProtocol和IHubFilter:

builder.Services.AddSignalR(options =>
{
    options.MaximumReceiveMessageSize = 32768;
})
.AddHubProtocol(() => 
{
    // 包装默认的JSON协议,若使用MessagePack可替换为对应的协议实现
    return new SizeTrackingHubProtocol(new JsonHubProtocol());
})
.AddFilter<MessageSizeTrackingFilter>();

注意事项

  • 若使用多种Hub协议,需分别包装对应协议实现
  • WebSocket传输通过ParseMessage直接处理字节序列,长轮询等HTTP传输通过ParseMessageAsync读取完整请求体计算大小
  • 如需跟踪连接建立时的初始消息,可在Hub的OnConnectedAsync方法中读取Context.Items中的大小值

内容的提问来源于stack exchange,提问作者Shad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 07:55:00