在经典 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;
}
}
}
我需要将 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;
}
}
}