ASP.NET MVC - 为基本控制器中的母版页设置ViewData

时间:2009-06-10 15:52:41

标签: asp.net-mvc controller master-pages

我在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 个答案:

答案 0 :(得分:45)

我看到两个选项:

<强>首先

在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
{
    ...
}

我认为第二种解决方案完全符合您的情况。