Как повторно использовать временную зависимость в одном контексте с контейнером Castle Windsor DI - PullRequest
2 голосов
/ 21 октября 2010

Если у меня есть следующие настройки, как я могу настроить свой контейнер для использования той же базы данных, когда объекты создаются в одном контексте

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
                    );

    }
}

EDIT: Я пытался использовать собственный образ жизни, но я не могу понять, что я могу использовать, чтобы обнаружить, что я изменил контекст

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)

Ответы [ 3 ]

3 голосов
/ 22 октября 2010

Вы всегда получаете новый экземпляр при запросе переходного компонента, если это не то, что вы хотите, не используйте переходный образ жизни: -)

Зачем вам регистрировать переходный компонент, но пытаться разрешитьодин и тот же объект в зависимости от какого-то «контекста»?Скорее всего, образ жизни не подходит для данной ситуации, и у вас возникнут проблемы, пытаясь заставить его превратиться в нечто, чего нет.

То, что вы хотите, - это что-то вроде контекстного образа жизни, упомянутого в этой статье .У следующих двух сущностей есть реализация для этого:

Это позволит вам сделать это:

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!
    }
}

Надеюсь, это поможет!

2 голосов
/ 08 марта 2011
0 голосов
/ 21 октября 2010

Я сам придумал это решение, реализовав IDisposable, чтобы я мог использовать своего рода сеанс для базы данных

Будет ли это правильным способом справиться с этой ситуацией?

Все тесты пройдены, но есть некоторые дополнительные функции, которые должны быть реализованы во всех моих будущих потребителях репозиториев:

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
                    );
    }
}
...