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

问题描述

我需要将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:

enter image description here

然后尝试:var ws = new WebSocket("ws://localhost/APP/Page.aspx"); 但这行不通。

不确定这是否完全可行?

我会错过有关配置或实现的信息吗? 我可以将websocket放在单独的应用程序/服务器上,但希望将其放置在可以访问同一会话对象的位置。

解决方法

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

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

您可以通过转到Visual Studio中的“添加项目”对话框来创建处理程序 Visual Studio's 'Add Item' dialog with the entry for 'Generic Handler' highlighted

这时,您只需在处理程序代码中实现websocket逻辑即可。我在this aspnet sample中添加了一个简单的回显,只是为了演示。

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,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 developer console with output from the sample javascript above.

注意:我通常不建议您尝试从websocket处理程序访问会话数据。您的会话可能会在网络套接字使用期限之外过期。您可能想要使用其他机制在套接字和页面的其余部分(可能是数据库或应用程序级缓存)之间保持状态,您可以在上面的示例中从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;
        }
    }
}