"
ASP.NET (snapshot 2017) Microsoft documentation and samples

Introduction to WebSockets in ASP.NET Core

By Tom Dykstra and Andrew Stanton-Nurse

This article explains how to get started with WebSockets in ASP.NET Core. WebSocket is a protocol that enables two-way persistent communication channels over TCP connections. It is used for applications such as chat, stock tickers, games, anywhere you want real-time functionality in a web application.

View or download sample code ((xref:)how to download). See the Next Steps section for more information.

Prerequisites

When to use it

Use WebSockets when you need to work directly with a socket connection. For example, you might need the best possible performance for a real-time game.

ASP.NET SignalR provides a richer application model for real-time functionality, but it runs only on ASP.NET, not ASP.NET Core. A Core version of SignalR is under development; to follow its progress, see the GitHub repository for SignalR Core.

If you don’t want to wait for SignalR Core, you can use WebSockets directly now. But you might have to develop features that SignalR would provide, such as:

How to use it

Configure the middleware

Add the WebSockets middleware in the Configure method of the Startup class.

[!code-csharpMain]

   1:  #define UseOptions // or NoOptions
   2:  using System;
   3:  using System.Collections.Generic;
   4:  using System.Linq;
   5:  using System.Net.WebSockets;
   6:  using System.Text;
   7:  using System.Threading;
   8:  using System.Threading.Tasks;
   9:  using Microsoft.AspNetCore.Builder;
  10:  using Microsoft.AspNetCore.Hosting;
  11:  using Microsoft.AspNetCore.Http;
  12:  using Microsoft.Extensions.DependencyInjection;
  13:  using Microsoft.Extensions.Logging;
  14:   
  15:  namespace EchoApp
  16:  {
  17:      public class Startup
  18:      {
  19:          // This method gets called by the runtime. Use this method to add services to the container.
  20:          // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
  21:          public void ConfigureServices(IServiceCollection services)
  22:          {
  23:          }
  24:   
  25:          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  26:          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  27:          {
  28:              loggerFactory.AddConsole(LogLevel.Debug);
  29:              loggerFactory.AddDebug(LogLevel.Debug);
  30:   
  31:              if (env.IsDevelopment())
  32:              {
  33:                  app.UseDeveloperExceptionPage();
  34:              }
  35:   
  36:  #if NoOptions
  37:              #region UseWebSockets
  38:              app.UseWebSockets();
  39:              #endregion
  40:  #endif
  41:  #if UseOptions
  42:              #region UseWebSocketsOptions
  43:              var webSocketOptions = new WebSocketOptions()
  44:              {
  45:                  KeepAliveInterval = TimeSpan.FromSeconds(120),
  46:                  ReceiveBufferSize = 4 * 1024
  47:              };
  48:              app.UseWebSockets(webSocketOptions);
  49:              #endregion
  50:  #endif
  51:              #region AcceptWebSocket
  52:              app.Use(async (context, next) =>
  53:              {
  54:                  if (context.Request.Path == "/ws")
  55:                  {
  56:                      if (context.WebSockets.IsWebSocketRequest)
  57:                      {
  58:                          WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
  59:                          await Echo(context, webSocket);
  60:                      }
  61:                      else
  62:                      {
  63:                          context.Response.StatusCode = 400;
  64:                      }
  65:                  }
  66:                  else
  67:                  {
  68:                      await next();
  69:                  }
  70:   
  71:              });
  72:  #endregion
  73:              app.UseFileServer();
  74:          }
  75:  #region Echo
  76:          private async Task Echo(HttpContext context, WebSocket webSocket)
  77:          {
  78:              var buffer = new byte[1024 * 4];
  79:              WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  80:              while (!result.CloseStatus.HasValue)
  81:              {
  82:                  await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
  83:   
  84:                  result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  85:              }
  86:              await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
  87:          }
  88:  #endregion
  89:      }
  90:  }

The following settings can be configured:

