2011-01-10 46 views
2

在Microsoft Unity IoC中,如果我打电话给Resolve<SomeType>(),我可以保证返回的对象是在当前会话期间创建的对象吗?是否解决<T>()每会话返回对象?

例如,三个用户登录,并让我们说,是被在容器中创建的SomeType对象必须为每个用户不同的值。将调用Resolve返回为当前用户创建的对象吗?或者它会做一些愚蠢的事情,比如返回创建的最后一个?

由于一些环境问题,我有麻烦测试自己,我需要很快检查一些东西,所以如果有人能回答这个问题,这将是非常有益的!

编辑

原谅我,我是很新的团结,但基于what I read here,好像我应该能够用唯一的名称来注册在容器中的对象,并通过该名称进行检索。那么,我是不是可以使用会话ID或某个会话内持续存在的其他值来检索我的对象?

+0

看起来好像你想使用Unity作为缓存,如果你正在注册一个'钥匙'的实例。这实际上并不是Unity最擅长的\,也可能是您收到的答案令人困惑的原因。 – 2011-01-11 19:22:24

+1

如果你确实使用Unity作为缓存,当你有一个Web服务器场时会发生什么,或者当ASP.Net工作者进程再循环时会发生什么? – 2011-01-11 19:32:31

+0

除了@chibacity说了什么之外,如果你在不同的线程之间共享实例,那么你正打开一个让自己受到伤害的世界。哪个线程为特定的请求提供服务是完全不确定的,并且当您想要访问它时,您需要同步左侧和右侧中心。真的,创造新的对象,如果它需要去数据库旅行并不昂贵。 – 2011-01-11 22:41:54

回答

6

哦,哇,在MVC应用程序中使用Unity的生命周期管理。我从哪说起呢?

首先,会话单例不是真的可行,因为没有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

默认行为是为每个解析调用返回一个新实例,这不是你想要的。

在会话中创建和解析同一个实例是可能的,但据我所知没有内置支持。你将不得不编写自己的一生经理,然后在注册你的类型时使用它。

有一个可以为每个线程实例执行的生命周期管理器,但是这对于会话没有用,因为线程将被重用,并且解决方案还需要跨多个请求工作才能真正实现会话范围。

有人为此写了一辈子的经理是完全可能的。