在我的应用程序中,我使用 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);
}
}
}
}
在我处理 signalR 方法的 javascript 文件中,我插入了应该从 signalR 触发的 onMessage 方法。(就像我插入所有由 signalR 处理的方法一样,它们工作得很好。)
repHub.client.onMessage = function (notification) {
// Show the message
}
根据我所做的,目前的结果是:
- 我的 websocket 连接正确打开
- 从那里我的调试器进入
await Task.WhenAll(OnMessage(webSocket));
- 之后我的调试器在行中等待
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
- 当从服务器发送消息时,我的调试将继续正确地得到结果。
我的问题和疑问是:
在某些时候触发了我的
Connect
方法的 finally,其中 websocket 被释放并且我的监听器被释放。(发送的任何消息都不再从 中捕获await webSocket.ReceiveAsync
)。在什么情况下会发生这种情况,我应该寻找什么?收到消息后,我将 json 结果正确反序列化为 WebSocketNotification,但我的 javascript 函数 onMessage 永远不会触发。我错过了什么?
更新 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 到 finally 并被处理之前得到的错误中,我得到以下错误和堆栈跟踪
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
我想我应该可以处理它并可能再次打开连接。现在几乎这是我唯一的问题(如果没有其他要寻找的):
这是最好的方法吗?我应该检查更多关于我的连接关闭的原因吗?