Home > Back-end >  Dependency injection in an event
Dependency injection in an event

Time:10-09

We have a .NET Core application that uses dependency injection heavily. Within our class we have a raised event, however, in this event we want to make use of one of the instances of an DI object. This however doesn't exist, which is understandable.

How can we make use of this instance from within the event?

public class GetSQLDependancyHandler : IRequestHandler<SQLDependancyQuery>
{
    private readonly ISqlDependancy _sqlDependancy;
    private readonly IMapper _autoMapper;
    private readonly IMediator _mediator;
    private  CancellationToken _cancellationToken;

    public GetSQLDependancyHandler( IMapper autoMapper, 
        ISqlDependancy sqlDependancy,
        IMediator mediator)
    {
        _autoMapper = autoMapper;
        _sqlDependancy = sqlDependancy;
        _mediator = mediator;
    }

    public async Task<Unit> Handle(SQLDependancyQuery request, CancellationToken cancellationToken)
    {
       await _sqlDependancy.IngnightSQLDependancy("ObservationAdmission", "ServiceBroker");
        _sqlDependancy.OnTableUpdate  = _sqlDependancy_OnTableUpdate1;
        _cancellationToken = cancellationToken;

        return Unit.Value;
    }

    private void _sqlDependancy_OnTableUpdate1(object sender, BroadCast e)
    {
        // THIS IS THE PART THAT DOESN'T EXIST
        _mediator.Publish(new SQLDependancyDTO { Id = 1,  Date = DateTime.Now, Message = "testmessage" }, _cancellationToken);
    }
}

Any advice or where I should be looking would be greatly appreciated.

CodePudding user response:

The problem is most likely the lifetime of _mediator: The OnTableUpdate event may fire long after whatever uses GetSQLDependancyHandler has completed and the object got cleaned up.

The common solution is injecting an IServiceScopeFactory object (which is a singleton), which you can then use in your event handler:

private void _sqlDependancy_OnTableUpdate1(object sender, BroadCast e)
{
    using var scope = serviceScopeFactory.CreateScope();
    var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
    mediator.Publish(new SQLDependancyDTO { Id = 1,  Date = DateTime.Now, Message = "testmessage" }, _cancellationToken);
}

In any case, subscribing to an event of an injected object while being in a handler is probably unsafe: If the _sqlDependancy object is ever reused, the event handler subscription stays and may surprisingly be executed again in the future.

CodePudding user response:

Not sure if this addresses the problem, but you could try capturing the dependency in a closure when subscribing.

public async Task<Unit> Handle(SQLDependancyQuery request, CancellationToken cancellationToken)
{
   await _sqlDependancy.IngnightSQLDependancy("ObservationAdmission", "ServiceBroker");
    _sqlDependancy.OnTableUpdate  = (s,e) => _sqlDependancy_OnTableUpdate1(s,e,_mediator);
    _cancellationToken = cancellationToken;

    return Unit.Value;
}

private void _sqlDependancy_OnTableUpdate1(object sender, BroadCast e, IMediator mediator)
{
    mediator.Publish(new SQLDependancyDTO { Id = 1,  Date = DateTime.Now, Message = "testmessage" }, _cancellationToken);
}
  • Related