在Microsoft Unity IoC中,如果我调用Resolve<SomeType>()
,我可以保证返回的对象是在当前会话期间创建的对象吗?
例如,有三个用户登录,并且假设在容器中创建的SomeType
对象对每个用户具有不同的值。调用Resolve
会返回为当前用户创建的对象吗?或者它会做一些愚蠢的事情,比如返回创建的最后一个?
由于一些环境问题,我自己也遇到了麻烦,我需要尽快检查一下,所以如果有人能回答这个问题,那将非常有帮助!
修改
请原谅我,我是Unity的新手,但基于what I read here,似乎我应该能够在容器中注册具有唯一名称的对象,并通过该名称检索它们。那么,我不能使用会话ID或会话中持续存在的其他值来检索我的对象吗?
答案 0 :(得分:6)
首先,会话单例实际上是不可能的,因为没有ASP.NET系统可以保证在同一会话中的请求之间使用相同的实例。会话可以通过在请求之间对其进行序列化和反序列化来模仿会话中持久存在的同一对象。
瞬态实例 - 即没有生命周期管理规范的简单注册在99%的时间内都是足够的。这意味着每次需要时都会创建一个已注册类型的实例。
在请求的整个生命周期中,您很少需要实例。但是当你需要那些时,真的需要那些。与DB的连接是完美的候选者。另一方面,请求单身人士更容易创建和管理。
最优雅的解决方案是使用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();
}
需要做的另一件事是覆盖Controller Factory以使用子容器来创建控制器。 Controller是进入应用程序的第一个入口点,它们可以简单地依赖于构造函数中的其他组件。
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;
}
}
答案 1 :(得分:2)
默认行为是为每个解析调用返回一个新实例,这不是您想要的。
可以在会话中创建和解析同一个实例,但据我所知,没有内置支持。您必须编写自己的生命周期管理器,然后在注册类型时使用它。
有一个生命周期管理器可以执行每个线程实例,但这对于会话没有用,因为线程将被重用,并且解析还需要跨多个请求才能真正实现会话范围。
完全可能有人为此写了终身经理。