2015-07-13 44 views
1

我跟随此CQS tuturiol https://github.com/Code-First/CQS-Sample并且它使用Ninject。Ninject的Bind.ToMethod的Unity相当于使用CQRS

我目前使用Unity,并试图将此转换:

Bind<IQueryFactory>().ToMethod(t => new QueryFactory(x => Container.Current.Resolve(x))).InTransientScope(); 

我的查询工厂如下所示:

public class QueryFactory : IQueryFactory 
{ 
    private readonly Func<Type, object> _resolveCallback; 

    public QueryFactory(Func<Type, object> resolveCallback) 
    { 
     _resolveCallback = resolveCallback; 
    } 

    public T ResolveQuery<T>() 
     where T : class, IQuery 
    { 
     return _resolveCallback(typeof (T)) as T; 
    } 
} 

我已经试过container.RegisterType<IQueryFactory>(t => new InjectionFactory(u => u.Resolve(u)));但是,这并不工作。

+2

该文章给出的查询模型是有限制的,因为'IQuery'接口不是通用的。我会建议一个模型,在[这里]解释(https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=92)。 – Steven

回答

3

你会认为一个InjectionFactory将是一条路。这将编译:

container.RegisterType<IQueryFactory>(new ContainerControlledLifetimeManager(), 
    new InjectionFactory((c, x, o) => new QueryFactory(t => c.Resolve(x)))); 

的问题是,X型总是IQueryFactory这样就不会得到你想要的结果,这是返回一个IQUERY。

不幸的是,我不认为目前的设计很适合Unity。

但是,稍作修改就可以让工厂运作。有几种不同的方法可以做到这一点(例如,您可以在工厂注入容器并从那里解析),但在本例中,我将使用字典。

首先我们改变了工厂的定义:

public class QueryFactory : IQueryFactory 
{ 
    private readonly IDictionary<Type, Func<IQuery>> _factoryQueries; 

    public QueryFactory(IDictionary<Type, Func<IQuery>> factoryQueries) 
    { 
     this._factoryQueries = factoryQueries; 
    } 

    public T ResolveQuery<T>() where T : class, IQuery 
    { 
     return this._factoryQueries[typeof(T)]() as T; 
    } 

基本上,Func<Type, object> resolveCallback被交换包含用于创建所有支持IQUERY类型funcs中一个IDictionary。

接着注册的IDictionary和IQueryFactory:

IUnityContainer container = new UnityContainer(); 

// Register all IQuery's 
container.RegisterType<IActiveUsersQuery, ActiveUsersQuery>(); 
container.RegisterType<IUserByEmailQuery, UserByEmailQuery>(); 

IDictionary<Type, Func<IQuery>> factoryQueries = new Dictionary<Type, Func<IQuery>>() 
{ 
    { typeof(IActiveUsersQuery),() => container.Resolve<IActiveUsersQuery>() }, 
    { typeof(IUserByEmailQuery),() => container.Resolve<IUserByEmailQuery>() }, 
}; 

// Register mapping 
container.RegisterInstance<IDictionary<Type, Func<IQuery>>>(factoryQueries); 
container.RegisterType<IQueryFactory, QueryFactory>(); 

var factory = container.Resolve<IQueryFactory>(); 

factory.ResolveQuery<IActiveUsersQuery>().Execute(); 
factory.ResolveQuery<IActiveUsersQuery>().Execute(); 

如所提到的,更简单的QueryFactory办法,需要在容器上的依赖关系是:

public class QueryFactory : IQueryFactory 
{ 
    private readonly IUnityContainer container; 

    public QueryFactory(IUnityContainer container) 
    { 
     this.container = container; 
    } 

    public T ResolveQuery<T>() 
     where T : class, IQuery 
    { 
     return this.container.Resolve(typeof(T)) as T; 
    } 
} 

然而,有些人会反对具有工厂依赖于容器的实现。

另一种方法是摆脱工厂方法并直接注入查询;这会使依赖关系变得明显,但我可以看到您希望根据命令类型动态获取查询的场景。另外,我已经看到了命令和查询之间的关系,这些关系可以通过组合根中解决的开放泛型来处理。