[!code-csharpMain]

   1:  #define UseOptions // or NoOptions
   2:  using System;
   3:  using System.Collections.Generic;
   4:  using System.Linq;
   5:  using System.Net.WebSockets;
   6:  using System.Text;
   7:  using System.Threading;
   8:  using System.Threading.Tasks;
   9:  using Microsoft.AspNetCore.Builder;
  10:  using Microsoft.AspNetCore.Hosting;
  11:  using Microsoft.AspNetCore.Http;
  12:  using Microsoft.Extensions.DependencyInjection;
  13:  using Microsoft.Extensions.Logging;
  14:   
  15:  namespace EchoApp
  16:  {
  17:      public class Startup
  18:      {
  19:          // This method gets called by the runtime. Use this method to add services to the container.
  20:          // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
  21:          public void ConfigureServices(IServiceCollection services)
  22:          {
  23:          }
  24:   
  25:          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  26:          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  27:          {
  28:              loggerFactory.AddConsole(LogLevel.Debug);
  29:              loggerFactory.AddDebug(LogLevel.Debug);
  30:   
  31:              if (env.IsDevelopment())
  32:              {
  33:                  app.UseDeveloperExceptionPage();
  34:              }
  35:   
  36:  #if NoOptions
  37:              #region UseWebSockets
  38:              app.UseWebSockets();
  39:              #endregion
  40:  #endif
  41:  #if UseOptions
  42:              #region UseWebSocketsOptions
  43:              var webSocketOptions = new WebSocketOptions()
  44:              {
  45:                  KeepAliveInterval = TimeSpan.FromSeconds(120),
  46:                  ReceiveBufferSize = 4 * 1024
  47:              };
  48:              app.UseWebSockets(webSocketOptions);
  49:              #endregion
  50:  #endif
  51:              #region AcceptWebSocket
  52:              app.Use(async (context, next) =>
  53:              {
  54:                  if (context.Request.Path == "/ws")
  55:                  {
  56:                      if (context.WebSockets.IsWebSocketRequest)
  57:                      {
  58:                          WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
  59:                          await Echo(context, webSocket);
  60:                      }
  61:                      else
  62:                      {
  63:                          context.Response.StatusCode = 400;
  64:                      }
  65:                  }
  66:                  else
  67:                  {
  68:                      await next();
  69:                  }
  70:   
  71:              });
  72:  #endregion
  73:              app.UseFileServer();
  74:          }
  75:  #region Echo
  76:          private async Task Echo(HttpContext context, WebSocket webSocket)
  77:          {
  78:              var buffer = new byte[1024 * 4];
  79:              WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  80:              while (!result.CloseStatus.HasValue)
  81:              {
  82:                  await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
  83:   
  84:                  result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  85:              }
  86:              await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
  87:          }
  88:  #endregion
  89:      }
  90:  }

Accept WebSocket requests

Somewhere later in the request life cycle (later in the Configure method or in an MVC action, for example) check if it’s a WebSocket request and accept the WebSocket request.

This example is from later in the Configure method.

[!code-csharpMain]

   1:  #define UseOptions // or NoOptions
   2:  using System;
   3:  using System.Collections.Generic;
   4:  using System.Linq;
   5:  using System.Net.WebSockets;
   6:  using System.Text;
   7:  using System.Threading;
   8:  using System.Threading.Tasks;
   9:  using Microsoft.AspNetCore.Builder;
  10:  using Microsoft.AspNetCore.Hosting;
  11:  using Microsoft.AspNetCore.Http;
  12:  using Microsoft.Extensions.DependencyInjection;
  13:  using Microsoft.Extensions.Logging;
  14:   
  15:  namespace EchoApp
  16:  {
  17:      public class Startup
  18:      {
  19:          // This method gets called by the runtime. Use this method to add services to the container.
  20:          // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
  21:          public void ConfigureServices(IServiceCollection services)
  22:          {
  23:          }
  24:   
  25:          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  26:          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  27:          {
  28:              loggerFactory.AddConsole(LogLevel.Debug);
  29:              loggerFactory.AddDebug(LogLevel.Debug);
  30:   
  31:              if (env.IsDevelopment())
  32:              {
  33:                  app.UseDeveloperExceptionPage();
  34:              }
  35:   
  36:  #if NoOptions
  37:              #region UseWebSockets
  38:              app.UseWebSockets();
  39:              #endregion
  40:  #endif
  41:  #if UseOptions
  42:              #region UseWebSocketsOptions
  43:              var webSocketOptions = new WebSocketOptions()
  44:              {
  45:                  KeepAliveInterval = TimeSpan.FromSeconds(120),
  46:                  ReceiveBufferSize = 4 * 1024
  47:              };
  48:              app.UseWebSockets(webSocketOptions);
  49:              #endregion
  50:  #endif
  51:              #region AcceptWebSocket
  52:              app.Use(async (context, next) =>
  53:              {
  54:                  if (context.Request.Path == "/ws")
  55:                  {
  56:                      if (context.WebSockets.IsWebSocketRequest)
  57:                      {
  58:                          WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
  59:                          await Echo(context, webSocket);
  60:                      }
  61:                      else
  62:                      {
  63:                          context.Response.StatusCode = 400;
  64:                      }
  65:                  }
  66:                  else
  67:                  {
  68:                      await next();
  69:                  }
  70:   
  71:              });
  72:  #endregion
  73:              app.UseFileServer();
  74:          }
  75:  #region Echo
  76:          private async Task Echo(HttpContext context, WebSocket webSocket)
  77:          {
  78:              var buffer = new byte[1024 * 4];
  79:              WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  80:              while (!result.CloseStatus.HasValue)
  81:              {
  82:                  await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
  83:   
  84:                  result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  85:              }
  86:              await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
  87:          }
  88:  #endregion
  89:      }
  90:  }

