Zygimantas
Zygimantas

Reputation: 8787

Opening a websocket channel inside MVC controller

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?

Upvotes: 20

Views: 18488

Answers (1)

davidfowl
davidfowl

Reputation: 38764

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.

Upvotes: 8

Related Questions