Unity容器基于属性解析

时间:2017-05-17 15:11:53

标签: c# asp.net dependency-injection unity-container cqrs

我正在编写一个针对不同客户端具有不同类实现的应用程序。我们正在使用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>>();
    }

1 个答案:

答案 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