我正在运行一个承载REST API的OWIN自托管应用程序,并且还允许实时数据的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期间调度continuation,并返回Invoke方法。但是,连接仍然保持打开状态,我可以通过websocket发送和接收数据。
所以,我有一个解决方案,但我真的很想了解发生了什么。任何参考将不胜感激。
编辑:实际上在两种情况下都关闭套接字。 Web API版本从服务器发送RST,就好像连接突然关闭,而OWIN版本经历了正常的FIN ACK。然而,Web API不允许通过websocket进行任何进一步的通信,而OWIN版本则允许。所以我不确定这是怎么回事。