相当于Ninject的Bind.ToMethod使用CQRS

时间:2015-07-13 12:43:38

标签: c# ninject unity-container ioc-container cqrs

我正在关注此CQS tuturiol https://github.com/Code-First/CQS-Sample并使用Ninject。

我目前正在使用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)));,但这不起作用。

1 个答案:

答案 0 :(得分:3)

你认为注射工厂将是最佳选择。这编译:

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被交换为包含Funcs的IDictionary,用于创建所有支持的IQuery类型。

接下来注册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;
    }
}

但是,有些人会反对让工厂依赖于容器实现。

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