Получить размер полученного сообщения SignalR Core

Существует настройка, позволяющая ограничить максимальный размер принимаемых сообщений ядра сигнала:

services.AddSignalR(options =>
{
    options.MaximumReceiveMessageSize = 32768;
});

Мне нужно отслеживать фактический размер входящих сообщений ядра сигнализатора, но я не нашел способа его получить. Есть какой-либо способ сделать это? Было бы здорово, если бы это было возможно внутри IHubFilter реализации.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
152
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете попробовать этот код, чтобы отслеживать фактический размер входящих основных сообщений signalr внутри реализации IHubFilter:

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

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

    public async ValueTask<object?> InvokeMethodAsync(
        HubInvocationContext invocationContext,
        Func<HubInvocationContext, ValueTask<object?>> next
    )
    {
        try
        {
            var result = await next(invocationContext);

            result = "failed";
            // this means we can find the message sent from client
            if (invocationContext.HubMethodArguments.Count > 0)
            {
                result = "succeed";
            }

            var arguments = invocationContext.HubMethodArguments;

            // the total length of the json:

            /*var contentLength = System.Text.Json.JsonSerializer.Serialize(arguments).Length;
            _logger.LogInformation("message content length {ContentLength}", contentLength);*/


            // actual size of incoming signalr core messages:
            if (arguments.Count > 1 && arguments[1] is string message)
            {
                int messageLength = message.Length;

                _logger.LogInformation("message content length: {MessageLength}", messageLength);
            }

            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError($"Exception calling '{invocationContext.HubMethodName}': {ex}");
            throw;
        }
    }
}

Результат теста:

Ваш метод получает длину второго параметра метода концентратора и только тогда, когда он имеет строковый тип. Однако я хотел бы найти общее решение, чтобы получить размер всего сообщения без дополнительной сериализации.

Shad 18.06.2024 11:13
Ответ принят как подходящий

ТЛ; ДР

Это невозможно при текущей реализации обработчика соединения. Получение фактического размера необработанного сообщения без повторной сериализации помешало бы базовому PipeReader нарушить логику чтения сообщений SignalR.

Полное объяснение

SignalR использует ConnectionContext для хранения отдельных данных подключения ASP.NET Core. Это, в свою очередь, использует System.IO.Pipelines, чтобы разрешить транспортировку данных по соединению, поскольку конвейеры предназначены для чтения и записи потоковых данных. Вы можете получить доступ к базовому контексту соединения через коллекцию функций, находясь внутри фильтра-концентратора:

public class MessageSizeFilter : IHubFilter
{
    public async Task InvokeMethodAsync(InvokeMethodAsync invocationContext, Func<InvokeMethodAsync, Task> next)
    {
        var connectionContext = invocationContext.Context.Features
            .Select(x => x.Value)
            .OfType<ConnectionContext>()
            .FirstOrDefault();
        var pipeReader = connectionContext.Transport.Input;

        await next(invocationContext);
    }
}

Получить длину отдельного сообщения само по себе не так уж и сложно. Обычно вы используете возможности чтения из PipeReader:

var result = await pipeReader.ReadAsync();
var messageLength = result.Buffer.Length;

А вот чтение из трубы, которая уже находится в процессе чтения, начатого из другого места, затруднительно. Трубы не предназначены для использования. Если канал уже находится в состоянии чтения, он выдаст исключение при попытке запустить новый процесс чтения. Вам придется отменить или завершить исходный процесс, что повлияет на логику чтения на стороне SignalR. Вы можете самостоятельно увидеть, как выглядит процесс чтения в обработчике соединения SignalR. Обратите внимание на большой цикл while, который поддерживает работу и обрабатывает входящие сообщения по мере их поступления, читает их и пытается отправить нужному потребителю.

Хорошо, тогда, может быть, начнем читать до того, как обработчик соединения SignalR начнет свою работу? Что ж... удачи в этом. Вам придется заново реализовать обработчик соединения, поскольку нет метода подгонки, который можно было бы переопределить, поэтому вы можете просто добавить только фрагменты своего собственного кода.

ИМХО, будет проще создать проблему на GitHub, поэтому люди из MS могут хотя бы дать вам несколько советов. Мне не удалось преодолеть проблему помех, связанную с PipeReader выдачей исключения InvalidOperationException: чтение уже выполняется. Вы можете попробовать погрузиться в эту тему самостоятельно. Вот несколько хороших обсуждений на PipeReader на GitHub.

Альтернативно попробуйте запросить недостающую функциональность.

Альтернативное решение с сериализацией

Если у вас есть возможность знать используемый способ связи и вы можете предположить, что он не изменится в зависимости от клиентов, скажем, это всегда будет JSON, тогда вы можете попробовать сериализацию и к длине, полученной из байтов JSON, добавить еще несколько для конверт сообщения, который невелик.

Спасибо за такой подробный ответ! Я создал задачу на github: github.com/dotnet/aspnetcore/issues/56338

Shad 20.06.2024 13:20

Другие вопросы по теме