MediatR是否遍历项目中的所有类来寻找匹配项?

huangapple go评论63阅读模式
英文:

Does MediatR walk all classes in the project looking for matches?

问题

以下是翻译的部分:

问题1: 是否正确?

答: 是的,这是正确的。

问题2a: MediatR如何找到这个类?它没有传递给任何东西,也没有注册到任何地方。MediatR是否扫描所有类以寻找匹配项?

答: MediatR使用自动发现机制来查找处理程序类。它会扫描程序集中的所有类,以查找实现IRequestHandler<ExampleRequest, IResult>接口的类。这种自动发现使您无需手动注册处理程序类。

问题2b: 如果是这样,那么如果有两个匹配项会怎么样?

答: 如果有多个匹配项,MediatR将引发异常,因为它无法确定应该使用哪个处理程序类。因此,在应用程序中确保只有一个匹配项是很重要的。

问题2c: 如果是这样,是否有一种方法可以注册处理程序类以加快查找速度并避免重复匹配?

答: 是的,您可以使用依赖注入容器(如ASP.NET Core的内置DI容器)来注册处理程序类,以加速查找并确保只有一个匹配项。通过注册,您可以明确指定哪个处理程序类用于处理特定类型的请求。这可以提高应用程序的性能和可维护性。

英文:

There are two parts to this question. First I am going to explain what I think is happening? And then second, in that explanation, I want to verify how it is finding a class it needs.

This is from Nick Chapsas' program Write cleaner APIs in .NET 7 with MediatR.

This code handles a request using MediatR as follows.

n program.cs it has:

app.MediateGet&lt;ExampleRequest&gt;(&quot;example/{name}&quot;);

which is called via the extension function:

public static WebApplication MediateGet&lt;TRequest&gt;(
    this WebApplication app,
    string template) where TRequest : IHttpRequest
{
    app.MapGet(template, async (IMediator mediator,
        [AsParameters] TRequest request) =&gt; await mediator.Send(request));
    return app;
}

where IHttpRequest is defined as:

public interface IHttpRequest : IRequest&lt;IResult&gt;
{
}

So what has occurred from all this is me have an app.MapGet() call for the url "example/{name}" and it will be handles by MediatR.

ExampleRequest.cs is a POCO containing the URL parameters, etc.

The handler must implement the interface IRequestHandler<ExampleRequest, IResult>. When that url is requested, it will instantiate the appropiate class and call its Handle() method passing in the ExampleRequest and getting a Task<IResult> returned.

Question 1: Is that correct?

There is the following class in the program that is a handler that implements the require interface. And it is called by MediatR.

public class ExampleHandler : IRequestHandler&lt;ExampleRequest, IResult&gt;
{
    private readonly GuidService _guidService;

    public ExampleHandler(GuidService guidService)
    {
        _guidService = guidService;
    }

    public async Task&lt;IResult&gt; Handle(
        ExampleRequest request, CancellationToken cancellationToken)
    {
        await Task.Delay(10, cancellationToken);
        return Results.Ok(new
        {
            message = $&quot;The age was: {request.Age} and the name was: {request.Name}&quot;,
            requestGuid = request.GuidService.Id,
            ctorGuid = _guidService.Id
        });
    }
}

Question 2a: How does MediatR find this class? It is not passed to anything or registered with anything. Does MediatR scan all classes looking for a match?

Question 2b: And if so, what if there are two matches?

Question 2c: Also if so, is there a way to register handler classes to speed up finding them and avoid duplicate matches?

答案1

得分: 1

1. 有效地是的。这个想法是将各个端点操作与负责的请求/响应处理程序相关联,一个具体的实现类可能会实现一个或多个这样的处理程序;端点被抽象出来,只需要知道它自己所需的输入和输出对,解析由MediatR处理。

2a. 反射和程序集扫描。注册过程要求扫描程序集,MediatR库将定位并尝试注册满足其接口的类。

2b. 哪个优先级更高取决于你如何注册它们,但对于给定类型,MediatR只会解析一个IRequestHandler。程序集扫描器将注册第一个找到的处理程序,并会跳过找到的任何其他处理程序。如果您手动注册多个处理程序,它将使用最后注册的处理程序。

2c. 是的。您不必使用自动的程序集扫描通过注册扩展来注册MediatR;您可以手动注册IMediator、ISender和IPublisher的实现,然后手动将所有各种处理程序选择性地注册到IoC容器中。

英文:

1. Effectively, yes. The idea is that you're tying individual endpoint operations to a responsible request/response handler, for which a concrete implementation class may implement one or several; the endpoint is abstracted from that responsibility and just needs to know about it's own required input and output pair, resolution is handled by MediatR.

2a. Reflection and assembly scanning. The registration process asks for assemblies to scan, and the MediatR library will locate and attempt to register classes that fulfill its interfaces

https://github.com/jbogard/MediatR/blob/master/src/MediatR/Registration/ServiceRegistrar.cs
> MediatR supports Microsoft.Extensions.DependencyInjection.Abstractions
> directly. To register various MediatR services and handlers:
>
> services.AddMediatR(cfg =>
> cfg.RegisterServicesFromAssemblyContaining<Startup>()); or with an
> assembly:
>
> services.AddMediatR(cfg =>
> cfg.RegisterServicesFromAssembly(typeof(Startup).Assembly));
>
> This registers:
>
> - IMediator as transient
> - ISender as transient
> - IPublisher as transient
> - IRequestHandler<,> concrete implementations as transient
> - IRequestHandler<> concrete implementations as transient
> - INotificationHandler<> concrete implementations as transient
> - IStreamRequestHandler<> concrete implementations as transient
> - IRequestPreProcessor<> concrete implementations as transient
> - IRequestPostProcessor<,> concrete implementations as transient
> - IRequestExceptionHandler<,,> concrete implementations as transient
> - IRequestExceptionAction<,>) concrete implementations as transient
>
> This also registers open generic implementations for:
>
> - INotificationHandler<>
> - IRequestPreProcessor<>
> - IRequestPostProcessor<,>
> - IRequestExceptionHandler<,,>
> - IRequestExceptionAction<,>

2b. Which takes precedence depends on how you register them, but MediatR will only resolve one IRequestHandler for a given type. The assembly scanner will register the first located handler and will skip any additional ones it finds. If you manually register multiple, it will use the last registered.

2c. Yes. You do not have to use the automated assembly scanning via the registration extensions to register MediatR; you can manually register the implementations of IMediator, ISender, and IPublisher yourself, and then selectively register all of your various handlers manually into the IoC container.

huangapple
  • 本文由 发表于 2023年2月18日 07:25:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/75490088.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定