C# 使用OWIN的WebSocket

C# 使用OWIN的WebSocket,c#,asp.net-web-api,websocket,owin,C#,Asp.net Web Api,Websocket,Owin,到目前为止,我看到的所有通过web api使用Microsoft websocket的示例都使用IIS,实现在get方法上。HTTP连接被升级到websocket,websocket处理程序的实例被传递到HTTPContext public HttpResponseMessage Get() { if (HttpContext.Current.IsWebSocketRequest) { var noteHandler = new NoteSocketHandler();

到目前为止,我看到的所有通过web api使用Microsoft websocket的示例都使用IIS,实现在get方法上。HTTP连接被升级到websocket,websocket处理程序的实例被传递到HTTPContext

public HttpResponseMessage Get() {
  if (HttpContext.Current.IsWebSocketRequest) {
     var noteHandler = new NoteSocketHandler();
     HttpContext.Current.AcceptWebSocketRequest(noteHandler);
  }
  return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
}
我试图实现的是在OWIN管道上做同样的事情。我面临的问题是连接正在升级为使用websocket,但它没有使用我的websocket处理程序。我哪里做错了?请建议

控制器利用文本(遵循示例)

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;
字符串[]子目录;
if(requestHeaders.TryGetValue(“Sec WebSocket协议”,out子目录)&&subtocols.Length>0){
acceptOptions=newdictionary();
//从客户端选择第一个
acceptOptions.Add(“websocket.subtocol”,subtocols[0]。拆分(',).First().Trim());
}
acceptToken(acceptOptions,异步wsEnv=>{
var wssendsync=(websocketsendsync)wsEnv[“websocket.sendsync”];
var wsreceiveasync=(WebSocketReceiveAsync)wsEnv[“websocket.ReceiveAsync”];
var wsCloseAsync=(WebSocketCloseAsync)wsEnv[“websocket.CloseAsync”];
var wsCallCancelled=(CancellationToken)wsEnv[“websocket.CallCancelled”];
//我应该将处理程序传递给事件吗?
var handler=new NoteSocketHAndler();
});
}否则{
返回新的HttpResponseMessage(HttpStatusCode.BadRequest);
}
返回新的HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
}
处理程序代码:

using System;
using Socket = Microsoft.Web.WebSockets;
using Newtonsoft.Json;

public class NoteSocketHandler : Socket.WebSocketHandler {
   private static Socket.WebSocketCollection connections = new Socket.WebSocketCollection();

   public NoteSocketHandler() {
   }

   public override void OnOpen() {
      connections.Add(this);
   }

   public override void OnClose() {
      connections.Remove(this);
   }

   public override void OnMessage(string message) {
      ChatMessage chatMessage = JsonConvert.DeserializeObject<ChatMessage>(message);
      foreach (var connection in connections) {
         connection.Send(message);
      }
   }
}
使用系统;
使用Socket=Microsoft.Web.WebSockets;
使用Newtonsoft.Json;
公共类NoteSocketHandler:Socket.WebSocketHandler{
private static Socket.WebSocketCollection connections=new Socket.WebSocketCollection();
公共记事本{
}
公共覆盖无效OnOpen(){
连接。添加(此);
}
公共覆盖void OnClose(){
连接。移除(此);
}
公共覆盖无效消息(字符串消息){
ChatMessage ChatMessage=JsonConvert.DeserializeObject(消息);
foreach(连接中的var连接){
连接。发送(消息);
}
}
}

我终于想出了解决问题的办法。你可以找到下面的代码,我也写了一个基本的应用程序,使用

使用System.Collections.Generic;
使用System.Linq;
Net系统;
使用System.Net.Http;
使用System.Web.Http;
使用Microsoft.Owin;
命名空间NoteApp.WebService.Controller{
使用制度;
使用System.Net.WebSockets;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
使用NoteApp.WebService.Handler;
使用WebSocketAccept=System.Action<
System.Collections.Generic.IDictionary,//WebSocket接受参数
System.Func>;
使用WebSocketCloseAsync=System.Func<
int,//关闭状态
字符串,//closeDescription
System.Threading.CancellationToken,//取消
System.Threading.Tasks.Task>;
使用WebSocketReceiveAsync=System.Func<
System.ArraySegment,//数据
System.Threading.CancellationToken,//取消
System.Threading.Tasks.Task<
System.Tuple>>;//计数
//关闭状态描述
使用WebSocketReceiveResult=System.Tuple;
使用WebSocketSendAsync=System.Func<
System.ArraySegment,//数据
int,//消息类型
bool,//消息结束
System.Threading.CancellationToken,//取消
System.Threading.Tasks.Task>;
公共类NoteController:ApicController{
公共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;
字符串[]子目录;
if(requestHeaders.TryGetValue(“Sec WebSocket协议”,out子目录)&&subtocols.Length>0){
acceptOptions=newdictionary();
//从客户端选择第一个
acceptOptions.Add(“websocket.subtocol”,subtocols[0]。拆分(',).First().Trim());
}
acceptToken(acceptOptions,ProcessSocketConnection);
}否则{
返回新的HttpResponseMessage(HttpStatusCode.BadRequest);
}
返回新的HttpResponseMessage(HttpStatusCode.SwitchingProtocols);
}
专用异步任务ProcessSocketConnection(IDictionary wsEnv){
var wssendsync=(websocketsendsync)wsEnv[“websocket.sendsync”];
var wsCloseAsync=(WebSocketCloseAsync)wsEnv[“websocket.CloseAsync”];
var wsCallCancelled=(CancellationToken)wsEnv[“websocket.CallCancelled”];
var wsreceiveAsync=(WebSocketReceiveAsync)wsEnv[“WebSock
using System;
using Socket = Microsoft.Web.WebSockets;
using Newtonsoft.Json;

public class NoteSocketHandler : Socket.WebSocketHandler {
   private static Socket.WebSocketCollection connections = new Socket.WebSocketCollection();

   public NoteSocketHandler() {
   }

   public override void OnOpen() {
      connections.Add(this);
   }

   public override void OnClose() {
      connections.Remove(this);
   }

   public override void OnMessage(string message) {
      ChatMessage chatMessage = JsonConvert.DeserializeObject<ChatMessage>(message);
      foreach (var connection in connections) {
         connection.Send(message);
      }
   }
}
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<string, object>, // WebSocket Accept parameters
                                System.Func< // WebSocketFunc callback
                                    System.Collections.Generic.IDictionary<string, object>, // 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<byte>, // data
                  System.Threading.CancellationToken, // cancel
                  System.Threading.Tasks.Task<
                      System.Tuple< // WebSocketReceiveTuple
                          int, // messageType
                          bool, // endOfMessage
                          int>>>; // count
   // closeStatusDescription
   using WebSocketReceiveResult = System.Tuple<int, bool, int>;
   using WebSocketSendAsync = System.Func<
                                       System.ArraySegment<byte>, // 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<WebSocketAccept>("websocket.Accept");
         if (acceptToken != null) {
            var requestHeaders = GetValue<IDictionary<string, string[]>>(owinContext.Environment, "owin.RequestHeaders");

            Dictionary<string, object> acceptOptions = null;
            string[] subProtocols;
            if (requestHeaders.TryGetValue("Sec-WebSocket-Protocol", out subProtocols) && subProtocols.Length > 0) {
               acceptOptions = new Dictionary<string, object>();
               // 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<string, object> 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<byte>(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<T>(IDictionary<string, object> env, string key) {
         object value;
         return env.TryGetValue(key, out value) && value is T ? (T)value : default(T);
      }


   }
}