SignalR server for asp.net core is currently in version 0.2.0. It has not been released yet to the official nuget repositories, so we must configure our project to use the asp.net core dev feed to obtain SignalR related packages.
Autofac for asp.net core still does not have the hubs registration extensions that we are used to when using full framework packages, but we will see how we can write them from scratch.
First of all we create a new asp.net core web project and we create a NuGet.config file so we can specify the core devevelopment NuGet feed so we can restore the websockets and SignalR packages.
The NuGet.config file should look like this:
1 2 3 4 5 6 7 |
<?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <add key="AspNetCore" value="https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json" /> <add key="NuGet" value="https://api.nuget.org/v3/index.json" /> </packageSources> </configuration> |
Once created the nuget file, we should add the dependencies to project.json. The dependencies to use SignalR and autofac are shown below:
1 2 3 |
"Microsoft.AspNetCore.SignalR.Server": "0.2.0-*", "Microsoft.AspNetCore.WebSockets": "0.2.0-*", "Autofac.Extensions.DependencyInjection": "4.0.0" |
We are now set to start configuring our hubs!. As an example we are going to create a ChatHub that will receive a service to keep track of connections in it’s constructor.
Let’s create first the service interface and implementation to register it with AutoFac:
IHubTrackingService.cs
1 2 3 4 |
public interface IHubTrackingService { bool TrackConnection(HubTrack hubTrack); } |
HubTrackingService.cs
1 2 3 4 5 6 7 8 |
public class HubTrackingService : IHubTrackingService { public bool TrackConnection(HubTrack hubTrack) { // Do some stuff with your repo to keep tracking of connection; return true; } } |
The HubTrack class is a POCO class with the following properties, just as an example:
HubTrack.cs
1 2 3 4 5 6 7 |
public class HubTrack { public string HubName { get; set; } public string UserId { get; set; } public string ConnectionId { get; set; } public DateTime ConnectionTime { get; set; } } |
Now we are ready to create our ChatHub injecting in the constructor the HubTrackingService to allow tracking clients with OnConnected Method:
ChatHub.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class ChatHub : Hub { private readonly IHubTrackingService hubTrackingService; public ChatHub(IHubTrackingService hubTrackingService) { this.hubTrackingService = hubTrackingService; } public override Task OnConnected() { RegisterConnection(); return base.OnConnected(); } private void RegisterConnection() { this.hubTrackingService.TrackConnection(new HubTrack() { ConnectionId = Context.ConnectionId, HubName = nameof(ChatHub), UserId = Context.User?.Identity?.Name ?? string.Empty, ConnectionTime = DateTime.UtcNow }); } } |
Now, it is time to configure our Startup.cs to add SignalR Server and dependency injection.
In full framework, we use the RegisterHubs autofac extesion to register our hub classes:
1 |
builder.RegisterHubs(Assembly.GetExecutingAssembly()); |
but it is not available yet in Autofac for asp.net core so we should write a ContainerBuilder Extension to do this for us, the code is shown below:
AutofacExtensions.cs
1 2 3 4 5 6 7 8 9 10 11 |
public static class AutoFacExtensions { public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterHubs(this ContainerBuilder builder, params Assembly[] assemblies) { return builder.RegisterAssemblyTypes(assemblies) .Where(t => typeof(IHub).IsAssignableFrom(t)) .ExternallyOwned(); } } |
Note: We use ExternallyOwned() to allow SignalR disposing the Hubs instead of being managed by Autofac.
Once our extension is added to the project we should set our Configure and ConfigureServices methods in Startup.cs
Startup.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddSignalR(); services.AddMvc(); var builder = new ContainerBuilder(); builder.RegisterType & lt; HubTrackingService & gt; ().As & lt; IHubTrackingService & gt; (); builder.RegisterHubs(typeof(Startup).GetTypeInfo().Assembly); builder.Populate(services); return new AutofacServiceProvider(builder.Build()); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { app.UseSignalR(); app.UseMvc(); } |
Notice the line:
1 |
builder.RegisterHubs(typeof(Startup).GetTypeInfo().Assembly); |
In asp.net core we don’t have Assembly.GetExecutingAssembly() so we get the assembly from the Startup.cs type
How do we use the Hubs to notify clients when execution is inside a Mvc/Api Controller?
If we are working inside a controller, we can also notify the clients that are connected to a hub injecting the SignalR IConnectionManager interface. We just need to get the context using the hub target type we want to invoke and perform the client operation.
Imagine we have a TicketController, where Tickets can be added through a POST action and we want to notify all clients connected to the NotificationHub about the ticket being added, we could do it like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
[Route("api/[controller]")] public class TicketController : Controller { private readonly IConnectionManager connectionManager; private readonly ITicketService ticketService; public TicketController(IConnectionManager connectionManager, ITicketService ticketService) { this.connectionManager = connectionManager; this.ticketService = ticketService; } [HttpPost, Route("[action]")] public void Add(Ticket ticket) { this.ticketService.Add(ticket); connectionManager.GetHubContext & lt; NotificationHub & gt; () .Clients.All.notifyTicket(ticket); } } |
And we are done!. We can now use SignalR in our Asp.Net Core project using Autofac dependency injection.
Happing coding!.