-
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
Question: How to register generic requests #1041
Comments
Well. My initial thought without being able to test out your class definitions are that you are declaring the handlers as internal and then trying to add mediatr from an assembly that doesn't have visibility to internals. The fix to this would be to change the internal visibility or to make internals visible to the other calling assembly. I don't know if this is the exact cause or not. I will confirm this soon. But, this is my initial thought.
|
Yes I do believe the issue with your handlers is that you are declaring the handler classes as internal. I am guessing you are calling You will need to update the handler's access modifier to allow other assemblies to see it. Here is more info. Another option is to make those internals visible to another assembly. You can do this by adding this to the library you want to make visible. [assembly: InternalsVisibleTo("NameOfAssemblyYouWantToMakeLibraryVisibleTo")] |
No sir this is not the issue. The assembly that contains the internal handlers is responsible for registering mediatr and has access to them. The same approach is applied for non-generic requests and handlers. That means public requests and internal handlers but those are registered successfully and it's working |
So I can see that your sample registers handlers in the assembly that
contains the BaseDto class. Are you saying that the base dto assembly has
access to the internals of the assembly that contains the handlers? Are
your handlers in the same assembly as the BaseDto type? Maybe it would help
me understand more if you shared your project architecture and structure
and note which classes are in what assembly.
…On Sat, Jun 22, 2024, 1:35 PM rezathecoder ***@***.***> wrote:
Yes I do believe the issue with your handlers is that you are declaring
the handler classes as internal. I am guessing you are calling AddMediatR
from your .net core presentation layer project, such as, mvc, or blazor, or
razor pages, etc... Probably from the Program.cs class. The issue is that
your presentation layer, being in a separate assembly cannot see the
internal handler when doing the assembly scanning and therefore never
registers those handlers.
You will need to update the handler's access modifier to allow other
assemblies to see it. Here
<https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers>
is more info.
Another option is to make those internals visible to another assembly. You
can do this by adding this to the library you want to make visible.
[assembly: InternalsVisibleTo("NameOfAssemblyYouWantToMakeLibraryVisibleTo")]
No sir this is not the issue. The assembly that contains the internal
handlers is responsible for registering mediatr and has access to them. The
same principles is done for non-generic requests and handlers. That means
public requests and internal handlers but those are registered successfully
and it's working
—
Reply to this email directly, view it on GitHub
<#1041 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACL2QUS5LQVLXMMINVLXMZTZIXNZFAVCNFSM6AAAAABJNYPNIKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBUGE4DCMRUGU>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Yes the public static void RegisterApplicationLayer(this IServiceCollection services) {
services.AddMediatR(opts => {
opts.RegisterServicesFromAssemblyContaining<BaseDto>();
});
} Then in program.cs file in Api layer i simply call: builder.Services.RegisterApplicationLayer(); Non-generic requests and handlers are registered fine but the generics not |
Hmm.. Ok.. So if what you say is accurate then I have no idea why the handlers are not being registered. In my testcase for this specific issue I created a class in a separate project to be used as your "ApplicationLayer" example. public class BaseEntity
{
public int Id { get; set; }
}
public class Entity : BaseEntity
{
}
public record GetByIdQuery<TEntity>(int Id) : IRequest<string>
where TEntity : BaseEntity;
internal sealed class GetByIdQueryHandler<TEntity> : IRequestHandler<GetByIdQuery<TEntity>, string>
where TEntity : BaseEntity
{
public Task<string> Handle(GetByIdQuery<TEntity> request, CancellationToken cancellationToken)
{
return Task.FromResult(request.Id.ToString());
}
}
public static class Registration
{
public static IServiceCollection RegisterApplicationLayer(this IServiceCollection services)
{
return services.AddMediatR(opts => opts.RegisterServicesFromAssemblyContaining<BaseEntity>());
}
} This contains the Lastly I simply call the extension method from my Program.cs file in my presentation layer: builder.Services.RegisterApplicationLayer(); In my presentation layer I then call the mediatR request in an action method on a controller like so: public async Task<IActionResult> Index()
{
var vm = new HomeViewModel
{
IdValue = await _mediator.Send(new GetByIdQuery<Entity>(1))
};
return View(vm);
} The result is successful and the handler is registered. The view shows the input id that is stored on the view model. So I'm really not sure what else could be different between my test and your issue? It seems to work as designed on my end. |
@rezathecoder is this still an issue? Did you ever get to the bottom of this? |
I had the same problem. It looks like if the generic parameter is in a different assembly, you need to add this assembly during the registration:
|
Today i had time and debugged into MediatR code and reached the exact same solution and wanted to share it with others but you mentioned it earlier 😆😆😆
This tries to get all possible types for registering the handler based on the constraints. In my case my matching types are my entities that are present in the Domain layer and |
Yes you must pass in your domain layer assembly
…On Sat, Aug 24, 2024, 7:56 AM rezathecoder ***@***.***> wrote:
I had the same problem. It looks like if the generic parameter is in a
different assembly, you need to add this assembly during the registration:
configuration.RegisterServicesFromAssemblies(typeof(Request<>).Assembly,
typeof(Entity).Assembly)
Today i had time and debugged into MediatR code and reached the exact same
solution and wanted to share it with others but you mentioned it earlier
😆😆😆
Anyway. To complete your solution the code that causes this problem is
this line:
https://github.com/jbogard/MediatR/blob/cac76bee59a0f61c99554d76d4c39d67810fb406/src/MediatR/Registration/ServiceRegistrar.cs#L236
https://github.com/jbogard/MediatR/blob/cac76bee59a0f61c99554d76d4c39d67810fb406/src/MediatR/Registration/ServiceRegistrar.cs#L237
This tries to get all possible types for registering the handler based on
the constraints. In my case my matching types are my entities that are
present in the Domain layer and assembliesToScan will not search for them.
This should be mentioned in the document
@zachpainter77 <https://github.com/zachpainter77>
—
Reply to this email directly, view it on GitHub
<#1041 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACL2QUVWG6JWSNI3CZURPD3ZTCNKDAVCNFSM6AAAAABJNYPNIKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMBYGQZDCNRYG4>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Can anyone help me, this is not working, even the above code. I even got all the assemblies of the solution and pass in them all, it still didn't help |
i have a similar issue and the above code did not solve it either even when passing both assemblies Service Registration services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssemblies(typeof(ApplicationAssemblyReference).Assembly, typeof(DomainAssemblyReference).Assembly);
cfg.AddOpenBehavior(typeof(LoggingBehavior<,>));
cfg.AddOpenBehavior(typeof(FluentValidationBehavior<,>));
}); Command: public record CreatePageCommand<TPage, TRequestDto>(TRequestDto Page, string ContextUsername)
: IRequest<Result<int>> where TPage : Page where TRequestDto : IPageRequest;
public class CreatePageCommandHandler<TPage, TRequestDto>(
IApplicationDbContext dbContext,
IPageValidationService<TPage, TRequestDto> pageValidationService)
: IRequestHandler<CreatePageCommand<TPage, TRequestDto>, Result<int>>
where TPage : Page
where TRequestDto : IPageRequest
{
public async Task<Result<int>> Handle(CreatePageCommand<TPage, TRequestDto> request, CancellationToken cancellationToken)
{
}
} the only time it works is when i register the different versions of the command individually. services.AddTransient<IRequestHandler<CreatePageCommand<DocumentPage, DocumentPageRequestDto>, Result<int>>, CreatePageCommandHandler<DocumentPage, DocumentPageRequestDto>>(); |
@lstsystems the latest release changed autoregistration of generic request handlers feature to OPT-IN.
Works like a charm :) |
@vs-savelich thanks that worked like a charm👍. One thing to note is that I initially registered each iteration of |
Hi
I have updated the MediatR package to version 12.3.0 to use the new feature for generic requests and handlers.
Is there any other change beside updating the package is needed to enable this feature?
I am registering my requests like this:
But i get the error showing that the container can not find the implementation for my generic handlers.
I have two types of generic requests. First the ones that return some data like string or dto like this:
And then the ones that return nothing like this:
None of the above types are registered automatically and i have to register them like this:
Please help me so i can register all of my generic requests at once.
@jbogard
@zachpainter77
The text was updated successfully, but these errors were encountered: