Resolve <T>() возвращает объекты за сеанс? - PullRequest
2 голосов
/ 11 января 2011

В Microsoft Unity IoC, если я вызываю Resolve<SomeType>(), могу ли я гарантировать, что возвращенный объект является тем, который был создан во время текущего сеанса?

Например, три пользователя входят в систему, и скажем, что объект SomeType, который создается в контейнере, имеет разные значения для каждого пользователя. Будет ли вызов Resolve вернуть объект, созданный для текущего пользователя? Или он сделал бы что-нибудь глупое, вроде возврата последнего созданного?

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

Редактировать

Простите, я очень новичок в Unity, но на основании того, что я прочитал здесь , похоже, я должен иметь возможность регистрировать объекты в контейнере с уникальным именем и извлекать их по этому имени , Итак, я не смогу использовать идентификатор сеанса или какое-либо другое значение, которое сохраняется в сеансе, для извлечения моего объекта?

Ответы [ 2 ]

6 голосов
/ 11 января 2011

Ух ты, управление временем жизни с помощью Unity в приложении MVC.С чего начать?

Прежде всего, сеансовые синглтоны на самом деле невозможны, поскольку нет системы ASP.NET, которая гарантировала бы, что один и тот же экземпляр будет использоваться между запросами в одном сеансе.Сеанс может имитировать тот же объект, сохраняющийся в сеансе, путем сериализации и десериализации его между запросами.

Переходные экземпляры - то есть, простые регистрации без спецификации управления сроком службы достаточны в 99% случаев.Это подразумевает, что экземпляр зарегистрированного типа будет создаваться каждый раз, когда это необходимо.

Очень редко вам нужно, чтобы экземпляры жили в течение всего времени существования запроса.Однако, когда вам это нужно, вы действительно нуждаетесь в них.Подключение к БД является идеальным кандидатом для этого.С другой стороны, создание запросов и управление ими намного проще в создании и управлении.

Наиболее элегантным решением является использование дочерней функции контейнера Unity.Дочерний контейнер может быть создан в начале запроса и расположен в конце запроса (в качестве дополнительного бонуса он будет располагать всеми ContainerControlledLifetimeManager экземплярами).

При создании дочернего контейнера все регистрациивсе еще доступны из родительского контейнера, поэтому вам нужно зарегистрировать специфический запрос в дочернем контейнере.

Вот псевдокод, чтобы это заработало:

private void Application_Start() {
  _parentContainer = new UnityContainer();
   //creates a transient registration, available at any point in the app.
  _parentContainer.RegisterType<IParentIntf, ParentIntfImpl>();
  ControllerBuilder.Current.SetControllerFactory(new ServiceLocatorControllerFactory());
}

private void Application_BeginRequest() {
  var childContainer = _parentContainer.CreateChildContainer();
  //registers a request "singleton"
  //This registration is a type registration, an instance of RequestInterfaceImpl
  //will be created when needed and then kept in the container for later use.
  childContainer.RegisterType<IRequestInterface,RequestInterfaceImpl>(new ContainerControlledLifetimeManager());
  //save the child container in the context, so we can use it later
  HttpContext.Items["childContainer"] = childContainer;
}

private void Application_EndRequest() {
  //dispose the child container
  ((IUnityContainer)HttpContext.Items["childContainer"]).Dispose();
}

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

public class UnityControllerFactory : DefaultControllerFactory {

    #region IControllerFactory Members

    public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) {
        IController controller;
        controllerName = controllerName.ToLower();
        var container = ((IUnityContainer)HttpContext.Items["childContainer"])
        if(container.IsRegistered<IController>(controllerName))
            controller = container.Resolve<IController>(controllerName);
        else 
            controller = base.CreateController(requestContext, controllerName) ;
        return controller;
    }
} 
2 голосов
/ 11 января 2011

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

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

Существует диспетчер времени жизни, который может работать с экземплярами потоков, но это не полезно для сеансов, так как потоки будут повторно использоваться, и для решения проблемы потребуется также работать с несколькими запросами, чтобы быть действительно областью сеанса. *

Вполне возможно, что кто-то написал пожизненный менеджер для этого.

...