1

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)?

1
  • This seems like a similar question Commented May 25, 2021 at 5:09

1 Answer 1

2

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!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.