2017-01-25 10 views
14

これまでに私が見たweb-api上のMicrosoft WebSocketsを使用するすべての例は、IISを使用しています。実装はgetメソッドにあります.HTTP接続はwebsocketにアップグレードされ、websocketハンドラのインスタンスが渡されます。 HTTPContextへOWINを使用したWebSocket

public HttpResponseMessage Get() { 
    if (HttpContext.Current.IsWebSocketRequest) { 
    var noteHandler = new NoteSocketHandler(); 
    HttpContext.Current.AcceptWebSocketRequest(noteHandler); 
    } 
    return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols); 
} 

OWINパイプラインで同じことを達成しようとしています。問題は、接続がWebSocketを使用するようにアップグレードされているが、WebSocketハンドラを使用していないことです。どこが間違っていますか?提案してください。

OwinContextを利用コントローラー(例WebSockets in Nancy using OWINに続く)、

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, async wsEnv => { 
     var wsSendAsync = (WebSocketSendAsync)wsEnv["websocket.SendAsync"]; 
     var wsRecieveAsync = (WebSocketReceiveAsync)wsEnv["websocket.ReceiveAsync"]; 
     var wsCloseAsync = (WebSocketCloseAsync)wsEnv["websocket.CloseAsync"]; 
     var wsCallCancelled = (CancellationToken)wsEnv["websocket.CallCancelled"]; 

     //should I pass the handler to an event? 
     var handler = new NoteSocketHAndler();    
     }); 

    } else { 
     return new HttpResponseMessage(HttpStatusCode.BadRequest); 
    } 
    return new 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); 
     } 
    } 
} 
+0

もう少しコードが必要な場合があります。 Owinのアプリケーション設定/パイプラインはどこに設定していますか? – Brannon

+0

@Brannon遅延応答のお詫び。私が書いた答えの下で、私はStartup.csであなたがowin appの設定を調べることができるプロジェクトへのリンクを付けました。私は問題が何であるかを理解しました。 – LearnCode

答えて

5

私は最終的に問題を解決する方法を考え出しました。以下のコードを見つけることができます。また、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<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); 
     } 


    } 
} 
関連する問題