-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
v12.3.0 Breaking Change #1038
Comments
I think the problem might be with the assemblies you are passing to mediatR for registration. MediatR uses those assemblies to scan for types. I think when you use var assemblies = new Assembly[]
{
typeof(Request1).Assembly,
typeof(Request2).Assembly
}; That's just my initial thought... I will mess around with this some more to see if I can reproduce this issue on my end. |
I am creating a test project to test out your code to see if I can reproduce the error. So far I have not been successful. The application seems to run fine with the way you are retrieving assemblies to pass to MediatR and the way that I am explicitly setting those assemblies. Can you provide some more detail perhaps?
Thanks. |
SDK version: 8.0.302 Definitions example: public static class Create
{
public class Command : IRequest<Result<Unit>>
{
public required int foo { get; set; }
}
public class Handler : IRequestHandler<Command, Result<Unit>>
{
private readonly IConfiguration _config;
private readonly DataContext _context;
private readonly ILogger<Handler> _logger;
private readonly IMediator _mediator;
public Handler(
IConfiguration config,
DataContext context,
ILogger<Handler> logger,
IMediator mediator
)
{
_config = config;
_context = context;
_logger = logger;
_mediator = mediator;
}
public async Task<Result<Unit>> Handle(Command request, CancellationToken cancellationToken)
{
// endpoint logic
}
}
} |
hmm.. well.. I tested your exact code and I can't seem to reproduce the issue on my end. Are there any other details that could be helpful? Anything that you have in your code that I could be missing or important to the issue? |
I'm looking into the code, it's a large codebase that I recently inherited so it's possible. While googling I found this old MediatR issue that seems to be the same problem, and it's had some activity in the last few weeks: #674. It could be the Handler registrations, which occur directly after the AddMediatR call. My predecessor stopped adding these at some point, for whatever reason, so I didn't add them either and it worked fine so far with only about 25% of the Handlers being registered like this. Handler registrations: _ = services.AddTransient<IRequestHandler<Create<Foo, Bar, FooBar>.Command, Result<Unit>>, Create<Foo, Bar, FooBar>.Handler>();
_ = services.AddTransient<IRequestHandler<Read<Foo, Bar, FooBar>.Query, Result<List<FooBar>>>, Read<Foo, Bar, FooBar>.Handler>();
_ = services.AddTransient<IRequestHandler<Update<Foo, Bar, FooBar, FooFooBarBar>.Command, Result<Unit>>, Update<Foo, Bar, FooBar, FooFooBarBar>.Handler>();
_ = services.AddTransient<IRequestHandler<Delete<Foo, Bar>.Command, Result<Unit>>, Delete<Foo, Bar>.Handler>(); Edit: Pretty sure it's not that because these come after anyway. |
yeah those are the same error but probably not the same issue entirely.. The error of arity is suggesting that Mediator is attempting to register a dependency like so: services.AddTransient(typeof(IRequestHandler<,>), typeof(ConcreteRequestHandler<,,>)); this will not work since the arity (number of generic type arguments) do not match. I must admit.. I've never seen MediatR used like this before.. But the above code does seem to be trying to register generic commands and handlers. I think those service registrations is what the last update was intended to alleviate. It appears that the registrations are concrete registrations for generic request handlers, correct? Are the Maybe it would help if I had some of these examples too. haha. |
Ok I was able to reproduce the issue.. I added some generic type parameters to the static class. public static class Create<T, T1, T2>
{
public class Command : IRequest<Result<Unit>>
{
public required int Foo { get; set; }
}
public class Handler : IRequestHandler<Command, Result<Unit>>
{
private readonly IConfiguration _config;
private readonly DataContext _context;
private readonly ILogger<Handler> _logger;
private readonly IMediator _mediator;
public Handler(
IConfiguration config,
DataContext context,
ILogger<Handler> logger,
IMediator mediator
)
{
_config = config;
_context = context;
_logger = logger;
_mediator = mediator;
}
public Task<Result<Unit>> Handle(Command request, CancellationToken cancellationToken)
{
return Task.FromResult(new Result<Unit>());
}
}
} I then ran the code as is, and I was able to get the arity error like above. I then downgraded to the previous version. The code ran but also did not register the handler. I then registered the handler concretely like so: builder.Services.AddTransient<IRequestHandler<Create<Foo, Bar, FooBar>.Command, Result<Unit>>, Create<Foo, Bar, FooBar>.Handler>(); Then the code worked again and the handler was indeed found. Also, yes there doesn't need to be that many assemblies for MediatR to scan through. though it didn't seem to matter either way when testing this specific issue but it could speed up initialization for your app. Mediator scans the assemblies passed to it for mediator registrations. So by providing more assemblies than needed you are adding extra work. So in summary the issue is that in the previous version MediatR, it would not even attempt to register generic commands and queries so you had to explicitly register them like your example above. With that said, I think there should be a check to make sure that MediatR isn't trying to register generic abstractions to concrete implementations when the arity does not match. So that is a bug that will need to be fixed. A workaround for you might be to essentially turn off that feature by providing a type evaluator like so: builder.Services.AddMediatR(config => {
config.TypeEvaluator = x => !x.ContainsGenericParameters;
config.RegisterServicesFromAssemblies(assemblies);
}); This will tell MediatR to not attempt to register types that have generic parameters. Or you can simply roll back to the previous version. In the meantime I will be working on a fix for this bug. Thanks. |
Really appreciate your help. That probably explains why the app is so deathly slow to build as well. I might suggest adding a warning if that check is triggered, because it could be an indicator of a bad configuration like mine. If the issue is a mismatch between arity of the concrete handler and the IRequestHandler, could I maybe be more specific about the type parameters of IRequestHandler? |
Well.. The real issue in why your code is not working has to deal more with the new code that I added. The code attempts to find all types to close your generic request, for example |
For reasons beyond my understanding, I'm no longer getting the exception now that I'm specifying the assembly. But it doesn't register the generic handlers, they have to be done separately as before. |
I would think you must have rolled back the MediatR version or you must have added the type evaluator lambda so that MedaitR does not try and register the generic handlers. Because as of right now, trying to register generic commands and handlers with more than one type parameter via AddMediatR assembly scanning results in the exception. |
Still on 12.3.0, only thing I changed was went from Assembly[] assemblies = Assembly.GetEntryAssembly()!.GetReferencedAssemblies().Select(Assembly.Load).Append(Assembly.GetCallingAssembly()).ToArray(); to Assembly[] assemblies = [typeof(Application.Consent.Read).Assembly]; |
After updating from 12.2.0 to 12.3.0, I'm getting a runtime exception during app instantiation.
The code:
The exception:
Not too sure how to fix this unfortunately. I don't have any generic handlers (that I know of at least) and I didn't change anything else.
The text was updated successfully, but these errors were encountered: