如何在ASP.NET MVC 5中通过Unity.Mvc正确注入TempDataDictionary?
嘿,刚好我之前在ASP.NET MVC5项目里用Unity处理过类似的依赖注入问题,给你一步步梳理怎么搞定这个事儿:
首先得明确一个关键点:TempDataDictionary是和当前HTTP请求上下文绑定的,不能像普通服务那样注册成单例或者瞬时实例——每个请求都有自己独立的TempData,所以我们得让Unity在解析的时候,动态从当前请求里拿到对应的实例。
1. 用工厂方法注册TempDataDictionary
打开你的Unity配置文件(一般是UnityConfig.cs),添加下面的注册代码,通过工厂方法来获取当前请求的TempData:
container.RegisterType<TempDataDictionary>( new InjectionFactory(c => { // 先解析当前的ControllerContext var controllerContext = c.Resolve<ControllerContext>(); // 返回当前请求的TempData实例 return controllerContext.TempData; }) );
这样每次Unity需要TempDataDictionary的时候,都会从当前请求的ControllerContext里拿到正确的实例,完全贴合请求上下文。
2. 确保ControllerContext能被正确解析
如果你的容器还没注册ControllerContext,得补上这一步——同样用工厂方法从当前HttpContext构建:
container.RegisterType<ControllerContext>( new InjectionFactory(c => { var currentHttpContext = HttpContext.Current; if (currentHttpContext == null) throw new InvalidOperationException("当前没有HTTP请求上下文,无法获取TempData"); // 用一个空Controller实例来构建ControllerContext,我们只需要它的TempData return new ControllerContext( new HttpContextWrapper(currentHttpContext), new RouteData(), new EmptyController() ); }) ); // 内部辅助的空Controller类,不用对外暴露 private class EmptyController : Controller { }
3. 验证MessageManager的依赖注入
现在你的MessageManager就能正常依赖TempDataDictionary了,比如你的类定义应该是这样的:
public class MessageManager { private readonly TempDataDictionary _tempData; // 构造函数注入TempDataDictionary public MessageManager(TempDataDictionary tempData) { _tempData = tempData; } public void AddSuccessMessage(string message) { _tempData["SuccessMessage"] = message; } }
注册MessageManager的时候直接用默认的瞬时注册就行:
container.RegisterType<MessageManager>();
之后你在Controller里注入MessageManager时,Unity会自动把当前请求的TempDataDictionary实例传进去,完美解决依赖问题。
额外场景:处理非HTTP请求的情况
如果你的应用有后台任务或者非HTTP请求的场景需要用到MessageManager,上面的代码会抛出异常。这时候可以做个兼容:
container.RegisterType<TempDataDictionary>( new InjectionFactory(c => { var currentHttpContext = HttpContext.Current; if (currentHttpContext == null) // 没有请求上下文时返回一个空的TempDataDictionary return new TempDataDictionary(); var controllerContext = new ControllerContext( new HttpContextWrapper(currentHttpContext), new RouteData(), new EmptyController() ); return controllerContext.TempData; }) );
这样不管是HTTP请求还是后台任务,都能正常解析MessageManager了。
内容的提问来源于stack exchange,提问作者Junior

