SelfHost Websocket - Web API与OWIN中间件

时间:2017-03-20 15:57:35

标签: websocket owin self-host-webapi

我正在运行一个承载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版本则允许。所以我不确定这是怎么回事。

0 个答案:

没有答案