// Order of operations: // 1. A WebSocket handshake request is received by the middleware. // 2. The middleware inserts an alternate Accept signature into the OWIN environment. // 3. The middleware invokes Next and stores Next's Task locally. It then returns an alternate Task to the server. // 4. The OwinFeatureCollection adapts the alternate Accept signature to IHttpWebSocketFeature.AcceptAsync. // 5. A component later in the pipleline invokes IHttpWebSocketFeature.AcceptAsync (mapped to AcceptWebSocketAsync). // 6. The middleware calls the OWIN Accept, providing a local callback, and returns an incomplete Task. // 7. The middleware completes the alternate Task it returned from Invoke, telling the server that the request pipeline has completed. // 8. The server invokes the middleware's callback, which creats a WebSocket adapter complete's the orriginal Accept Task with it. // 9. The middleware waits while the application uses the WebSocket, where the end is signaled by the Next's Task completion. public static AppFunc AdaptWebSockets(AppFunc next) { return(environment => { object accept; if (environment.TryGetValue(OwinConstants.WebSocket.Accept, out accept) && accept is WebSocketAccept) { var adapter = new OwinWebSocketAcceptAdapter((WebSocketAccept)accept); environment[OwinConstants.WebSocket.AcceptAlt] = new WebSocketAcceptAlt(adapter.AcceptWebSocketAsync); try { adapter.UpstreamTask = next(environment); adapter.UpstreamWentAsyncTcs.TrySetResult(0); adapter.UpstreamTask.ContinueWith(adapter.EnsureCompleted, TaskContinuationOptions.ExecuteSynchronously); } catch (Exception ex) { adapter.UpstreamWentAsyncTcs.TrySetException(ex); throw; } return adapter.RequestTask; } else { return next(environment); } }); }
// Order of operations: // 1. A WebSocket handshake request is received by the middleware. // 2. The middleware inserts an alternate Accept signature into the OWIN environment. // 3. The middleware invokes Next and stores Next's Task locally. It then returns an alternate Task to the server. // 4. The OwinFeatureCollection adapts the alternate Accept signature to IHttpWebSocketFeature.AcceptAsync. // 5. A component later in the pipleline invokes IHttpWebSocketFeature.AcceptAsync (mapped to AcceptWebSocketAsync). // 6. The middleware calls the OWIN Accept, providing a local callback, and returns an incomplete Task. // 7. The middleware completes the alternate Task it returned from Invoke, telling the server that the request pipeline has completed. // 8. The server invokes the middleware's callback, which creats a WebSocket adapter complete's the orriginal Accept Task with it. // 9. The middleware waits while the application uses the WebSocket, where the end is signaled by the Next's Task completion. public static AppFunc AdaptWebSockets(AppFunc next) { return environment => { object accept; if (environment.TryGetValue(OwinConstants.WebSocket.Accept, out accept) && accept is WebSocketAccept) { var adapter = new OwinWebSocketAcceptAdapter((WebSocketAccept)accept); environment[OwinConstants.WebSocket.AcceptAlt] = new WebSocketAcceptAlt(adapter.AcceptWebSocketAsync); try { adapter.UpstreamTask = next(environment); adapter.UpstreamWentAsyncTcs.TrySetResult(0); adapter.UpstreamTask.ContinueWith(adapter.EnsureCompleted, TaskContinuationOptions.ExecuteSynchronously); } catch (Exception ex) { adapter.UpstreamWentAsyncTcs.TrySetException(ex); throw; } return adapter.RequestTask; } else { return next(environment); } }; }