Has anyone has any good experience with opening a websocket connection inside MVC controller?
Technology stack: ASPNET Core 1.0 (RC1) MVC, dnx46, System.Net.WebSockets
Why MVC instead of middleware: for overall consistency, routing, already injected repositories, an option to call private methods in the same controller.
[HttpGet("v1/resources/{id}")]
public async Task<IActionResult> GetAsync(string id)
{
var resource = await this.repository.GetAsync(id);
if (resource == null)
{
return new HttpStatusCodeResult(404);
}
if (this.HttpContext.WebSockets.IsWebSocketRequest)
{
var webSocket = await this.HttpContext.WebSockets.AcceptWebSocketAsync();
if (webSocket != null && webSocket.State == WebSocketState.Open)
{
while (true)
{
var response = string.Format("Hello! Time {0}", System.DateTime.Now.ToString());
var bytes = System.Text.Encoding.UTF8.GetBytes(response);
await webSocket.SendAsync(new System.ArraySegment<byte>(bytes),
WebSocketMessageType.Text, true, CancellationToken.None);
await Task.Delay(2000);
}
}
}
return new HttpStatusCodeResult(101);
}
Question: are there any known downsides going with way instead of handling a websocket connections in a middleware? How about the handshake, do we need to do anything else in addition to returning HTTP 101 status code?
Update 1: why not SignalR? there is no need to use fallback techniques, so while it's a good product, it see no benefit of adding additional dependency in this situation.
Update 2: one downside I've already noticed - when the while(true) exists (for simplicity reasons, not shown in an example above, let' say, when a channel needs to be closed), the methods needs to return something (Task). What it should be? HTTP 200 status response? I guess no, because in the WebSockets documentation is written, that nothing should be sent after the "close" frame.
Update 3: one thing I learned the hard way, that if you want to get WebSockets working while debugging in Visual Studio 2015 using IIS Express 10.0 on Windows 10, you still have to use https://github.com/aspnet/WebSockets and configure app.UseWebSockets() in your Startup.cs file. Otherwise, IsWebSocketRequest will be false. Anyone knows why? Handshake?
To open a websocket connection, we need to create new WebSocket using the special protocol ws in the url: let socket = new WebSocket("ws://javascript.info"); There's also encrypted wss:// protocol. It's like HTTPS for websockets.
WebSockets is actually the underlying transport that SignalR uses, at least most of the time. SignalR has the ability to fall back to other ways of transporting messages, such as long-polling over HTTP. This is useful in situations where you don't have WebSockets support.
SignalR uses the new WebSocket transport where available and falls back to older transports where necessary. While you could certainly write your app using WebSocket directly, using SignalR means that a lot of the extra functionality you would need to implement is already done for you.
Seems fine.
while(true)
to while (!HttpContext.RequestAborted.IsCancellationRequested)
so you detect client disconnects and end the request. I'm assuming all of that code is temporary and you'll actually be reading something from the websocket.
All the usual websocket rules apply:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With