IoC Instancing дилемма общего контекста - PullRequest
0 голосов
/ 02 ноября 2011

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

 class CompanyService : ICompanyService
{
    private IUserRepository _userRepository;

    private IEmployeeRepository _employeeRepository;

    public CompanyService(IEmployeeRepository employeeRepository,
          IUserRepository userRepository)
    {
        this._employeeRepository = employeeRepository;
        this._userRepository = userRepository;
    }
}

Службе компании требуются репозитории пользователей и сотрудников, для каждого из этих репозиториев требуется контекст:

class UserRepository : Repository<User>, IUserRepository
{
    public UserRepository(IDataContext dataContext) : base(dataContext) { }
}

class EmployeeRepository : Repository<Employee>, IEmployeeRepository
{
    public EmployeeRepository(IDataContext dataContext) : base(dataContext) { }
}

Я хочу иметь возможность регистрировать эти типы в контейнере следующим образом:

    public WindsorContainer BuildContainer()
    {
        var container = new WindsorContainer();
        container.Register(Component.For<SqlContext, IDataContext>());
        container.Register(Component.For<UserRepository, IUserRepository>());
        container.Register(Component.For<EmployeeRepository, IEmployeeRepository>());
        container.Register(Component.For<CompanyService, ICompanyService>());
        return container;
    }

Тогда я просто хочу разрешить Сервис следующим образом:

        var container = BuildContainer();
        var service = container.Resolve<ICompanyService>();

Я знаю, что по умолчанию используется экземпляр singleton, я хочу, чтобы все эти службы, включая репозитории, были временными, но я хочу использовать один и тот же контекст с репозиториями, НО только для определенного набора запросов.

EDIT: ThreadLocal или основанный на запросе экземпляр НЕ БУДУТ РАБОТАТЬ, потому что, когда я разрешаю ICompanyService дважды из одного и того же потока, но используется в 2 контекстах, поток остается тем же, и экземпляр IDataContext будет таким же, однако они не должны быть.

Я не вижу способа сделать это, когда контейнер является однимтонна, единственный способ увидеть это - использовать функцию сборки для перестройки всего контейнера при каждом запросе и сделать IDataContext одиночным, а все остальное временным.

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

Я просто неправильно смотрю на всю эту проблему, кто-то может указать мне правильное направление?

Спасибо

1 Ответ

0 голосов
/ 26 ноября 2011

Одним из решений является предоставление собственного шаблона UnitOfWork и реализация собственного стиля жизни для управления жизненным циклом данных без привязки его к потоку, веб-запросу и т. Д.

Вам придется использоватьстатическое свойство в вашем классе UnitOfWork, чтобы эта работа работала, поэтому ваша единица работы может выглядеть следующим образом:

public class UnitOfWork : IDisposable {
    [ThreadStatic]
    public static UnitOfWork Current { get; set; }

    private IDictionary<string, object> _items;

    public IDictionary<string, object> Items 
    {
         get { 
              if(_items == null) 
              {
                 _items = new Dictionary<string, object>();
              }
              return _items;
         }
    }

    public void Dispose()
    {
         Current = null;
    }

    public static UnitOfWork Start() 
    {
         Current = new UnitOfWork();
         return Current;
    }
}

Если у вас есть что-то подобное, вы можете использовать его следующим образом:

using(UnitOfWork.Start())
{
    var companyService = container.Resolve<ICompanyService>();
    // .. use company service
}

Наконец, ваш собственный стиль жизни будет выглядеть так:

public class UnitOfWorkLifestyleManager : AbstractLifestyleManager
{
    private string PerUnitOfWorkObjectID = "UnitOfWorkLifestyleManager_" + Guid.NewGuid().ToString(); 

    public override object Resolve()
    {
        if(UnitOfWork.Current.Items[PerUnitOfWorkObjectID] == null)
        {
            // Create the actual object
            UnitOfWork.Current.Items[PerUnitOfWorkObjectID] = base.Resolve();  
        }

        return UnitOfWork.Current.Items[PerUnitOfWorkObjectID];
    }

    public override void Dispose()
    { 
    }
}

И регистрация вашего собственного стиля жизни:

container.Register(Component.For<SqlContext, IDataContext>().Lifestyle.Custom<UnitOfWorkLifestyle>());
...