注册 Mediatr IPipelineBehavior 的多个实现时了解 Asp.net Core 依赖注入 [英] Understanding Asp.net Core Dependency Injection when registering multiple implementations of Mediatr IPipelineBehavior

查看:25
本文介绍了注册 Mediatr IPipelineBehavior 的多个实现时了解 Asp.net Core 依赖注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到以下代码使用 Asp.Net Core 3.1 和 Mediatr,使用 IPipelineBehavior.

I saw the following code using Asp.Net Core 3.1 with Mediatr using IPipelineBehavior.

启动

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPerformanceBehaviour<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestValidationBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>));

RequestValidationBehavior

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FluentValidation;
using MediatR;
using ValidationException = CleanArchitecture.Application.Common.Exceptions.ValidationException;

public class RequestValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public RequestValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
    {
        _validators = validators;
    }

    public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
    {
        if (_validators.Any())
        {
            var context = new ValidationContext(request);

            var failures = _validators
                .Select(v => v.Validate(context))
                .SelectMany(result => result.Errors)
                .Where(f => f != null)
                .ToList();

            if (failures.Count != 0)
            {
                throw new ValidationException(failures);
            }
        }

        return next();
    }
}

但是,根据我对 asp.net DI 的有限理解,_validators 不应该是 IValidator 类型吗?为什么它是 IEnumerable> 类型?

However, Based on my limited understanding of asp.net DI, shouldn't _validators be of type IValidator<TRequest>? Why is it of type IEnumerable<IValidator<TRequest>>?

运行代码时,_validators 的长度总是 = 1.

When running the code, _validators is always of length = 1.

在哪里可以找到有关 DI 何时将实现解析为 IEnumerable 的更多文档?

Where can I find more documentation on when the DI will resolve an implementation to IEnumerable?

感谢 Deepak MishraSteven 帮助我理解.我了解到这就是 dotnet DI 如何解析同一接口的多个实现.要获得所有实现,我将使用 IEnumerable 来获取实现它的所有服务.这是一个演示此操作的工作示例:

Thanks to Deepak Mishra and Steven for helping me understand. I learned that this is how dotnet DI resolve multiple implementations of the same interface. To get all implementations, I'd use IEnumerable<Interface> to get all services that implement it. Here is a working example demoing this:

using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;

namespace DotnetCoreDependencyInjection
{
    class Program
    {
        static void Main(string[] args)
        {
            IServiceCollection services = new ServiceCollection();
            services.AddSingleton<IValidator<Shipment>, ValidateSourceAddress>();
            services.AddSingleton<IValidator<Shipment>, ValidateDestinationAddress>();

            var serviceProvider = services.BuildServiceProvider();

            using var scope = serviceProvider.CreateScope();

            // DI will resolve IEnumerable<IValidator<Shipment>> to all implementations of IValidator<Shipment>
            var validators = scope.ServiceProvider.GetService<IEnumerable<IValidator<Shipment>>>();

            foreach (var validator in validators)
            {
                validator.Validate(new Shipment{ SourceAddress = "Source Address", DestinationAddress = "Destination Address"});
            }

        }
    }

    class Shipment
    {
        public int Id { get; set; }
        public string DestinationAddress { get; set; }
        public string SourceAddress { get; set; }
    }

    interface IValidator<T>
    {
        void Validate(T shipment);
    }

    class ValidateSourceAddress : IValidator<Shipment>
    {
        public void Validate(Shipment shipment)
        {
            Console.WriteLine($"Validate SourceAddress: {shipment.SourceAddress}");
        }
    }

    class ValidateDestinationAddress : IValidator<Shipment>
    {
        public void Validate(Shipment shipment)
        {
            Console.WriteLine($"Validate DestinationAddress: {shipment.DestinationAddress}");
        }
    }
}

推荐答案

当您注册同一接口的多个实现时,DI 可以使用包含所有实现的 IEnumerable 进行解析.如果您不指定 IEnumerable,则它将仅包含第一个实现.

When you register multiple implementation of the same interface, the DI can resolve with the IEnumerable containing all the implementation. If you don't specify IEnumerable, then it will contain only first implementation.

这篇关于注册 Mediatr IPipelineBehavior 的多个实现时了解 Asp.net Core 依赖注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