Websockets using OWIN

前端 未结 1 1687
傲寒
傲寒 2021-02-19 05:50

All the examples using Microsoft WebSockets over a web-api that I\'ve seen so far use IIS, the implementation is on the get method the HTTP connection is upgraded to a websocket

1条回答
  •  感动是毒
    2021-02-19 06:34

    I finally figured out how to resolve the issue. You can find the code below, also I've written a basic app which uses websockets on OWIN.

    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    using Microsoft.Owin;
    
    namespace NoteApp.WebService.Controller {
       using System;
       using System.Net.WebSockets;
       using System.Text;
       using System.Threading;
       using System.Threading.Tasks;
       using NoteApp.WebService.Handler;
       using WebSocketAccept = System.Action<
                                    System.Collections.Generic.IDictionary, // WebSocket Accept parameters
                                    System.Func< // WebSocketFunc callback
                                        System.Collections.Generic.IDictionary, // WebSocket environment
                                        System.Threading.Tasks.Task>>;
       using WebSocketCloseAsync = System.Func<
                                        int, // closeStatus
                                        string, // closeDescription
                                        System.Threading.CancellationToken, // cancel
                                        System.Threading.Tasks.Task>;
       using WebSocketReceiveAsync = System.Func<
                      System.ArraySegment, // data
                      System.Threading.CancellationToken, // cancel
                      System.Threading.Tasks.Task<
                          System.Tuple< // WebSocketReceiveTuple
                              int, // messageType
                              bool, // endOfMessage
                              int>>>; // count
       // closeStatusDescription
       using WebSocketReceiveResult = System.Tuple;
       using WebSocketSendAsync = System.Func<
                                           System.ArraySegment, // data
                                           int, // message type
                                           bool, // end of message
                                           System.Threading.CancellationToken, // cancel
                                           System.Threading.Tasks.Task>;
    
       public class NoteController : ApiController {
          public HttpResponseMessage Get() {
             IOwinContext owinContext = Request.GetOwinContext();
    
             WebSocketAccept acceptToken = owinContext.Get("websocket.Accept");
             if (acceptToken != null) {
                var requestHeaders = GetValue>(owinContext.Environment, "owin.RequestHeaders");
    
                Dictionary acceptOptions = null;
                string[] subProtocols;
                if (requestHeaders.TryGetValue("Sec-WebSocket-Protocol", out subProtocols) && subProtocols.Length > 0) {
                   acceptOptions = new Dictionary();
                   // Select the first one from the client
                   acceptOptions.Add("websocket.SubProtocol", subProtocols[0].Split(',').First().Trim());
                }
                acceptToken(acceptOptions, ProcessSocketConnection);
    
    
             } else {
                return new HttpResponseMessage(HttpStatusCode.BadRequest);
             }
             return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
          }
    
          private async Task ProcessSocketConnection(IDictionary wsEnv) {
             var wsSendAsync = (WebSocketSendAsync)wsEnv["websocket.SendAsync"];
             var wsCloseAsync = (WebSocketCloseAsync)wsEnv["websocket.CloseAsync"];
             var wsCallCancelled = (CancellationToken)wsEnv["websocket.CallCancelled"];
             var wsRecieveAsync = (WebSocketReceiveAsync)wsEnv["websocket.ReceiveAsync"];
    
             //pass the sendasync tuple and the cancellation token to the handler. The handler uses the sendasync method to send message. Each connected client has access to this
             var handler = new NoteSocketHandler(wsSendAsync, CancellationToken.None);
             handler.OnOpen();
             var buffer = new ArraySegment(new byte[100]);
             try {
                object status;
                while (!wsEnv.TryGetValue("websocket.ClientCloseStatus", out status) || (int)status == 0) {
                   WebSocketReceiveResult webSocketResultTuple = await wsRecieveAsync(buffer, CancellationToken.None);                   
                   int count = webSocketResultTuple.Item3;
    
                   handler.OnMessage(Encoding.UTF8.GetString(buffer.Array, 0, count));
                }
             } catch (Exception ex) {
                Console.WriteLine(ex.Message);
                throw ex;
             }
             handler.OnClose();
             await wsCloseAsync((int)WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
          }
    
          T GetValue(IDictionary env, string key) {
             object value;
             return env.TryGetValue(key, out value) && value is T ? (T)value : default(T);
          }
    
    
       }
    }
    

    0 讨论(0)
提交回复
热议问题