SelfHost Websocket - веб-API против промежуточного программного обеспечения OWIN

Я использую OWIN-приложение, которое размещает API REST, а также позволяет подключаться через веб-сокет для данных в реальном времени. Я использую WebAPI для обработки маршрутизации и сопоставления маршрутов с контроллерами.

Когда я использую веб-API для обработки маршрутов веб-сокетов, сокет закрывается, как только контроллер возвращается. Однако, если я создаю свое собственное промежуточное программное обеспечение, сокет не закрывается.

Я бы предпочел использовать 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, который закрывает соединение, которое также закрывает веб-сокет.

Вот соответствующий код для промежуточного программного обеспечения 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 возвращается. Однако соединение остается открытым, и я могу отправлять и получать данные через веб-сокет.

Итак, у меня есть решение, но я бы очень хотел понять, что происходит. Любые ссылки будут с благодарностью.

Изменить: На самом деле сокет закрыт в обоих случаях. Версия веб-API отправляет RST с сервера, как если бы соединение было внезапно закрыто, в то время как версия OWIN испытывает обычное FIN ACK. Тем не менее, веб-API не позволяет дальнейшее общение через веб-сокет, в то время как версия OWIN делает. Так что я не совсем уверен, как это должно работать.

0 ответов

Другие вопросы по тегам