azureazure-functionssignalr.net-8.0

Having issue implementing SignalR with Azure Functions in .NET 8


I'm having an issue with configuring SignalR. I'm working with .NET Azure Functions in isolated process model.

Here's the error message I get:

Exception Unable to resolve service for type 'Microsoft.Azure.SignalR.Management.ServiceManager' while attempting to activate 'PatientNavigationDBAPI.Services.SignalRService'

This is my code:

public static class AzureServiceExtensions
{
     public static IServiceCollection AddAzureServices(this IServiceCollection services)
     {
         //other services
         services.AddSignalR().AddAzureSignalR(Environment.GetEnvironmentVariable(EnvironmentVariable.AzureSignalRConnectionString));
         services.AddScoped<SignalRService>();
         
         return services;
     }
}

In Program.cs, I have:

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication(worker =>
    {
        worker.UseNewtonsoftJson(new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Include,
            Formatting = Formatting.Indented,
            ContractResolver = new DefaultContractResolver
            {
                NamingStrategy = new CamelCaseNamingStrategy()
            }
        });
       
    })
    .ConfigureOpenApi()
    .ConfigureServices((host, services) =>
    {
        services.AddAzureServices();
       
    })
    .Build()
    .SeedData();

host.Run();

Solution

  • Exception Unable to resolve service for type 'Microsoft.Azure.SignalR.Management.ServiceManager' while attempting to activate 'PatientNavigationDBAPI.Services.SignalRService'

    I got the same error when I reproduced the same in my environment. It occurs because Dependency Injection (DI) is trying to create an instance of your SignalRService, but the required dependency ServiceManager is not registered in the service container.

    Below code worked for me:

    SignalRService.cs:

    public class SignalRService
    {
        private readonly IServiceManager _serviceManager;
    
        public SignalRService(IServiceManager serviceManager)
        {
            _serviceManager = serviceManager;
        }
    
        public async Task SendMessageAsync(string hubName, string methodName, object message)
        {
            var hubContext = await _serviceManager.CreateHubContextAsync(hubName, default);
            await hubContext.Clients.All.SendAsync(methodName, message);
            await hubContext.DisposeAsync();
        }
    }
    

    Program.cs:

    var host = new HostBuilder()
        .ConfigureFunctionsWebApplication(worker =>
        {
            worker.UseNewtonsoftJson(new JsonSerializerSettings
            {
                NullValueHandling = NullValueHandling.Include,
                Formatting = Formatting.Indented,
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = new CamelCaseNamingStrategy()
                }
            });
        })
        .ConfigureOpenApi()
        .ConfigureServices((context, services) =>
        {
            services.AddAzureServices();
        })
        .Build();
    
    host.Run();
    

    AzureServiceExtensions.cs:

    public static class AzureServiceExtensions
    {
        public static IServiceCollection AddAzureServices(this IServiceCollection services)
        {
            var connectionString = Environment.GetEnvironmentVariable("AzureSignalRConnectionString");
    
            services.AddSingleton<IServiceManager>(sp =>
            {
                return new ServiceManagerBuilder()
                    .WithOptions(opt => opt.ConnectionString = connectionString)
                    .Build();
            });
    
            services.AddScoped<SignalRService>();
    
            return services;
        }
    }
    

    Function.cs:

    public class Function1
    {
        private readonly SignalRService _signalRService;
        private readonly ILogger<Function1> _logger;
    
        public Function1(SignalRService signalRService, ILogger<Function1> logger)
        {
            _signalRService = signalRService;
            _logger = logger;
        }
    
        [Function("BroadcastMessage")]
        public async Task<HttpResponseData> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
        {
            await _signalRService.SendMessageAsync("chat", "newMessage", new { message = "Hello from Azure Function!" });
    
            var response = req.CreateResponse(HttpStatusCode.OK);
            await response.WriteStringAsync("Message sent via Azure SignalR.");  
            _logger.LogInformation("SignalR message sent.");
            return response;
        }
    }
    

    Output:

    Functions:
    
            BroadcastMessage: [POST] http://localhost:7012/api/BroadcastMessage
    
            RenderOAuth2Redirect: [GET] http://localhost:7012/api/oauth2-redirect.html
    
            RenderOpenApiDocument: [GET] http://localhost:7012/api/openapi/{version}.{extension}
    
            RenderSwaggerDocument: [GET] http://localhost:7012/api/swagger.{extension}
    
            RenderSwaggerUI: [GET] http://localhost:7012/api/swagger/ui
    
    For detailed output, run func with --verbose flag.
    [2025-06-06T09:24:07.457Z] Executing 'Functions.BroadcastMessage' (Reason='This function was programmatically called via the host APIs.', Id=661e9597-d9fa-463f-a639-42ddfe0fbdfb)
    [2025-06-06T09:24:08.093Z] Host lock lease acquired by instance ID '0000000000000000000000004F4DDDC0'.
    [2025-06-06T09:24:09.278Z] SignalR message sent.
    [2025-06-06T09:24:09.310Z] Executed 'Functions.BroadcastMessage' (Succeeded, Id=661e9597-d9fa-463f-a639-42ddfe0fbdfb, Duration=1900ms)
    

    enter image description here