Asp.net Core使用MediatR

1. 源码

1.1. 项目 MediatR.Extensions.Microsoft.DependencyInjection

    public static IServiceCollection AddMediatR(this IServiceCollection services, params Assembly[] assemblies)
        => services.AddMediatR(assemblies, configuration: null);
    public static IServiceCollection AddMediatR(this IServiceCollection services, IEnumerable<Assembly> assemblies, Action<MediatRServiceConfiguration>? configuration)
    {
        if (!assemblies.Any())
        {
            throw new ArgumentException("No assemblies found to scan. Supply at least one assembly to scan for handlers.");
        }
        var serviceConfig = new MediatRServiceConfiguration();
        configuration?.Invoke(serviceConfig);
        //注册项目默认服务
        ServiceRegistrar.AddRequiredServices(services, serviceConfig);
        //注册程序集相关接口继承类
        ServiceRegistrar.AddMediatRClasses(services, assemblies, serviceConfig);
        return services;
    }

This registers:

  • IMediator 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<,>

注册泛型

     var multiOpenInterfaces = new[]
        {
            typeof(INotificationHandler<>),
            typeof(IRequestPreProcessor<>),
            typeof(IRequestPostProcessor<,>),
            typeof(IRequestExceptionHandler<,,>),
            typeof(IRequestExceptionAction<,>)
        };
        foreach (var multiOpenInterface in multiOpenInterfaces)
        {
            var arity = multiOpenInterface.GetGenericArguments().Length;
            var concretions = assembliesToScan
                .SelectMany(a => a.DefinedTypes)
                .Where(type => type.FindInterfacesThatClose(multiOpenInterface).Any())
                .Where(type => type.IsConcrete() && type.IsOpenGeneric())
                .Where(type => type.GetGenericArguments().Length == arity)
                .Where(configuration.TypeEvaluator)
                .ToList();
            foreach (var type in concretions)
            {
                services.AddTransient(multiOpenInterface, type);
            }
        }

IsOpenGeneric 中调用 Type.IsGenericTypeDefinition 判断 是否为泛型

  typeof(List<>).IsGenericTypeDefinition  true
  typeof(List<>).IsGenericTypeDefinition  false
//定义委托
public delegate object ServiceFactory(Type serviceType);
    //委托扩展方法,factory 相当于 GetRequiredService
    public static class ServiceFactoryExtensions
    {
        public static T GetInstance<T>(this ServiceFactory factory)
            => (T) factory(typeof(T));
        public static IEnumerable<T> GetInstances<T>(this ServiceFactory factory)
            => (IEnumerable<T>) factory(typeof(IEnumerable<T>));
    }
//工厂方法,传入Microsoft.Extensions.DependencyInjection.IServiceCollection,在接下来的项目中作为解析实例工厂
services.TryAddTransient<ServiceFactory>(p => p.GetRequiredService);
//将IOC自带的GetRequiredService解析为ServiceFactory 委托实例
public static T GetRequiredService<T>(this IServiceProvider provider) where T : notnull;

The difference between GetService() and GetRequiredService() in ASP.NET Core GetRequiredService 找不到服务时会抛出异常,而GetService会返回null,建议采用GetRequiredService

RequestHandlerWrapperImpl

    public override Task<TResponse> Handle(IRequest<TResponse> request, CancellationToken cancellationToken,
        ServiceFactory serviceFactory)
    {
        Task<TResponse> Handler() => GetHandler<IRequestHandler<TRequest, TResponse>>(serviceFactory).Handle((TRequest) request, cancellationToken);
        //累加器嵌套调用
        return serviceFactory
            .GetInstances<IPipelineBehavior<TRequest, TResponse>>()
            .Reverse()
            .Aggregate((RequestHandlerDelegate<TResponse>) Handler, (next, pipeline) => () => pipeline.Handle((TRequest)request, cancellationToken, next))();
    }

NotificationHandlerWrapperImpl

public class NotificationHandlerWrapperImpl<TNotification> : NotificationHandlerWrapper
    where TNotification : INotification
{
    public override Task Handle(INotification notification, CancellationToken cancellationToken, ServiceFactory serviceFactory,
        Func<IEnumerable<Func<INotification, CancellationToken, Task>>, INotification, CancellationToken, Task> publish)
    {
        //linq select 来遍历通知
        var handlers = serviceFactory
            .GetInstances<INotificationHandler<TNotification>>()
            .Select(x => new Func<INotification, CancellationToken, Task>((theNotification, theToken) => x.Handle((TNotification)theNotification, theToken)));
        return publish(handlers, notification, cancellationToken);
    }
}

2. 总结

扩展按一定的顺序注册程序集中接口继承,再根据request type 反射 相关WrapperImplWrapper解析接口,嵌套或遍历执行

IPipelineBehavior 解析 之前注册的 RequestPreProcessorBehaviorRequestPostProcessorBehavior,而这两者的构造函数均解析了一组IRequestPreProcessorIRequestPostProcessor,利用上面的累加器嵌套和 next.Handle 执行的位置决定 pre 会在 IRequestHandler前执行,而 post 则在其之后执行,而非泛型会在泛型之前,这则由扩展注册的顺序(AddMediatRClasses)决定。

调用的顺序:

  Send
    根据type构造RequestHandlerWrapperImpl
      RequestHandlerWrapperImpl.Handle 解析 IPipelineBehavior
        IPipelineBehavior解析一组Processor,并在内部Handle方法中利用**累加器**迭代执行Processor.process
  本质上是通过IOC解析和累加器嵌套实现解耦
  publish
    NotificationHandlerWrapperImpl
      INotificationHandler
        利用linq Select 遍历执行(通知)INotificationHandler

3. 知识点

3.1. Array转化为IEnumerable

params Assembly[] assemblies 可以转化为 IEnumerable<Assembly> assemblies,因为Array继承了IEnumerable

In the .NET Framework version 2.0, the Array class implements the System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>, and System.Collections.Generic.IEnumerable<T> generic interfaces.

3.2. linq Aggregate 累加器

using System;
using System.Linq;
namespace LINQDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] intNumbers = { 3, 5, 7, 9 };
            int result = intNumbers.Aggregate(2, (n1, n2) => n1 * n2);
            Console.WriteLine(result);
            Console.ReadKey();
        }
    }

步骤1:首先乘以(2*3)得到结果6
步骤2:步骤1的结果,即6乘以5得到结果30
步骤 3:步骤 2 的结果,即 30,然后乘以 7,得到结果 210。
步骤4:将步骤3的结果,即210乘以9,得到最终结果1890。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值