Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opening a websocket channel inside MVC controller

Tags:

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?

like image 461
Zygimantas Avatar asked Feb 22 '16 12:02

Zygimantas


People also ask

How do I open a WebSocket connection?

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.

What is the difference between SignalR and web sockets?

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.

Is SignalR based on WebSocket?

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.


1 Answers

Seems fine.

  • You probably want to change the while(true) to while (!HttpContext.RequestAborted.IsCancellationRequested) so you detect client disconnects and end the request.
  • You don't need to check for null or the state of the websocket after you call accept.

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:

  • Use SSL (when you're hosting it forreal)
  • It won't work on multiple servers (it's a point to point socket connection)
  • You need to support handling partial frames. You can punt this if you know the client won't send any.
like image 107
davidfowl Avatar answered Nov 04 '22 01:11

davidfowl