Live updates with SignalR - stefffdev/NubeSync GitHub Wiki
When a client pushes its changes to the server, all other clients can be notified via SignalR to trigger a sync, which gives the user a "realtime" experience when updating data.
The payload in this notification can be kept very simple, as the notification only triggers a sync on the client.
- Create a new file UpdateHub.cs with the following contents:
using Microsoft.AspNetCore.SignalR;
namespace Nube.SampleService.Hubs
{
public class UpdateHub : Hub
{
}
}
- In the Startup.cs file in the server project, add the following code to the ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSignalR();
}
- Configure the hub routing in the Configure method of Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<UpdateHub>("/updateHub");
});
}
- Trigger a update to that hub whenever a client synced operations, make your OperationsController.cs look like this:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Nube.SampleService.Hubs;
using Nube.Server;
using Nube.Server.Data;
using NubeSync.Service.Data;
namespace NubeSync.Service.Controllers
{
[ApiController]
[Route("[controller]")]
public class OperationsController : ControllerBase
{
private readonly DataContext _context;
private readonly IOperationService _operationService;
private readonly IHubContext<UpdateHub> _hubContext;
public OperationsController(
DataContext context,
IOperationService operationService,
IHubContext<UpdateHub> hubContext)
{
_context = context;
_operationService = operationService;
_hubContext = hubContext;
}
[HttpPost]
public async Task<IActionResult> PostOperationsAsync(List<NubeOperation> operations)
{
try
{
await _operationService.ProcessOperationsAsync(_context, operations);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
await _hubContext.Clients.All.SendAsync("Update", "user", "message");
return Ok();
}
}
- Install the nuget package Microsoft.AspNetCore.SignalR.Client in all your projects
- Add the following method to MainPage.xaml.cs:
private async Task ConfigureSignalRAsync()
{
string hubUrl = "https://localhost:5001/updateHub";
if (DeviceInfo.Platform == DevicePlatform.Android)
{
hubUrl = "https://10.0.2.2:5001/updateHub";
}
var hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl, (opts) =>
{
opts.HttpMessageHandlerFactory = (message) =>
{
if (message is HttpClientHandler clientHandler2)
// bypass the SSL certificate for local debugging
clientHandler2.ServerCertificateCustomValidationCallback +=
(sender, certificate, chain, sslPolicyErrors) => { return true; };
return message;
};
}).Build();
hubConnection.Closed += async (error) =>
{
await Task.Delay(new Random().Next(0, 5) * 1000);
await hubConnection.StartAsync();
};
hubConnection.On<string, string>("Update", async (user, message) =>
{
await SyncAsync();
});
await hubConnection.StartAsync();
}
}
- Call the method ConfigureSignalRAsync(); in ContentPage_Appearing
That's it, if you run the app on multiple devices, changes made on one device should appear on the other devices almost immediatly!
Mind that this is a very primitive implementation, that should be refined for the use in production, as for example a sync by a certain client also triggers a unnecessary sync on that client itself.