Hugo Buff
Hugo Buff

Reputation: 421

SignalR event not being received through dependency injection

I am working on integrating SignalR into an error/exception logging package which is being consumed by an AspNetCore project.

The logging package offers 2 ways to log errors:

  1. Manually through an ICustomLogger interface which can be injected, then calling _customLogger.LogError(...)
  2. Automatically through a registered exception handler by registering IApplicationBuilder.UseExceptionHandler to construct an instance of the custom logger, then calling .LogError(...) similar to the above

To test this functionality, I have created 3 endpoints in a project which consumes this package:
/UnhandledException:

internal static async Task TestUnhandledException()
{
    //caught by the exception handler mentioned above
    //logs the error and a message is received in the in the front-end by signal r
    //no issues
    throw new NotImplementedException();
}

/SendMessage:

public static async Task SendSignalRMessage(IHubContext<CustomLogger.SignalR.EventHub> hubContext)
{
    //uses the dependency-injected event hub from package
    //does not call any functions from CustomLogger
    //no issues
    await hubContext.Clients.All.SendAsync("NewEvent", "Hello");
}

/ExplicitTest:

internal static async Task Test(ICustomLogger logger)
{
    //relies on injected CustomLogger receiving an injected IHubContext<EventHub>
    //performs logging successfully but signalr message is not received in front-end
    //issues!
    var a = await logger.LogEventAsync(LogLevel.Info, "Manual event", "Is this message sent?");
}

The EventHub is registered in the consuming project's Program.cs through:

app.UseEndpoints(ep => ep.MapHub<EventHub>("/Events"));

The custom logging package consists of:

public class CustomLogger
{
    private readonly IHubContext<EventHub> hubContext;

    public EventLogger(IOptionsSnapshot<LoggerSettings> settings, IHubContext<EventHub> hubContext)
    {
        this.hubContext = hubContext;
    }

    //Snip boring code that does actual logging

    private async Task SendEventAsync(Event evt)
    {
        if (this.hubContext == null)
        {
            await this.LogEventAsync(LogLevel.Warning, "Configuration Error", "SignalR hub context is null");
            return;
        }

        var eventData = new NewEvent
        {
            EventId = evt.EventId,
            TimeStamp = evt.TimeStamp,
            Message = evt.Message,
        };

        try
        {
            await this.hubContext.Clients.All.SendAsync(MessageType.NewEvent, eventData);
        }
        catch (Exception ex)
        {
            await this.LogExceptionAsync(LogLevel.Warning, ex);
        }
    }
}

As you can see, calling the function to manually log the data (in the non-working /ExplicitTest endpoint) requires a dependency-injected ICustomLogger from the dependency package, the constructor of which requires a dependency-injected IHubContext<EventHub>. The actual logging within the package will run successfully and on pausing the debugger, I can see that the injected ICustomLogger has an IHubContext with 1 active connection. No exception appears to be thrown when attempting to send a message to the connected clients, yet the message is not received.

Upvotes: 1

Views: 79

Answers (1)

Jason Pan
Jason Pan

Reputation: 22082

After checking the issue, could you tell us why you are using EventLogger as a constructor in the CustomLogger class.

// Class Name
public class CustomLogger
{
    private readonly IHubContext<EventHub> hubContext;
    // <========= Here <==========
    // The name of the constructor should be same as CLASS NAME
    public EventLogger(IOptionsSnapshot<LoggerSettings> settings, IHubContext<EventHub> hubContext)
    {
        this.hubContext = hubContext;
    }
    ...
    ...
}

Because of the lack of your EventLogger, I can't be sure that's the root cause, but you can set a breakpoint in SendEventAsync and see if the method is executed.

In my test environment, it works well. Please don't forget to add below codein your Program.cs file.

builder.Services.AddSignalR(); 
builder.Services.AddSingleton<ICustomLogger, CustomLogger>();

Upvotes: 0

Related Questions