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 делает. Так что я не совсем уверен, как это должно работать.