modular-monolith-with-ddd
modular-monolith-with-ddd copied to clipboard
UnitOfWorkCommandHandlerDecorator in UserAccess Module Doesn't Get Called.
Hello Kamil,
I thought I have figured the project architecture from end to end and decided to try it out on a side project. I am almost sure I followed your example thoroughly and didn't miss out anything. But when I tested it by trying out the RegisterUser
endpoint, It returns 200 but the user isn't found at least in the database.
I tried to step through the process and realized that all through the process of the step-through, UnitOfWorkCommandHandlerDecorator
and ValidationCommandHandlerDecorator
were never called. When this line from CommandsExecutor.cs
runs - return await mediator.Send(command);
, Dispose()
of SqlConnectionFactory.cs
gets called next. I don't know why this happens.. At some point, the debug was stuck in between Quartz and SerilogLogProvider. I don't know what I'm missing, and I've been on this for days.
I was hoping you would point me to the right direction because my frustration is building up.
Please help.
Hello @kgrzybek I am still struggling with this challenge. I am in dire need of some assistance.
Hi @kacey90
I checked my solution and it works - you can check this by running integration test: RegisterNewUserCommand_Test
I don't see your code so it is hard to give you an answer but I can guess that your decorators are not registered correctly. Remember, that if you have
- commands without result (inherits from
CommandBase
) - commands with the result (inherits from
CommandBase<TResult>
)
you must create and register two sets of decorators for each of them. Maybe this is the issue?
In fact, I wonder whether to give up the command without result in the future and always return some kind of result for all commands.
Hi @kgrzybek ,
Thanks for your response. I have both decorators created and registered. But I am currently doing comparative checks with your code base to see if I'm missing something. My last resort may be to make a fork of your project and refactor it to my specifications.
Based on your suggestion on the command decorators, we may ditch the one without the "Result" since it's mostly unused throughout the project.
@kacey90 I had a similar problem with the decorator and in my situation, there are a couple of problems.
The first problem is related to missing registrations of command handlers which are implements ICommandHandler<>. Thereby, MediatR resolved the IRequestHandler<> service from the container and my handlers were skipped.
Another problem was in registering the decorator itself. You no need to set serviceType as typeof(ICommandHandler<>)
, just change it to the typeof(IRequestHandler<>)
.
e.g.
builder.RegisterGenericDecorator(typeof(UnitOfWorkCommandHandlerDecorator<>), typeof(IRequestHandler<>));
That new behavior with decorator registering was introduced in the Autofac starting from the v5.
Kamil's infrastructure project uses Autofac v4.9.2 where we have no such problems in registration.
See details here
cc @kgrzybek FYI
This work with Autofac v6.1 See details builder.RegisterGenericDecorator( typeof(UnitOfWorkCommandHandlerWithResultDecorator<,>), typeof(ICommandHandler<,>), context => !context.AppliedDecorators.Any());
Hi, I'm trying to decorate IRequestHandler <TCommand>, but it doesn't work (without result). The LoggingDecorator and DiagnosticDecorator decorators are never invoked
I have no problem decorating IRequestHandler <TCommand, TResult> (with result)
TargetFramework net5.0 Autofac 6.1.0 MediatR 9.0.0 MediatR.Extensions.Autofac 0.6.0 MediatR.Extensions.Autofac.DependencyInjection 7.1.0
` class Program { static IContainer container;
static async Task Main(string[] args)
{
await Setup();
using (var scope = container.BeginLifetimeScope())
{
var mediatr = scope.Resolve<IMediator>();
await mediatr.Send(new CreatePersonCommand() { x = 1, y = 2 });
}
}
public static async Task Setup()
{
var builder = new ContainerBuilder();
builder.RegisterMediatR(typeof(Program).Assembly);
builder.RegisterGenericDecorator(typeof(DiagnosticDecorator<>), typeof(IRequestHandler<>));
builder.RegisterGenericDecorator(typeof(LoggingDecorator<>), typeof(IRequestHandler<>));
container = builder.Build();
}
}
public class LoggingDecorator<TCommand> : IRequestHandler<TCommand>
where TCommand : IRequest
{
private readonly IRequestHandler<TCommand> commandHandler;
public LoggingDecorator(IRequestHandler<TCommand> commandHandler)
{
this.commandHandler = commandHandler;
}
public async Task<Unit> Handle(TCommand request, CancellationToken cancellationToken)
{
Console.WriteLine("executing...");
return await this.commandHandler.Handle(request, cancellationToken);
}
}
public class DiagnosticDecorator<TCommand> : IRequestHandler<TCommand>
where TCommand : IRequest
{
private readonly IRequestHandler<TCommand> commandHandler;
public DiagnosticDecorator(IRequestHandler<TCommand> commandHandler)
{
this.commandHandler = commandHandler;
}
public async Task<Unit> Handle(TCommand request, CancellationToken cancellationToken)
{
var r = await commandHandler.Handle(request, cancellationToken);
return r;
}
}
public class CreatePersonCommand : IRequest
{
public int x { get; set; }
public int y { get; set; }
}
public class CreatePersonCommandHandler : IRequestHandler<CreatePersonCommand>
{
public async Task<Unit> Handle(CreatePersonCommand request, CancellationToken cancellationToken)
{
return Unit.Value;
}
}
`
also try registering the decorators like this, but it doesn't work
builder.RegisterGenericDecorator(typeof(DiagnosticDecorator<>), typeof(IRequestHandler<>), context=> !context.AppliedDecorators.Any()); builder.RegisterGenericDecorator(typeof(LoggingDecorator<>), typeof(IRequestHandler<>), context =>!context.AppliedDecorators.Any());
thanks for your help
@ghuarcayam downgrade autofac version thesame with project currenly using.
I've managed to do it like this (Autofac 6.2.0):
builder.RegisterGenericDecorator(
typeof(UnitOfWorkCommandHandlerDecorator<>),
typeof(IRequestHandler<>),
context => context.ImplementationType.FullName.EndsWith("CommandHandler"));
builder.RegisterGenericDecorator(
typeof(UnitOfWorkCommandHandlerWithResultDecorator<,>),
typeof(IRequestHandler<,>),
context => context.ImplementationType.FullName.EndsWith("CommandHandler"));