1

我正在运行一个 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 版本则允许。所以我不确定这应该如何工作。

4

0 回答 0