0
votes

I have a .net core 3.0 web application. In Startup.cs, I register an EventProcessor (from Microsoft.Azure.EventHubs.Processor) that listens to an Azure EventHub for events. I do it like this:

await eventProcessorHost.RegisterEventProcessorAsync<TwinChangesEventHandler>();

I'm interested in device twin changes in an IoT Hub that's connected to the EventHub.

So, in the EventProcessor, I want to access the SignalR IHubContext interface (from Microsoft.AspNetCore.SignalR - the new version of SignalR) to be able to notify connected browsers of a device twin property change. My problem is that the EventProcessor can't get a handle to IHubContext. How can I get it?

I see online that people are using dependency injection but because my EventProcessor is created by RegisterEventProcessorAsync() like I showed above, its default constructor is ALWAYS called and NOT the one with IHubContext as a parameter! Even if I use a factory to create the EventProcessor and call RegisterEventProcessorFactoryAsync() in Startup.cs, I can't get the IHubContext handle in the factory, because the call is not originating from a controller. It either originates from Startup.ConfigureServices() or a callback from whenever something happens in the EventHub, which is not a controller method. I'm really stuck, so any help would be much appreciated. Does anyone know the answer to this?

1

1 Answers

0
votes

You can add your Factory and processor to services

.ConfigureServices((hostContext, services) =>
{
    ...
    services.AddSingleton<IEventProcessorFactory, EventProcessorFactory>();
    services.AddSingleton<IEventProcessor, TwinChangesEventHandler>();
    ...
});
 public class EventProcessorFactory : IEventProcessorFactory
 {
     private readonly IEventProcessor _fluxEventProcessor;

     public EventProcessorFactory(IEventProcessor fluxEventProcessor)
     {
         _fluxEventProcessor = fluxEventProcessor;
     }

     public IEventProcessor CreateEventProcessor(PartitionContext context)
     {
         return _fluxEventProcessor;
     }
 }

Then in your handler you can have access to the injected hub

public class TwinChangesEventHandler : IEventProcessor
{
    private readonly IHubContext<MyHub> _myHubContext;

    public TwinChangesEventHandler(IHubContext<MyHub> myHubContext)
    {
        _myHubContext= myHubContext;
    }

    ...

    async Task IEventProcessor.ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
    {
        foreach (var eventData in messages)
        {
            await _myHubContext.Clients.All.SendAsync("Update", eventData);
        }

        //Call checkpoint every 5 minutes, so that worker can resume processing from 5 minutes back if it restarts.
        if (_checkpointStopWatch.Elapsed > TimeSpan.FromMinutes(5))
        {
            await context.CheckpointAsync();
            _checkpointStopWatch.Restart();
        }
    }
}