【问题标题】:How to reuse a transient dependency in same context with Castle Windsor DI container如何在与 Castle Windsor DI 容器相同的上下文中重用瞬态依赖项
【发布时间】:2010-10-21 11:07:19
【问题描述】:

如果我有以下设置,当在同一上下文中创建对象时,如何配置我的容器以使用同一数据库

public class Database { }
public interface IRepository { Database Database { get; } }
public interface IFooRepository : IRepository { }
public interface IBarRepository : IRepository { }

public class FooRepository : IFooRepository
{
    public Database Database { get; private set; }
    public FooRepository(Database database) { this.Database = database; }
}

public class BarRepository : IBarRepository
{
    public Database Database { get; private set; }
    public BarRepository(Database database) { this.Database = database; }
}

public class Consumer
{
    public IFooRepository fooRepository { get; private set; }
    public IBarRepository barRepository { get; private set; }
    public Consumer(IFooRepository fooRepository, IBarRepository barRepository)
    {
        this.fooRepository = fooRepository;
        this.barRepository = barRepository;
    }
}

[TestClass]
public class ConfigurationTest
{
    private IWindsorContainer container;

    [TestMethod]
    public void SameDatabaseIsUsed()
    {
        Consumer consumer = container.Resolve<Consumer>();
        IFooRepository fooRepository = consumer.fooRepository;
        IBarRepository barRepository = consumer.barRepository;
        Assert.AreEqual(fooRepository.Database, barRepository.Database); //FAILS
    }

    [TestMethod]
    public void DifferentDatabaseIsUsed()
    {
        Consumer consumer = container.Resolve<Consumer>();
        IFooRepository fooRepository = consumer.fooRepository;
        Consumer consumer2 = container.Resolve<Consumer>();
        IBarRepository barRepository = consumer2.barRepository;
        Assert.AreNotEqual(fooRepository.Database, barRepository.Database); //PASSES
    }

    [TestInitialize]
    public void SetUp()
    {
        container = new WindsorContainer();
        container.Register(
            Component.For<Database>().ImplementedBy<Database>().LifeStyle.Transient,
            AllTypes.FromThisAssembly()
                    .BasedOn<IRepository>().WithService.FromInterface()
                    .Configure(c => c.LifeStyle.Transient),
            Component.For<Consumer>().ImplementedBy<Consumer>().LifeStyle.Transient
                    );

    }
}

编辑: 我尝试过使用自定义生活方式,但我无法弄清楚我可以使用什么来检测我已经切换了上下文

public class DatabaseLifestyleManager : AbstractLifestyleManager
{
    private CreationContext context;
    private Database database;

    private Database Database
    {
        get
        {
            if (database == null) database = new Database();
            return database;
        }
        set 
        {
            database = null;
        }
    }

    public override object Resolve(CreationContext context)
    {
        if (this.context!=null && this.context.??? == context.???)
            return Database;
        else
        {
            this.context = context;
            Database = null;
            return Database;
        }

    }

