5

I'm facing a problem that Mediatr command handler is not called. I have the following solution structure.

Project.sln -> Application layer (.NET standard class library) -> Jobs (.NET standard class library) -> Job Server (.NET Core console app)

The idea is that Job Server uses scheduler (Quartz.NET) to execute Jobs. The actual business logic is in Application layer. Application layer uses CQRS pattern which is wired using Mediatr. I'm using Microsoft dependency injection libraries.

Job Server Main method (with DI code):

public class Program
{
    static ManualResetEvent _quitEvent = new ManualResetEvent(false);

    static void Main(string[] args)
    {
        Console.WriteLine("Job Server started");

        //DI setup
        var serviceProvider = new ServiceCollection()
            .AddQuartz()
            .AddTransient<InitializeJobServer>()
            .AddTransient<ProcessAdRssFeedsJob>()
            .AddScoped<IConfigService, ConfigService>()
            .AddScoped<IRssService, RssService>()
            .AddScoped<IBaseService, BaseService>()
            .AddMediatR(typeof(ProcessAdSectionsRssCommand).GetType().Assembly)
            .AddDbContext<MyDbContext>(options =>
                options.UseNpgsql("xxx"))
            .AddMemoryCache()
            .BuildServiceProvider();

        Console.CancelKeyPress += (sender, eArgs) => {
            _quitEvent.Set();
            eArgs.Cancel = true;
        };

        Task.Run(async () =>
        {
            await serviceProvider.GetService<InitializeJobServer>().Start();
        });

        _quitEvent.WaitOne();
        Console.WriteLine("Job Server ended");
    }
}

Code from Quartz.net job:

[DisallowConcurrentExecution]
public class ProcessAdRssFeedsJob : IJob
{
    private readonly IMediator _mediator;

    public ProcessAdRssFeedsJob(IMediator mediator)
    {
        _mediator = mediator;
    }

    public Task Execute(IJobExecutionContext context)
    {
        try
        {
            _mediator.Send(new ProcessAdSectionsRssCommand());               
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
        return null;
    }
}

Mediatr command:

public class ProcessAdSectionsRssCommand : IRequest<bool>
{

    public class Handler : IRequestHandler<ProcessAdSectionsRssCommand, bool>
    {
        private readonly MyDbContext _context;
        private readonly IRssService _rssService;
        private readonly IConfigService _configService;

        public Handler(
            MyDbContext context,
            IRssService rssService,
            IConfigService configService)
        {
            _context = context;
            _rssService = rssService;
            _configService = configService;
        }

        public async Task<bool> Handle(ProcessAdSectionsRssCommand request, CancellationToken cancellationToken)
        {
            var config = await _configService.GetAllConfigs();

            var r0 = await _rssService.GetAdSectionRssUrls();
            // etc.
            return true;
        }
    }
}

After debugging I've concluded that code stops executing after initializing ProcessAdSectionsRssCommand class (if I create an empty constructor, it will be executed). Unfortunately, I haven't got any actual error messages, I think some sort of exception might be swallowed. Handler class as far as I can tell never gets initialized.

  • Mediatr version: 6.0.0
  • .NET code SDK version: 2.2
  • Microsoft DI version (Microsoft.Extensions.DependencyInjection): 2.2.0

I suspect it's some sort of DI + Mediatr related issue. Anyone has any ideas? Thanks.

user3646017
  • 51
  • 1
  • 1
  • 5
  • [`IMediator.Send`](https://github.com/jbogard/MediatR/blob/8e0c349ff720dcf8d63cbb560d3718fd229076ae/src/MediatR/IMediator.cs#L19) returns a `Task`, so I'd suggest using the `async` keyword in your job `Execute` method definition and `await` the call to the `Send` method on your `_mediator`. It might be that the operation is not monitored anymore, hence the exception is not captured anywhere. – Mickaël Derriey Feb 27 '19 at 02:28
  • @MickaëlDerriey Thank you for the suggestion! After appying the suggested changes I ended up with exception `System.InvalidOperationException: Handler was not found for request of type MediatR.IRequestHandler 2[xxx.Application.Rss.Commands.ProcessAdSectionsRss.ProcessAdSectionsRssCommand,System.Boolean]. Register your handlers with the container. See the samples in GitHub for examples.` I guess, the question remains - how do I set up dependency injection to work in console application? Please note, in ASP.NET Core project this logic works. Also, I tried to remove all dependencies from handler – user3646017 Feb 27 '19 at 18:38
  • I think this tells us that either a) MediatR cannot even see the handler class, or b) there's a problem when MediatR tries to instantiate the handler. Could you try, just to be sure, to move the handler class out of the request class, so it's not a nested class anymore? Also, in your code sample, the handler has a dependency on `MyDbContext`, which is not registered in the container. Is it a typo or are you missing registrations? – Mickaël Derriey Feb 27 '19 at 20:06
  • I tried to move handler class outside request class. `MyDbContext` is the correct name (previously copy/paste issue), it's registered. I also removed all dependencies from handler's ctor. I tried also registering request/handler classes in DI. So far the same issue. – user3646017 Feb 28 '19 at 20:49
  • OK. If you debug the app and analyse the exception, the `InnerException`s might have more details about what's going wrong. – Mickaël Derriey Mar 01 '19 at 00:03
  • Maybe one of the handler dependencies - `MyDbContext`, `ConfigService` or `BaseService` - has dependencies that are not registered in the container? – Mickaël Derriey Mar 01 '19 at 00:05
  • Yes, I tried the things you mentioned. Unfortunately, without any success. I've set up simplified version of what I'm doing and the same issue can be observed (handler not found). You can check this [GitHub repo](https://github.com/t3hInox/MediatRQuartzConsoleApp). Am I missing something? – user3646017 Mar 02 '19 at 16:15
  • 4
    Ok, I finally managed to resolve this problem. It turned out that it was necessary to explicitly register handler in `ServiceCollection`. You can see how I did it in [this commit](https://github.com/t3hInox/MediatRQuartzConsoleApp/commit/df0d61f57e31f4886ab858e250f8682c499b7fea). @MickaëlDerriey thank you for your assistance! – user3646017 Mar 03 '19 at 09:48

1 Answers1

1

I think you are missing an await in while calling Send() method