A WebSocket request could come in on any URL, but this sample code only accepts requests for /ws.

Send and receive messages

The AcceptWebSocketAsync method upgrades the TCP connection to a WebSocket connection and gives you a WebSocket object. Use the WebSocket object to send and receive messages.

The code shown earlier that accepts the WebSocket request passes the WebSocket object to an Echo method; here’s the Echo method. The code receives a message and immediately sends back the same message. It stays in a loop doing that until the client closes the connection.

[!code-csharpMain]

   1:  #define UseOptions // or NoOptions
   2:  using System;
   3:  using System.Collections.Generic;
   4:  using System.Linq;
   5:  using System.Net.WebSockets;
   6:  using System.Text;
   7:  using System.Threading;
   8:  using System.Threading.Tasks;
   9:  using Microsoft.AspNetCore.Builder;
  10:  using Microsoft.AspNetCore.Hosting;
  11:  using Microsoft.AspNetCore.Http;
  12:  using Microsoft.Extensions.DependencyInjection;
  13:  using Microsoft.Extensions.Logging;
  14:   
  15:  namespace EchoApp
  16:  {
  17:      public class Startup
  18:      {
  19:          // This method gets called by the runtime. Use this method to add services to the container.
  20:          // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
  21:          public void ConfigureServices(IServiceCollection services)
  22:          {
  23:          }
  24:   
  25:          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  26:          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  27:          {
  28:              loggerFactory.AddConsole(LogLevel.Debug);
  29:              loggerFactory.AddDebug(LogLevel.Debug);
  30:   
  31:              if (env.IsDevelopment())
  32:              {
  33:                  app.UseDeveloperExceptionPage();
  34:              }
  35:   
  36:  #if NoOptions
  37:              #region UseWebSockets
  38:              app.UseWebSockets();
  39:              #endregion
  40:  #endif
  41:  #if UseOptions
  42:              #region UseWebSocketsOptions
  43:              var webSocketOptions = new WebSocketOptions()
  44:              {
  45:                  KeepAliveInterval = TimeSpan.FromSeconds(120),
  46:                  ReceiveBufferSize = 4 * 1024
  47:              };
  48:              app.UseWebSockets(webSocketOptions);
  49:              #endregion
  50:  #endif
  51:              #region AcceptWebSocket
  52:              app.Use(async (context, next) =>
  53:              {
  54:                  if (context.Request.Path == "/ws")
  55:                  {
  56:                      if (context.WebSockets.IsWebSocketRequest)
  57:                      {
  58:                          WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
  59:                          await Echo(context, webSocket);
  60:                      }
  61:                      else
  62:                      {
  63:                          context.Response.StatusCode = 400;
  64:                      }
  65:                  }
  66:                  else
  67:                  {
  68:                      await next();
  69:                  }
  70:   
  71:              });
  72:  #endregion
  73:              app.UseFileServer();
  74:          }
  75:  #region Echo
  76:          private async Task Echo(HttpContext context, WebSocket webSocket)
  77:          {
  78:              var buffer = new byte[1024 * 4];
  79:              WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  80:              while (!result.CloseStatus.HasValue)
  81:              {
  82:                  await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);
  83:   
  84:                  result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
  85:              }
  86:              await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
  87:          }
  88:  #endregion
  89:      }
  90:  }

When you accept the WebSocket before beginning this loop, the middleware pipeline ends. Upon closing the socket, the pipeline unwinds. That is, the request stops moving forward in the pipeline when you accept a WebSocket, just as it would when you hit an MVC action, for example. But when you finish this loop and close the socket, the request proceeds back up the pipeline.

Next steps

The sample application that accompanies this article is a simple echo application. It has a web page that makes WebSocket connections, and the server just resends back to the client any messages it receives. Run it from a command prompt (it’s not set up to run from Visual Studio with IIS Express) and navigate to http://localhost:5000. The web page shows connection status at the upper left:

Initial state of web page
Initial state of web page

Select Connect to send a WebSocket request to the URL shown. Enter a test message and select Send. When done, select Close Socket. The Communication Log section reports each open, send, and close action as it happens.

Initial state of web page
Initial state of web page


Comments ( )
Link to this page: //www.vb-net.com/AspNet-DocAndSamples-2017/aspnetcore/fundamentals/websockets.htm
< THANKS ME>