我正在编写一个针对不同客户端具有不同类实现的应用程序。我们正在使用CQRS,我想为每个客户端添加不同的命令和查询实现(如果不存在客户端特定的,则默认为默认值)。
以前写的应用程序只有一个客户端,这很好用,但现在我们需要为每个客户端覆盖命令和客户端。我已经玩弄了很多关于如何做到这一点的想法,但是这感觉最干净,因为只需添加一组查询/命令就可以轻松添加新客户端。
调度查询的代码如下:
public InProcQueryDispatcher(
IQueryHandlerFactory queryHandlerFactory,
Action<Exception, IQuery> onHandlerFailed)
{
this.queryHandlerFactory = queryHandlerFactory;
this.onHandlerFailed = onHandlerFailed;
this.getHandlerMethod = typeof(IQueryHandlerFactory).GetMethod("GetHandler");
}
public async Task<TResult> Execute<TResult>(IQuery<TResult> query)
{
if (query == null)
{
throw new ArgumentNullException();
}
try
{
var queryHandler = this.ResolveHandler<TResult>(query.GetType());
var task = (Task<TResult>) queryHandler.Handle((dynamic) query);
return await task;
}
catch (Exception ex)
{
this.onHandlerFailed(ex, query);
throw;
}
}
private dynamic ResolveHandler<TResult>(Type queryType)
{
var getHandler = this.getHandlerMethod.MakeGenericMethod(queryType, typeof (TResult));
return getHandler.Invoke(this.queryHandlerFactory, null);
}
}
我现在希望能够按如下方式更改它:
`public async Task<TResult> Execute<TResult>(IQuery<TResult> query)
{
if (query == null)
{
throw new ArgumentNullException();
}
try
{
var queryHandler = this.ResolveHandler<TResult>(query.GetType(), query.ClientId);
var task = (Task<TResult>) queryHandler.Handle((dynamic) query);
return await task;
}
catch (Exception ex)
{
this.onHandlerFailed(ex, query);
throw;
}
}
private dynamic ResolveHandler<TResult>(Type queryType, Guid clientId)
{
var getHandler = this.getHandlerMethod.MakeGenericMethod(queryType, clientId, typeof (TResult));
return getHandler.Invoke(this.queryHandlerFactory, null);
}
有人可以推荐我如何更新我的getHandleMethod来解析基于clientID的正确查询吗?
GetHandleMethod:
public IQueryHandler<TQuery, TResult> GetHandler<TQuery, TResult>() where TQuery : class, IQuery<TResult>
{
return container.Resolve<IQueryHandler<TQuery, TResult>>();
}
答案 0 :(得分:0)
使用IoC,您的对象不应该意识容器本身,因为您不能将容器直接传递给构造函数。但是,您可以将工厂传递给您的班级,然后将其用于解决问题。我发现将它与命名注册相结合非常有效。如何做到这一点的摘要将是:
container.RegisterType<IQueryHandler<TQuery, TResult>, QueryHandlerVersionOne<TQuery, TResult>>("1");
container.RegisterType<IQueryHandler<TQuery, TResult>, QueryHandlerVersionTwo<TQuery, TResult>>("2");
container.RegisterType<Func<int, IQueryHandler<TQuery, TResult>>>(
new InjectionFactory(c =>
new Func<int, IQueryHandler<TQuery, TResult>>((clientID) =>
{
var handler = c.Resolve<IQueryHandler<TQuery, TResult>>(clientID.ToString());
return handler;
})));
然后,在构造函数中,为工厂注入Func<int, IQueryHandler<TQuery, TResult>>
类型添加一个参数。
我回答了一个较长的例子in this post。