ASP.NET MVC - 在基本控制器中为母版页设置 ViewData
Posted
技术标签:
【中文标题】ASP.NET MVC - 在基本控制器中为母版页设置 ViewData【英文标题】:ASP.NET MVC - Set ViewData for masterpage in base controller 【发布时间】:2009-06-10 15:52:40 【问题描述】:我在我的 ASP.NET MVC 项目中使用母版页。此母版页需要存在一些 ViewData,它会在每个页面上显示。
如果我没有在我的控制器中设置这个 ViewData 键,我会收到一个找不到它的错误。但是,我不想在每个控制器中都设置 ViewData(我不想在每个控制器中都说 ViewData["foo"] = GetFoo();
)。
所以,我正在考虑在基本控制器中设置它,并让每个控制器都从这个基本控制器继承。在基本控制器默认构造器中,我设置了 ViewData。我在这里找到了类似的方法:http://www.asp.net/learn/MVC/tutorial-13-cs.aspx. 到目前为止一切都很好,这行得通……但问题是这些数据来自某处的数据库。
现在,当我想对我的控制器进行单元测试时,从基本控制器继承的控制器调用其默认构造函数。在默认构造函数中,我初始化我的存储库类以从数据库中获取此数据。结果:我的单元测试失败,因为它无法访问数据(我当然不希望他们访问这些数据)。
我也不想将正确的 Repository(或 DataContext,无论你如何命名)类传递给每个控制器,然后再将其传递给默认控制器,然后我可以用我的单元测试对其进行模拟。控制器又依赖于其他存储库类,我最终会将多个参数传递给构造函数。对我的感觉来说工作太多了,还是我错了?还有其他解决方案吗?
我尝试过使用 StructureMap,但最后我觉得这不能解决我的问题,因为每个控制器仍然必须调用将初始化存储库类的基本构造函数,所以我不能嘲笑它。
This 是一个类似的问题,但我发现没有给出令人满意的答案。我可以用一种简洁的方式解决这个问题,也许使用 StructureMap 作为解决方案吗?或者我应该吸吮它并将存储库传递给每个控制器并再次将其传递给基本控制器?再一次,对于如此简单的事情,感觉就像做了大量的工作。谢谢!
【问题讨论】:
【参考方案1】:我看到两个选项:
第一:
在 YourBaseController.OnActionExecuting() 或 YourBaseController.OnActionExecuted() 中为 MasterPage 设置 ViewData:
public class YourBaseController : Controller
protected override void OnActionExecuting(ActionExecutingContext filterContext)
// Optional: Work only for GET request
if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")
return;
// Optional: Do not work with AjaxRequests
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
return;
...
filterContext.Controller.ViewData["foo"] = ...
第二:
或者创建自定义过滤器:
public class DataForMasterPageAttribute : ActionFilterAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
// Optional: Work only for GET request
if (filterContext.RequestContext.HttpContext.Request.RequestType != "GET")
return;
// Optional: Do not work with AjaxRequests
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
return;
...
filterContext.Controller.ViewData["foo"] = ...
然后应用到你的控制器:
[DataForMasterPage]
public class YourController : YourBaseController
...
我认为第二种解决方案完全适合您的情况。
【讨论】:
嗯,这看起来很有希望。我现在在家,所以明天会测试这个,虽然我确实觉得第二个会起作用(保持我的手指交叉,已经花了太多时间尝试各种事情)。我喜欢它的 AOP 风格。 我在我的项目中使用了第二种解决方案,它运行顺利 @eu-ge-ne:在我看到你的代码 sn-p 之前,我一直不明白如何(或何时)使用 ActionFilters。我现在可以想象它们的许多用途。 :) 我已经将我的实现从使用类似的架构切换到您的“第一”方法,我现在正在使用 ActionFilter 方法。它工作得很好,一路上清理了我的基本控制器中的许多其他垃圾。感谢您的精彩回答! 是否可以在操作级别上设置属性,否则我是否必须实现过滤器? 是的,您可以在控制器级别或操作级别设置属性以上是关于ASP.NET MVC - 在基本控制器中为母版页设置 ViewData的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ASP.NET MVC 中的 2 个不同项目/应用程序之间共享母版页?
带有 jquery 代码的脚本块应该放在 ASP.NET MVC 母版页的啥位置?