【发布时间】:2018-09-11 05:05:55
【问题描述】:
我正在处理 ASP.NET Core 2.0 中的一些 websocket。我想接受传入的请求并将它们交给单例服务,以便可以轻松地从 API 控制器向它们发送消息。我的服务器根本没有读取任何内容,它只是接受连接并向它们发送消息。
每当我尝试访问套接字以发送消息时,它总是被释放 (ObjectDisposedException)。我不确定如何以不处理的方式正确地将连接从中间件传递到服务。我该怎么做?
websocket 管理器(单例):
public class WebSocketManager
{
private readonly ConcurrentDictionary<Guid, WebSocket> _sockets;
protected WebSocketManager()
{
_sockets = new ConcurrentDictionary<Guid, WebSocket>();
}
public Guid AddWebSocket(WebSocket socket)
{
var guid = Guid.NewGuid();
_sockets.TryAdd(guid, socket);
return guid;
}
public async Task SendAsync(Guid guid, string message)
{
if (!_sockets.TryGetValue(guid, out var socket))
return;
await SendMessageAsync(socket, message);
}
public async Task SendAllAsync(string message)
{
foreach (var socket in _sockets)
{
if (socket.Value.State == WebSocketState.Open)
await SendMessageAsync(socket.Value, message);
else
await RemoveWebSocketAsync(socket.Key);
}
}
private async Task SendMessageAsync(WebSocket socket, string message)
{
await socket.SendAsync(
new ArraySegment<byte>(Encoding.UTF8.GetBytes(message)),
WebSocketMessageType.Text,
true,
CancellationToken.None);
}
private async Task RemoveWebSocketAsync(Guid guid)
{
if (!_sockets.TryRemove(guid, out var socket))
return;
if (socket?.State == WebSocketState.Open)
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
socket.Dispose();
}
}
接受连接的中间件:
public class WebSocketMiddleware
{
private readonly RequestDelegate _next;
private readonly WebSocketManager _wsMgr;
public WebSocketMiddleware(
RequestDelegate next,
WebSocketManager wsMgr)
{
_next = next;
_wsMgr = wsMgr;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Path != "/ws")
{
await _next(context);
return;
}
if (!context.WebSockets.IsWebSocketRequest)
{
context.Response.StatusCode = 400;
await context.Response.WriteAsync("This endpoint accepts only websocket connections.");
return;
}
var guid = _wsMgr.AddWebSocket(await context.WebSockets.AcceptWebSocketAsync());
// this call succeeds
await _wsMgr.SendAsync(guid, "test message");
}
}
示例控制器调用:
public class WinLossController : Controller
{
private readonly WebSocketManager _wsMgr;
public WinLossController(WebSocketManager wsMgr)
{
_wsMgr = wsMgr;
}
[HttpPost]
public async Task<IActionResult> Update()
{
await _wsMgr.SendAllAsync("test controller update");
return NoContent();
}
}
【问题讨论】:
标签: c# asp.net-core websocket