当我们用在MVC总使用IoC时,大家的Controller生命周期(lifestyle)是以哪种方式注册的呢?
之前我一直没有思考过这个问题。众所周知在MVC开发过程中,大部分的组件都是以PerWebRequest的方式注册到容器的,Controller也不例外,以Castle为例,注册Controller的代码大都如下:
public class ControllerInstaller:IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( Classes.FromThisAssembly().BasedOn<Controller>().WithService.Self().LifestylePerWebRequest()); } }
经过长期项目运行证明,这样的方式并不会带来任何问题,这样的代码跑的很好。
后来在做webApi开发的时候,又以PerWebRequest的方式注册了webApi的controller。 由于项目需要,我们在MVC的controller中以in-memory的方式调用了webApi的controller, 代码会报出以下异常:Cannot reuse an 'HomeController' instance. 'HomeController' has to be constructed per incoming message. Check your custom 'IHttpControllerActivator' and make sure that it will not manufacture the same instance.
具体解释见ASP.NET Web API中的Controller
很明显,webApi希望每一次请求都创建一个新的controller, 而我们在MVC中的in-memory调用是在同一个webrequest中请求了相同的controller,我们意识到webApi的lifestyle方式选择有问题,在更换为LifestyleTransient后问题顺利解决。
那么Controller的lifestyle究竟是PerWebRequest呢还是Transient呢?我在stackoverfllow发现了这样的解释:
MVC controllers are transient. Thinking about it, this makes sense for a few reasons. First, if a single instance is used to service multiple requests and if multiple requests happen to hit the same controller at the same time, you're going to experience some fairly bizarre race conditions. Second, HTTP is by its very nature stateless, and requests exist independently of one another. This is reflected in the transient lifestyle of controllers.
意思是说:controller是transient,首先第一点正好证实了我们项目中遇到的问题,第二,http是无状态的,每一个请求都是相互独立的,这也正好符合transient的定义。