在经典 asp.net 表单应用程序中使用 websockets

Using websockets in classic asp.net forms application

我需要将 websocket 功能添加到遗留 asp.net webforms 应用程序(只是一个简单的长时间工作流程,从旧的 applet 功能转换而来)。

我天真地试图将 websocket 处理程序添加到 aspx 页面:

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

并在 IIS 上启用 websocket: 然后尝试:var ws = new WebSocket("ws://localhost/APP/Page.aspx"); 但这并不能正常工作。

不确定这是否可能?

我是否遗漏了有关配置或实施的内容? 我可以将 websocket 放在单独的 application/server 上,但更愿意将它放在一个可以访问同一会话的地方 object.

应该可以在经典 ASP.NET Forms 应用程序中处理网络套接字连接。这些工具在 HttpContext 上可用,您的想法基本上是正确的。

我认为问题在于您正试图从 aspx 页面调用它,而不仅仅是使用通用 IHttpHandler。 IIS 根据文件扩展名运行特定的处理管道。 Aspx 专门用于尝试呈现 HTML 页面,因此虽然可以重新配置 IIS 以允许 websockets 与 ASPX 页面交互,但更容易使用通用 ashx 处理程序。

您可以转到 Visual Studio 中的“添加项目”对话框来创建处理程序

此时,您只需在处理程序代码中实现您的 websocket 逻辑。我从 this aspnet sample 中输入了一个简单的 echo 只是为了演示。

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;
        }
    }
}

您现在应该可以连接到 websocket。请注意 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!");

你应该会看到类似这样的输出:

注意:我通常不建议尝试从 websocket 处理程序访问会话数据。您的会话可能会在 websocket 的生命周期之外过期。您可能希望使用其他一些机制来保持套接字和其余页面之间的状态(可能是数据库或 application-level 缓存,您可以在上面的示例中从 socketContext.Cache 访问它。

编辑:添加了在套接字初始化时使用会话值的示例。 根据你的评论,如果你想在 websocket 的 初始化 期间使用会话值(这应该是一个安全的操作),那么你的处理程序只需要实现 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;
        }
    }
}