Использование веб-сокетов в классическом приложении форм asp.net

Мне нужно добавить функциональность веб-сокета в устаревшее приложение веб-форм asp.net (всего один простой длительный рабочий процесс, преобразованный из старых функций апплета).

Я наивно пытался просто добавить обработчик websocket на страницу aspx:

        public override void ProcessRequest(HttpContext context)
        {
            if (context.IsWebSocketRequest)
            {
                context.AcceptWebSocketRequest(HandleWebSocket);
            } else
            {
                base.ProcessRequest(context);
            }
        }

и включите веб-сокет в IIS: введите здесь описание изображения Затем попробуйте: var ws = new WebSocket("ws://localhost/APP/Page.aspx"); но это не работает.

Не уверен, возможно ли это вообще?

Я что-то упускаю из конфигурации или реализации? Я мог бы поместить веб-сокет в отдельное приложение/сервер, но предпочел бы сохранить его в одном месте с доступом к тому же объекту сеанса.


person tester.one    schedule 08.10.2020    source источник
comment
Вы используете IIS 8.0?   -  person Julián    schedule 13.10.2020


Ответы (1)


Должна быть возможность обрабатывать подключение к веб-сокету в классическом приложении ASP.NET Forms. Инструменты доступны на HttpContext, и у вас в основном есть правильное представление.

Я думаю, проблема в том, что вы пытаетесь вызвать его со страницы aspx, а не просто используете общий файл IHttpHandler. IIS запускает определенные конвейеры обработки на основе расширения файла. Aspx скорее специализируется на попытках отобразить HTML-страницу, поэтому, хотя можно перенастроить IIS, чтобы позволить веб-сокетам взаимодействовать со страницами ASPX, гораздо проще просто использовать общий ashx обработчик.

Вы можете создать обработчик, перейдя в диалоговое окно «Добавить элемент» в Visual Studio Диалоговое окно Visual Studio

На этом этапе вы просто реализуете логику веб-сокета в коде обработчика. Я добавляю простое эхо из этот пример aspnet просто для демонстрации.

public class MyHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        if (context.IsWebSocketRequest)
        {
            context.AcceptWebSocketRequest(EchoWebSocket);
        }
    }

    private async Task EchoWebSocket(AspNetWebSocketContext socketContext)
    {
        var buffer = new byte[1024 * 4];
        var result = await socketContext.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

        while (!result.CloseStatus.HasValue)
        {
            await socketContext.WebSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
            result = await socketContext.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
        }

        await socketContext.WebSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Теперь вы должны иметь возможность подключиться к веб-сокету. Обратите внимание на использование wss вместо ws. Для настройки, которую я тестировал, требуется безопасная версия (wss). Используйте все, что имеет отношение к приложению, над которым вы работаете.

// Replace with port/path to your handler.
var ws = new WebSocket("wss://localhost:44336/MyHandler.ashx");

ws.onmessage = function(evt) { 
    console.log(evt); 
};

ws.send("Hello, World!");

Вы должны увидеть примерно такой вывод: Консоль разработчика Chrome с выводом приведенного выше примера javascript.

Примечание. Обычно я не рекомендую пытаться получить доступ к данным сеанса из обработчика веб-сокетов. Срок действия вашего сеанса может истечь за пределами срока действия веб-сокета. Вы, вероятно, захотите использовать какой-то другой механизм для сохранения состояния между сокетом и остальными страницами (возможно, базу данных или кеш уровня приложения, к которому вы можете получить доступ из socketContext.Cache в приведенном выше примере.

Изменить: добавлен пример использования значения сеанса при инициализации сокета. Согласно вашему комментарию, если вы хотите использовать значения сеанса во время инициализации веб-сокета (что должно быть безопасным операции), тогда ваш обработчик просто должен реализовать IRequiresSessionState и добавить немного дополнительного синтаксиса для передачи значения сеанса в обработчик принятия.

public class MyHandler : IHttpHandler, IRequiresSessionState
{
    public void ProcessRequest(HttpContext context)
    {
        if (context.IsWebSocketRequest)
        {
            var sessionValue = context.Session["session_key"] as string;

            context.AcceptWebSocketRequest(async (socketContext) =>
            {
                await SetupWebSocket(socketContext, sessionValue);
            });
        }
    }

    private async Task SetupWebSocket(AspNetWebSocketContext socketContext, string sessionValue)
    {
        // Handle socket as before, but 'sessionValue' is now available for use.
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}
person cmcquillan    schedule 14.10.2020
comment
Спасибо, похоже, проблема в aspx. - person tester.one; 15.10.2020
comment
Мне нужен сеанс только для инициализации веб-сокета, сам сеанс не доступен для функции обработчика, потому что он не является потокобезопасным. - person tester.one; 15.10.2020
comment
@tester.one Хорошо. Этот вариант использования имеет смысл. Я добавил еще один пример, демонстрирующий, как это можно сделать. - person cmcquillan; 16.10.2020