Mitkins
Mitkins

Reputation: 4341

Share SignalR Service with Blazor Server and Azure Function

I have a web app that's running on Azure App Services. It's a Blazor Server backed by a SignalR Service. I also have some background processing that's performed by an Azure Function. Once the Function is complete, I want to send a notification to the web app via SignalR.

I have achieved this by enabling the SignalR output binding on the Azure Function. As long as I treat the Function App as a SignalR hub (i.e. the Blazor Server creates a HubConnection to the Function App) - I'm able to receive messages sent from the Azure Function.

However, in the above scenario I had to configure a second SignalR instance that's running in "Serverless" mode. So I'm wondering, is there an alternative method I could use that side-steps the serverless design? Can I just use the SignalR client inside my Azure Function (and manually create a HubConnection to the first SignalR Service)?

Or is that a little too heavy for an Azure Function? Would I be better off creating a push notification another way (e.g. the Blazor Server reacts to a Service Bus queue and then sends a message via SignalR)?

Upvotes: 0

Views: 1033

Answers (1)

Mitkins
Mitkins

Reputation: 4341

So I came up with 2 possible answers. In the first version I added the SignalR client to the Azure Function:

[Function("SignalRFunction")]
public static async Task RunAsync([ServiceBusTrigger("import-request")] string json, FunctionContext context)
{
    var conn = new HubConnectionBuilder()
        .WithUrl( "https://localhost:5001" )
        .Build();

    await conn.StartAsync();
    await conn.InvokeAsync( "Broadcast", "me", "some message" );
}

This connects to a hub on my Blazor Server and invokes the Broadcast message on my ImportHub:

public class ImportHub : Hub
{
    public const string HubUrl = "/import";

    public async Task Broadcast(string username, string message)
    {
        await Clients.All.SendAsync("Broadcast", username, message);
    }
}

But using this method, I'm creating a SignalR connection per Function call. Probably not the best plan. I could turn conn into a static object (like you might do with HttpClient), but I still need to call StartAsync(). I'm not sure what the best practice would be for a HubConnection.

Instead, I've opted for answer 2 - the Azure Function makes an api call to the Blazor server. Here's my function now:

[Function("SignalRFunction")]
public static async Task RunAsync([ServiceBusTrigger("import-request")] string json, FunctionContext context)
{
    var client = RestService.For<IImportHubApi>( "https://localhost:5001" );

    await client.Broadcast("me", json);
}

For the client, I'm using Refit:

public interface IImportHubApi
{
    [Get("/api/broadcast")]
    Task Broadcast( string user, string message );
}

On my Blazor server, I have the following API controller:

[Route("api/broadcast")]
[ApiController]
public class BroadcastController : ControllerBase
{
    private readonly IHubContext<ImportHub> _hub;

    public BroadcastController(IHubContext<ImportHub> hub)
    {
        _hub = hub;
    }

    [HttpGet]
    public async Task Get(string user, string message)
    {
        await _hub.Clients.All.SendAsync("Broadcast", user, message);
    }
}

So I think that allows my Azure Function to scale (if it were relevant) without worrying about managing connections whilst utilising the one SignalR Service (in Default mode).

However, whether that's a good idea (from a security point of view) is another question. I figure as long as the push notification isn't used for evil (i.e. is used to refresh the display, not to kick off some process) then it's a matter of making sure my server code just uses the notification to prompt a UI refresh.

We do have an API server running on App Service. So I could move this API call to there and put it behind a firewall (API Management). That way, the broadcast would only be possible within the VPC. I'm assuming I could then lock down ImportHub so you have to be authenticated first.

But I'm interested in what other people might have to say. Any advice is welcome!

Upvotes: 2

Related Questions