6

I have a slightly modified version of Mediatr handing command processing in my application. I have implemented a MediatorPipeline that allows me to have pre and post processors.

public class AsyncMediatorPipeline<TRequest, TResponse> 
    : IAsyncRequestHandler<TRequest, TResponse> 
    where TRequest : IAsyncRequest<TResponse>
{
    private readonly IAsyncRequestHandler<TRequest, TResponse> inner;
    private readonly IAsyncPreRequestHandler<TRequest>[] preRequestHandlers;
    private readonly IAsyncPostRequestHandler<TRequest,TResponse>[] postRequestHandlers;

    public AsyncMediatorPipeline(IAsyncRequestHandler<TRequest, TResponse> inner, 
        IAsyncPreRequestHandler<TRequest>[] preRequestHandlers, 
        IAsyncPostRequestHandler<TRequest, TResponse>[] postRequestHandlers)
    {
        this.inner = inner;
        this.preRequestHandlers = preRequestHandlers;
        this.postRequestHandlers = postRequestHandlers;
    }

    public async Task<TResponse> Handle(TRequest message)
    {
        foreach (var preRequestHandler in preRequestHandlers)
        {
            await preRequestHandler.Handle(message);
        }

        var result = await inner.Handle(message);

        foreach (var postRequestHandler in postRequestHandlers)
        {
            await postRequestHandler.Handle(message, result);
        }

        return result;
    }
}

I am registering my pre-processors with autofac like so:

builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
    .As(type => type.GetInterfaces()
        .Where(type => type.IsClosedTypeOf(typeof(IAsyncPreRequestHandler<>))))
    .InstancePerLifetimeScope();

At runtime I am getting duplicate preprcessors. I have to filter the set removing duplicates. I am not sure why this is happening. If i comment out the registration, I do not get any preprocessors, which indicates that I am not duplicating the registration somewhere else.

Update: Here are some more details on the type that appears to be getting registered twice. The various class definitions:

The concrete handler

public class ClientEditorFormIdentifierValidationHandler 
: IAsyncPreRequestHandler<AddOrEditClientCommand>{}

The command class

public class AddOrEditClientCommand 
: IAsyncRequest<ICommandResult>{}

The command interface

public interface IAsyncRequest<out TResponse> { }
NotMyself
  • 29,209
  • 17
  • 56
  • 74
  • Are you using `.AsImplementedInterfaces()` somewhere ? or `AppDomain.CurrentDomain.GetAssemblies()` ? If you add your registration before `builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies()).AsImplementedInterfaces()` the CLR will have your assembly loaded and you will have 2 registrations. If you comment your registration the CLR won't load your assembly and you won't have any registration. `GetAssemblies` will only returns Assembly that has beeen loaded by the CLR – Cyril Durand Mar 10 '15 at 10:00
  • I do not think it is being registered twice. If I comment out the registration above, the type does not resolve at all. I get the impression that this registration is actually registering the type twice, but I am not familiar enough with autofac to figure out why or how. – NotMyself Mar 10 '15 at 15:31
  • I can't see any reason why the registration is done twice. Do you use `AppDomain.CurrentDomain.GetAssemblies()` ? Are you sure your assembly is loaded when you register your type ? – Cyril Durand Mar 10 '15 at 16:27
  • Hi @CyrilDurand, I added some more details about the specific types that are getting duplicated. I am not using the GetAssemblies() method anywhere in the solution. – NotMyself Mar 10 '15 at 17:03
  • Unfortunately I am unable to reproduce the issue. I think I have the same code as yours but I have the registration only once (except with `AsImplementedInterfaces` which give me 2 registrations). If you look at `container.ComponentRegistry.RegistrationsFor(new TypedService(typeof(IAsyncPreRequestHandler)));` you should have 2 results and you may find additional information. – Cyril Durand Mar 10 '15 at 23:35
  • @CyrilDurand Ill see if I can pull out a functioning example of my problem and post it up to github sometime today. – NotMyself Mar 11 '15 at 16:18
  • @CyrilDurand I was able to figure it out by trying to recreate the issue to show you. Thanks for rubber ducky-ing for me. – NotMyself Mar 11 '15 at 17:47

1 Answers1

4

After extensive troubleshooting, I discovered that I was in fact registering my handlers twice. I like to use Autofac Modules to breakup the configuration of my container into manageable chunks.

In my MVC5 Startup class I register my modules like so:

builder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());

Buried deep within an "InfrastructureModule" class was the line:

builder.RegisterModule<MediatorModule>();

Which was of course reregistering my mediator handlers... DUH..

NotMyself
  • 29,209
  • 17
  • 56
  • 74
  • I had a very similar experience (including the "duh" moment : ). My notification handlers were being called twice. That's because they were registered twice. It's quite easy to accidentally register them twice using the `builder.RegisterAssemblyTypes(typeof(MyType).Assembly).AsImplementedInterfaces...` approach, because of course, your assembly contains many classes, and therefore many things you could substitute for `MyType`. https://github.com/jbogard/MediatR/issues/501 – OutstandingBill Mar 04 '20 at 22:15