    public override void Dispose()
    {
        database = null;
        context = null;
    }
}
......
Component.For<Database>().ImplementedBy<Database>().LifeStyle.Custom(typeof(DatabaseLifestyleManager)

【问题讨论】:

    标签: dependency-injection castle-windsor ioc-container


    【解决方案1】:

    在请求瞬态组件时,您总是会得到一个新实例,如果它不是您想要的,请不要使用瞬态生活方式:-)

    为什么你要注册一个瞬态组件,却试图根据某种“上下文”来解析同一个对象?很可能这种生活方式不适合这种情况,如果你试图强迫它变成不合适的东西,你会遇到麻烦。

    您想要的是一种情境式生活方式,在 this article 中提到。 以下两个要点对此有一个实现:

    这将允许您这样做:

    Register(Component.For<Database>().LifeStyle.Scoped())
    
    [TestMethod]
    public void SameDatabaseIsUsed()
    {
        using (container.BeginScope())
        {
            Consumer consumer = container.Resolve<Consumer>();
            IFooRepository fooRepository = consumer.fooRepository;
            IBarRepository barRepository = consumer.barRepository;
            Assert.AreEqual(fooRepository.Database, barRepository.Database); // YAY!
        }
    }
    

    希望这会有所帮助!

    【讨论】:

    • 当我说上下文时,我的意思是,如果我从容器中获取一个对象的实例,该实例依赖于两个不同的存储库,并且这些存储库都依赖于处理数据库操作的第四个对象。然后我想要一个行为是将相同的数据库对象注入到存储库中。但是,如果稍后使用一个或多个存储库创建另一个对象,则数据库对象是一个新实例,而不是与注入到我的第一个对象中的相同。可以做这样的事情的生活方式是“PerWebRequest”,但我在一个 WinForm 世界:-(。
    【解决方案2】:
    【解决方案3】:

    我自己通过实现 IDisposable 提出了这个解决方案,这样我就可以为数据库使用一种 sessionscope

    这是处理这种情况的有效方法吗?

    所有测试都通过了,但有一些附加功能,必须在我未来的所有存储库使用者中实现:

    public class Database { }
    public interface IRepository : IDisposable { Database Database { get; } }
    public interface IFooRepository : IRepository { }
    public interface IBarRepository : IRepository { }
    
    public abstract class BaseRepository : IDisposable
    {
        public BaseRepository(Database database) { this.Database = database; }
        public Database Database { get; private set; }
        public void Dispose() { Database = null; }
    }
    
    public class FooRepository : BaseRepository, IFooRepository
    {
        public FooRepository(Database database) : base(database) { }
    }
    
    public class BarRepository : BaseRepository, IBarRepository
    {
        public BarRepository(Database database) : base(database) { }
    }
    
    public abstract class BaseConsumer : IDisposable
    {
        public abstract void Dispose();
    }
    
    public class Consumer : BaseConsumer
    {
        public IFooRepository fooRepository { get; private set; }
        public IBarRepository barRepository { get; private set; }
    
        public Consumer(IFooRepository fooRepository, IBarRepository barRepository)
        {
            this.fooRepository = fooRepository;
            this.barRepository = barRepository;
        }
    
        public override void Dispose()
        {
            this.fooRepository.Dispose();
            this.barRepository.Dispose();
        }
    }
    
    [TestClass]
    public class ConfigurationTest
    {
        private IWindsorContainer container;
    
        [TestMethod]
        public void SameDatabaseIsUsed()
        {
            IFooRepository fooRepository;
            IBarRepository barRepository;
            using (Consumer consumer = container.Resolve<Consumer>())
            {
                fooRepository = consumer.fooRepository;
                barRepository = consumer.barRepository;
                Assert.AreEqual(fooRepository.Database, barRepository.Database); //FAILS
            }
            Assert.IsNull(fooRepository.Database);
            Assert.IsNull(barRepository.Database);
    
        }
    
        [TestMethod]
        public void DifferentDatabaseIsUsed()
        {
            IFooRepository fooRepository;
            IBarRepository barRepository;
    
            using (Consumer consumer = container.Resolve<Consumer>())
                fooRepository = consumer.fooRepository;
    
            Assert.IsNull(fooRepository.Database);
    
            using (Consumer consumer2 = container.Resolve<Consumer>())
                barRepository = consumer2.barRepository;
    
            Assert.IsNull(barRepository.Database);
        }
    
        [TestInitialize]
        public void SetUp()
        {
            container = new WindsorContainer().Register(
                Component.For<Database>().ImplementedBy<Database>().LifeStyle.Singleton,
                AllTypes.FromThisAssembly()
                        .BasedOn<IRepository>().WithService.FromInterface()
                        .Configure(c => c.LifeStyle.Transient),
                Component.For<Consumer>().ImplementedBy<Consumer>().LifeStyle.Transient
                        );
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多