Unity容器RegisterType <tfrom,tto =“”>问题</tfrom,>

时间:2011-06-08 18:11:47

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

我正在尝试自动注册存储库:

这有效,但我不喜欢它,因为在服务层类中,我必须向构造函数提供具体的EntityRepository<T>,而不是提供接口IRepository<T>

public static IContainer RegisterRepositories(
    this IContainer container, params Assembly[] assemblies)
{
    var repositories = (
        from assembly in assemblies
        from type in assembly.GetTypes()
        where typeof(ObjectContext).IsAssignableFrom(type)
        from property in type.GetProperties()
        let propertyType = property.PropertyType
        where propertyType.IsGenericType 
        where propertyType
            .GetGenericTypeDefinition() == typeof(ObjectSet<>)
        select new 
        {
            ObjectContextType = type, 
            DomainType = propertyType.GetGenericArguments()[0] 
        })
        .ToList();

    foreach (var repository in repositories)    
    {
        container.RegisterType(typeof(BaseObjectContext), 
            new PerExecutionContextLifetimeManager());

        var serviceType = typeof(IRepository<>)
            .MakeGenericType(repository.DomainType);

        var implementationType = typeof(EntityRepository<>)
            .MakeGenericType(repository.ObjectContextType);

        container.RegisterType(serviceType, implementationType, 
            new TransientLifetimeManager());
    };

    return container;
}

我想使用container.RegisterType<TFrom, TTo>(new TransientLifetimeManager());自动注册我的存储库 我知道问题出在哪里,因为这种注册方式要求您提供接口和类的真实名称,例如IRepository<Customer>EntityRepository<Customer>。我可以这样做,但我必须逐个列出存储库,如果您正在处理100个Domain对象的项目,我认为这是不可行的。 我想像这样自动执行它们,这样我就可以在服务层类中注入IRepository<T>

// Configure root container.Register types and life time 
// managers for unity builder process
public static IContainer RegisterRepositories(
    this IContainer container, params Assembly[] assemblies)
{
    var repositories = (
        from assembly in assemblies
        from type in assembly.GetTypes() 
        where typeof(ObjectContext).IsAssignableFrom(type)
        from property in type.GetProperties()
        let propertyType = property.PropertyType
        where propertyType.IsGenericType 
        where propertyType
            .GetGenericTypeDefinition() == typeof(ObjectSet<>)
        select new 
        {
            ObjectContextType = type, 
            DomainType = propertyType.GetGenericArguments()[0] 
        })
        .ToList()

    foreach (var repository in repositories)
    {
        container.RegisterType<BaseObjectContext>(
            new PerExecutionContextLifetimeManager(), 
            new InjectionConstructor());

        container.RegisterType<IRepository<repository.DomainType>,
             EntityRepository<repository.ObjectContextType>>(
            new TransientLifetimeManager());
    };

    return container;
}

1 个答案:

答案 0 :(得分:1)

我不确定你要解决的问题是什么,但我认为你的设计从长远来看不会起作用。然而,我清楚的是,你有一个很大的域,并希望能够在服务类中注入IRepository<T>个实例,但希望利用实体框架代码生成器的批量注册,以防止你从必须维护大量代码,这是一个令人钦佩的目标。

但是,您尝试将IRepository<T>实例注入服务。虽然存储库是一种常见的设计模式,但直接将存储库注入服务对我来说从来没有用过,在实体框架的上下文中看起来很奇怪,它使用工作单元模式(ObjectContext)来集中应用程序和服务器之间的操作。数据库。注入存储库意味着每个存储库下必须存放ObjectContext,并且您可能希望在单个服务中注入的所有存储库实例中具有相同的ObjectContext,因为您的操作可能应该是原子的。 / p>

IMO最好不要将IRepository<T>个实例注入您的服务,而是注入UnitOfWork甚至更好:IUnitOfWorkFactoryIUnitOfWorkFactory可以创建一个新的UnitOfWork实例(服务必须在完成后进行处置),UnitOfWork将包含IRepository<T>实例的列表,并包含SubmitChanges {1}}方法。

通过在IRepository<T> GetRepository<T>()上实施UnitOfWork方法,您可以有效地获取特定的存储库,而无需进行任何批量注册,以便连接100个存储库。这可以在IUnitOfWork实现中为您完成。

从应用程序的角度来看,如果UnitOfWork包含特定IRepository<T>实现的属性(例如public IRepository<Customer> Customers { get; set; })会更好,但这确实意味着您需要添加新属性当新实体被添加到系统时,这可能不是你喜欢的。但是,根据我的经验,这并不会对可维护性造成太大影响,同时它极大地提高了代码的可读性。

这个设计可能看起来有点牵强,但我实际上有一个类似的设计在生产中运行超过半年,它完美地工作。我在博客上写了这篇文章(见Faking your LINQ provider),其他人已经在他们的应用程序中成功采用了这种方法。它似乎也适用于其他人。也许这对你很有意思,或者它至少可以给你一些如何有效地做到这一点的想法。我使用依赖注入,并且在给定的设计中,我只需配置几种类型即可使其运行。

我希望这会有所帮助。