我正在运行一个 OWIN 自托管应用程序,该应用程序托管一个 REST API,还允许实时数据的 websocket 连接。我正在使用 WebAPI 来处理路由到控制器的路由和映射。
当我使用 Web API 处理 websocket 路由时,一旦控制器返回,套接字就会关闭。但是,如果我创建自己的中间件,则套接字不会关闭。
我更愿意为我的所有路线使用 Web API。但更重要的是,我想了解发生了什么。我不喜欢我的生产代码在不了解它为什么工作的情况下工作。
以下是相关的 Web API 代码片段:
public class WebServer : IDisposable
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "Websocket",
routeTemplate: "ws/all",
defaults: new { controller = "MyWebSocket", action = "Get" });
app.UseWebApi(config);
}
}
public class MyWebSocketController : System.Web.Http.ApiController
{
public IHttpActionResult Get()
{
var owinContext = Request.GetOwinContext();
var accept = owinContext.Get<Action<IDictionary<string, object>, Func<IDictionary<string, object>, Task>>>("websocket.Accept");
accept(null, RunWebSocket);
return Ok();
}
private async Task RunWebSocket(IDictionary<string, object> websocketContext)
{
WebSocket socket;
if (websocketContext.TryGetValue(typeof(System.Net.WebSockets.WebSocketContext).FullName, out value))
{
socket = ((System.Net.WebSockets.WebSocketContext)value).WebSocket;
}
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[128]);
WebSocketReceiveResult result = null;
using (var ms = new MemoryStream())
{
while (socket.State == WebSocketState.Open)
{
ms.SetLength(0);
do
{
result = await socket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
if (result.MessageType == WebSocketMessageType.Close)
{
// Close socket
}
ms.Seek(0, SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
// Handle message
}
}
}
}
}
对 ReceiveAsync 的调用会安排继续。Get 方法返回到关闭连接的 ApiController,这也关闭了 websocket。
这是OWIN中间件的相关代码。
public class WebServer : IDisposable
{
public void Configuration(IAppBuilder app)
{
app.Use<WebSocketMiddleware>();
}
}
public class WebSocketMiddleware : OwinMiddleware
{
public override Task Invoke(IOwinContext context)
{
var accept = context.Get<Action<IDictionary<string, object>, Func<IDictionary<string, object>, Task>>>("websocket.Accept");
accept(null, RunWebSocket);
return;
}
private async Task RunWebSocket(IDictionary<string, object> websocketContext)
{
// Same as Web API implementation
}
}
在调用 ReceiveAsync 和 Invoke 方法返回期间再次安排继续。但是,连接仍然打开,我可以通过 websocket 发送和接收数据。
所以,我有一个解决方案,但我真的很想了解发生了什么。任何参考将不胜感激。
编辑:实际上套接字在这两种情况下都是关闭的。Web API 版本从服务器发送 RST,就好像连接被突然关闭一样,而 OWIN 版本则经历正常的 FIN ACK。然而,Web API 不允许通过 websocket 进行任何进一步的通信,而 OWIN 版本则允许。所以我不确定这应该如何工作。