.NET Core依赖注入,解析泛型接口

Tar*_*ras 5 c# generics dependency-injection .net-core

我在 ASP.NET Core 依赖注入方面遇到问题,无法解析 IServiceProvider 的通用接口。这是我的设置:

通用接口:

public interface IRequest<out TResponse> {...}

public interface IRequestHandler<TRequest, TResult> 
    where TRequest : IRequest<TResult> {...}
Run Code Online (Sandbox Code Playgroud)

具体实现:

public class GetUsersQuery : IRequest<IEnumerable<GetUsersResult>> {...}

public abstract class RequestHandler<TRequest, TResult> 
    : IRequestHandler<TRequest, TResult>
    where TRequest : IRequest<TResult> {...}

public class GetUsersQueryHandler
    : RequestHandler<GetUsersQuery, IEnumerable<GetUsersResult>> {...}
Run Code Online (Sandbox Code Playgroud)

然后我有一个服务工厂,我像这样注册依赖注入:

public static void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IRequestHandler<GetUsersQuery, 
    IEnumerable<GetUsersResult>>, GetUsersQueryHandler>();
}
Run Code Online (Sandbox Code Playgroud)

我可以像这样成功解决我的处理程序:

var handler = 
_services.GetService<IRequestHandler<GetUsersQuery, IEnumerable<GetUsersResult>>>();
Run Code Online (Sandbox Code Playgroud)

但是,我希望在这个工厂中有一个通用方法,它接收 IRequest 的具体实现并返回适当的处理程序,而无需事先知道确切的类型,如下所示:

public Task<TResult> Execute<TResult>(IRequest<TResult> request)
{
    var handler =
        _services.GetService<IRequestHandler<IRequest<TResult>, TResult>>();
    return handler.ExecuteAsync(request);
}
Run Code Online (Sandbox Code Playgroud)

并像这样调用这个方法:

_serviceFactory.Execute(new GetUsersQuery(){});
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不起作用,处理程序未解析并且为空。我觉得这应该是可能的。

你能告诉我我做错了什么以及如何实现这一目标吗?

Ste*_*ven 4

这个设计可能源自这篇博文。同一篇博客文章显示了针对您的具体问题的解决方案:

public TResult Process<TResult>(IQuery<TResult> query)
{
    var handlerType = typeof(IQueryHandler<,>)
        .MakeGenericType(query.GetType(), typeof(TResult));

    dynamic handler = container.GetInstance(handlerType);

    return handler.Handle((dynamic)query);
}
Run Code Online (Sandbox Code Playgroud)

对于您的情况,这将转化为以下内容:

public Task<TResult> Execute<TResult>(IRequest<TResult> request)
{
    var handlerType = typeof(IRequestHandler<,>)
        .MakeGenericType(request.GetType(), typeof(TResult));

    dynamic handler = _services.GetRequiredService(handlerType);

    return handler.ExecuteAsync((dynamic)query);
}
Run Code Online (Sandbox Code Playgroud)

关于 的使用dynamic,博客文章指出:

不幸的是,我们需要使用反射来调用 Handle 方法(在本例中,使用 C# 4.0dymamic关键字完成),因为此时无法强制转换处理程序实例,因为通用 TQuery 参数在编译时不可用。