在 .NET Core (MS.DI) 中注册具有类型约束的泛型类型

Jor*_*ker 2 .net c# asp.net dependency-injection mediatr

我有一个通用接口IPipelineBehavior<TRequest, TResponse>(来自 MediatR)。我正在尝试为此接口注册特定行为,如下所示:

services.AddTransient(typeof(IPipelineBehavior<,>),
    typeof(ValidationMiddleware<,>));
Run Code Online (Sandbox Code Playgroud)

ValidationMiddlewareIPipelineBehavior像这样实现:

public class ValidationMiddleware<TRequest, TResponse>
    : IPipelineBehavior<TRequest, Result<TResponse>>
Run Code Online (Sandbox Code Playgroud)

Result是一个自定义类,我希望所有 MediatR IRequestHandlers 返回。

当应用程序运行时,服务容器给出以下错误:

System.ArgumentException:实现类型“StudentManagement.App.Middleware.ValidationMiddleware 2[StudentManagement.App.Students.DisenrollStudentCommand,StudentManagement.App.Result1[System.Object]]”无法转换为服务类型“MediatR.IPipelineBehavior 2[StudentManagement.App.Students.DisenrollStudentCommand,StudentManagement.App.Result1[System.Object]]”

我不明白为什么,因为它们显然在运行时都具有相同的类型参数。我的猜测是,该Result<TResponse>位由于某种原因导致了错误,因为其他行为在刚刚实现时工作正常IPipelineBehavior<TRequest, TResponse>

有谁明白为什么我会收到此错误,以及我需要做什么来解决它?

Ste*_*ven 5

MS.DI 不支持您希望实现的目标。在处理泛型类型时,.NET Core 的内置 DI 容器非常有限(甚至可能很幼稚)。

例如,以下是泛型类型的三个(相当基本的)用例,所有这些均不受 MS.DI 支持:

// Example generic abstraction
public interface IGeneric<TKey, TValue> where TKey : struct { }

// Type with a different number of generic types than the abstraction
public class MonoGeneric<TKey> : IGeneric<TKey, string> where TKey : struct { }

// Type with the generic types in a different order
public class SwappedGeneric<TValue, TKey> : IGeneric<TKey, TValue>
    where TKey : struct { }

// Type where the generic types don't exactly map to those of the abstraction
// NOTE: This is your use case.
public class ConstrainedGeneric<TKey, TValue> : IGeneric<TKey, List<TValue>>
    where TKey : struct { }

// Registration
services.AddTransient(typeof(IGeneric<,>), typeof(MonoGeneric<>));
services.AddTransient(typeof(IGeneric<,>), typeof(SwappedGeneric<,>));
services.AddTransient(typeof(IGeneric<,>), typeof(ConstrainedGeneric<,>));

// Usage
// Should work on any of the registrations, but it fails on all!
provider.GetRequiredService<IGeneric<int, string>>();
Run Code Online (Sandbox Code Playgroud)

这不仅不受支持,而且 MS.DI 抛出的异常消息将非常无益且令人困惑。

IMO,您的用例非常有效,这就是为什么许多 DI 容器实际上支持此用例的原因。我的建议:选择一个更成熟的 DI 容器并测试它是否支持您想要应用泛型的方式。