How to notify all your client apps that server content has changed?
That requirement is perhaps a standard nowadays since we have various hungry devices (and minds also ๐) for new notifications. In this article I have tested .NET signalR since it looks like it is easy to deploy, handles connection management automatically and scales easily.
Goal is to write server-side code that can broadcast content changes to client as soon as the content changes. SignalR supports following WebSocekets, Server-Side Events and Long Pooling techniques for handling real-time communication. To communicate between clients and servers SignalR uses hubs. A hub is a high-level pipeline that allows a client and server to call methods on each other and we will write one of those methods.
On my github you will find finished project so that you do not need to write code yourself. We have Web API that knows how to do CRUD operations and client Blazor WebAssembly application that consumes data.
First Step: Define a hub โ๏ธ
We write a custom class, and the most important thing is to inherit from Hub class.
LiveUpdatesHub.cs
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
namespace PublicAddressBook.Api.Hubs
{
public class LiveUpdatesHub : Hub
{
public async Task LiveUpdate()
{
await Clients.All.SendAsync("LiveUpdate");
}
}
}
Note: be sure to add using statement for SignalR
Second Step: Configure our newly created class (LiveUpdatesHub) โ๏ธ
All the configuration for .NET 5 or Core applications is done in application Startup.cs. We will need to add endpoint over which we will broadcast data.
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddControllers();
services.AddDbContext<PublicAddressBookContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("PublicAddressBookConnection")));
services.AddScoped<IContacts, Contacts>();
...(check github for full code ex.)
}
And also add service in ConfigureServicesMethod:
Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...(check github for full code ex.)
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<LiveUpdatesHub>("/liveupdateshub");
endpoints.MapControllers();
});
}
Third Step: Notify change โ๏ธ
In context of this application, I want to notify or perhaps it is better to say broadcast data change. Data will change when our API receives create contact POST request. If the data is OK we will write data to DB. After that we just need to call our Hub method (โLiveUpdateโ).
ContactsController.cs
[HttpPost]
public IActionResult CreateContact([FromBody] Contact contact)
{
... (check github for full code ex.)
try
{
var createdContact = _contactsService.AddContact(contact);
// Live Update for Client Apps
_hub.Clients.All.SendAsync("LiveUpdate");
return Created("contact", createdContact);
}
catch (Exception ex)
{
log.Error("PublicAddressBookApiError: ", ex);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
Note:Be sure to add hub service to controller constructor
Fourth Step: Consume changed data โ๏ธ
Since we stayed in .NET world it is easy to consume "data change event" or should I say listen to changes on client side.
In our Blazor component in method OnInitializedAsync() we will make a new instance of hub HubConnectionBuilder() and register what we are listening for.
ContactOverview.razor.cs
namespace PublicAddressBook.Client.Pages
{
... (check github for full code ex.)
public partial class ContactOverview
{
protected override async Task OnInitializedAsync()
{
hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri(baseUrl + liveUpdateEndPoint))
.Build();
hubConnection.On("LiveUpdate", () =>
{
GetLiveNotificationData();
StateHasChanged();
});
await hubConnection.StartAsync();
await GetData();
}
}
Note: On client side, be sure to add SignalR client package
Conclusion ๐ ๐พ
As you can se from this example it is very easy to set up real-time updates with SignalR. On client side you are of course not limited to .NET client and on this link you can find examples for JavaScript and TypeScript. Also, I must mention that your hub method can have parameters, there is a nice chat example on fore mentioned link.
Stay well,
Dino
Top comments (0)