Asp.Net打开websocket作为客户端

时间:2017-10-23 14:33:49

标签: asp.net asp.net-mvc-4 websocket signalr clientwebsocket

在我的应用程序中,我使用SignalR通过我的客户端进行消息传递。但是,应用程序有一个websocket连接到另一台服务器,用于通知,如下所示:

var wsURL = (isSecure() ? "wss://" : "ws://") + wsEndpointURI + "?token=" + token + "&lang=" + language
         + "&uid=" + wsUid,
    notifierWs = new WebSocket(wsURL);

middlewareNotifierWs.onmessage = function (event) {
   var notification = JSON.parse(event.data),
       msg = notification.message;

       // Show the notification
};

我想要做的是从我的Asp.Net应用程序建立此连接,并通过将它们推送到正确的客户端来处理所有传入的消息。 然而,我并没有找到这样一个实现的例子。我找到的所有示例都是关于从我的服务器到客户端设置websocket连接。 (我必须提到我对异步函数不是很熟悉,所以我可能会遇到一些与此相关的错误)

更新

从我发现的最好和(可能)最简单的方法是ClientWebSocket

试图找到一些我发现的例子:Websocket - Server Using HttpListener and Client With ClientWebSocket

从这个例子看,我似乎可以创建一个到我想要的端点的Websocket连接。这就是我做的事情

public static class Program
{
    private static UTF8Encoding encoding = new UTF8Encoding();

    public static async Task Connect()
    {

        ClientWebSocket webSocket = null;
        try
        {
            var url = serverWebSocketConnectionUrl;

            webSocket = new ClientWebSocket();
            await webSocket.ConnectAsync(new Uri(url), CancellationToken.None);
            await Task.WhenAll(OnMessage(webSocket));
        }
        catch (Exception ex)
        {
            // Log it
        }
        finally
        {
            if (webSocket != null)
            {
                webSocket.Dispose();
            }
        }
    }

    public static async Task OnMessage(ClientWebSocket webSocket)
    {
        byte[] buffer = new byte[1024];
        while (webSocket.State == WebSocketState.Open)
        {
            var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            if (result.MessageType == WebSocketMessageType.Close)
            {
                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
                    CancellationToken.None);

            }
            else
            {
                WebSocketNotification notification = Newtonsoft.Json.JsonConvert.DeserializeObject<WebSocketNotification>(Encoding.UTF8.GetString(buffer));

                // Here I want to get to the signalR context and send my message to the correct user.
                var hubContext = GlobalHost.ConnectionManager.GetHubContext<ReportingHub>();
                List<string> userIds = new List<string>();
                userIds.Add(notification.Id);
                hubContext.Clients.Users(userIds).OnMessage(notification);
            }
        }
    }
}

在我的javascript文件中处理我插入的signalR方法 应该从signalR触发的onMessage方法。 (就像我插入signalR处理的所有方法一样,它们工作得很好。)

repHub.client.onMessage = function (notification) {
    // Show the message
}

根据我所做的,目前的结果是:

  1. 我的websocket连接正确打开
  2. 从那里我的调试器进入await Task.WhenAll(OnMessage(webSocket));
  3. 的onMessage
  4. 之后我的调试器在行var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  5. 中等待
  6. 当从服务器发送消息时,我的调试会继续正确显示结果。
  7. 我的问题和疑问是:

    1. 在某些点上触发了我的Connect方法的最终,其中websocket被释放并且我的监听器被释放。 (发送的所有邮件都不会被await webSocket.ReceiveAsync抓住)。在什么情况下这应该发生,我应该寻找什么?

    2. 收到消息后,我正确地将json结果反序列化为WebSocketNotification,但我的javascript函数onMessage永远不会触发。我错过了什么?

    3. 更新2 关于第二个问题,我通过改变

      使其发挥作用
      repHub.client.onMessage => repHub.client.onmessage
      

      我觉得它很奇怪,因为我的报告中心使用signalR在服务器端拥有所有方法,因为camelCase具有首字母大写,而所有方法都在客户端使用简单的camelCase。为什么这种情况不同?我很感激答案。

      更新3

      我在我的OnMessage方法中插入了一个try catch,就像那个

          public static async Task OnMessage(ClientWebSocket webSocket)
          {
              byte[] buffer = new byte[1024];
              while (webSocket.State == WebSocketState.Open)
              {
                  try
                  {
                      // Receive data on ClientWebSocket as an asynchronous operation
                      var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                      if (result.MessageType == WebSocketMessageType.Close)
                      {
                          // If the server sends a message with message type for closure close the websocket connection
                          // Could use the CloseOutputAsync : https://stackoverflow.com/questions/26744420/net-websocket-closeoutputasync-vs-closeasync
                          await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
                              CancellationToken.None);
                      }
                      else
                      {
      
                          WebSocketNotification notification =
                              Newtonsoft.Json.JsonConvert.DeserializeObject<WebSocketNotification>(
                                  Encoding.UTF8.GetString(buffer));
                          var hubContext = GlobalHost.ConnectionManager.GetHubContext<ReportingHub>();
                          List<string> userIds = new List<string>();
                          userIds.Add(notification.Id);
                          hubContext.Clients.Users(userIds).OnMessage(notification);
      
                      }
                  }
                  catch (Exception ex)
                  {
                      var a = ex;
                  }
      
              }
          }
      

      从错误开始,我在Connect进入最终版之前就得到了处理,我得到了以下错误和堆栈跟踪

      An internal WebSocket error occurred. Please see the innerException, if present, for more details.
      
      at System.Net.WebSockets.WebSocketBase.ThrowIfConvertibleException(String methodName, Exception exception, CancellationToken cancellationToken, Boolean aborted)
      at System.Net.WebSockets.WebSocketBase.<ReceiveAsyncCore>d__45.MoveNext()
      --- End of stack trace from previous location where exception was thrown ---
           at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)  
      at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
      at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
      at AthenaWeb.Infrastructure.NotificationWebSocket.<OnMessage>d__3.MoveNext() in C:\Branches\Notifications\trunk\AthenaWeb\Infrastructure\NotificationWebSocket.cs:line 69
      

      我想我应该只是处理它并可能再次打开连接。 现在几乎这是我唯一的问题(如果没有其他要寻找的东西):

      这是最好的方式吗?我应该检查一下我的连接关闭的原因吗?

1 个答案:

答案 0 :(得分:2)

关于您的上一个问题,您可以从post获得一些见解。

似乎WebSockets可能因为多种原因而关闭,因此最好的方法是处理WebSocket闭包并可能重新打开它。

但是,从答案中可以看出,您还应该检查IIS服务器的I / O完成端口。

从@ user4624881提供的一种处理案例的方法可能是使用IAsyncResult.AsyncWaitHandle.WaitOne()进行websocket流产处理。

像这样:

Stream s = this.GetStream();
IAsyncResult ar = s.BeginWrite(data, 0, data.Length, SendAsync, state);
if (!ar.IsCompleted)
    ar.AsyncWaitHandle.WaitOne();