我在使用asp.net核心依赖项注入时遇到麻烦,无法从IServiceProvider解析通用接口。这是我的设置:
通用接口:
public interface IRequest<out TResponse> {...}
public interface IRequestHandler<TRequest, TResult>
where TRequest : IRequest<TResult> {...}
具体实现:
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>> {...}
然后我有一个服务工厂,就是我这样注册依赖项注入:
public static void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IRequestHandler<GetUsersQuery,
IEnumerable<GetUsersResult>>, GetUsersQueryHandler>();
}
我可以像这样成功解决我的处理程序:
var handler =
_services.GetService<IRequestHandler<GetUsersQuery, IEnumerable<GetUsersResult>>>();
但是,我想在这个工厂中有一个通用方法,该方法可以接收IRequest的具体实现,并在不事先知道确切类型的情况下返回适当的处理程序,如下所示:
public Task<TResult> Execute<TResult>(IRequest<TResult> request)
{
var handler =
_services.GetService<IRequestHandler<IRequest<TResult>, TResult>>();
return handler.ExecuteAsync(request);
}
并像这样调用此方法:
_serviceFactory.Execute(new GetUsersQuery(){});
不幸的是,这不起作用,处理程序未解析,并且为null。我觉得这应该是可能的。
您能告诉我我做错了什么以及如何实现吗?
答案 0 :(得分:0)
我想我找到了一种方法,可以这样声明execute方法:
public Task<TResult> Execute<TRequest, TResult>(TRequest request)
where TRequest : IRequest<TResult>
{
var handler = _services.GetService<IRequestHandler<TRequest, TResult>>();
return handler.ExecuteAsync(request);
}
并以此方式使用:
_serviceFactory.Execute<GetUsersQuery, IEnumerable<GetUsersResult>>(query);
这有点难看,因为我必须同时指定Execute方法的请求类型和结果类型,只使用_serviceFactory.Execute(query)会更好,但我想可能不可能吗?
答案 1 :(得分:0)
此设计可能源自this博客文章。同一篇博文显示了您的确切问题的解决方案:
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);
}
根据您的情况,这可以翻译为以下内容:
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);
}
关于dynamic
的使用,博客文章指出:
不幸的是,我们需要使用反射调用Handle方法(在这种情况下,使用C#4.0 dymamic关键字),因为此时无法转换处理程序实例,因为通用TQuery参数在编译时不可用