带有Initialize()的ASP.NET MVC Base Controller使用HTml.Action()多次执行

时间:2015-02-16 13:16:51

标签: c# asp.net asp.net-mvc asp.net-mvc-4

这是关于ASP.NET MVC中最佳实践的问题

我在MVC中创建了一个网站。因为每个页面都有一个菜单,我想我会创建一个基本控制器类,项目中的所有MVC控制器都继承该类。在基本控制器类的Initialize()函数中,我将加载我的菜单。 通过这种方式,我可以保留我在一个地方加载菜单的逻辑并让它自动执行。

代码(C#):

public abstract class BaseController : System.Web.Mvc.Controller
{
    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        //Load the menu:
        ViewBag.HeaderModel = LoadMenu();
    }
}

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        //the menu is loaded by the base controller, so we can just return the view here
        return View();
    }
}

这就像一个魅力。现在问题就在于此。

在我的视图中,我列出了网站上最新的五篇文章。由于文章在网站上有自己的逻辑和自己的部分,我创建了一个ArticleController,它继承自BaseController,其动作用我的五篇最新文章显示PartialResult。

public class ArticlesController : BaseController
{
    public ActionResult DisplayLatestArticles()
    {
       var model = ... //abbreviated, this loads the latest articles
       return PartialView("LatestArticles", model);
    }
}

在View:

中调用此方法
@Html.Action("Index", new { controller = "Articles" })

但这有一个缺点:即我的基本控制器上的Initialize()函数执行两次,这会将菜单加载两次,这是不可取的(出于性能原因)。到目前为止,我还没有办法避免这种行为。

在重构此代码方面,您有什么建议?我想确保加载我的菜单的逻辑停留在某处,以便自动调用它,而我或项目中的任何其他开发人员都不必担心它。我更喜欢保持我的逻辑以显示ArticlesController中的最新文章,所以与文章有关的一切都保存在自己的Controller中。

那么,如何最好地继续?

2 个答案:

答案 0 :(得分:5)

您尝试执行的操作更适合从_Layout.cshtml页面调用标题菜单。

<强> _Layout.cshtml

<html>
...
  <body>
...
    @Html.Action("Header", "SharedStuff")
...

<强> SharedStuffController.cs

public ActionResult Header()
{
    // logic to create header, also create a view
    return this.View();
}

基本控制器,我觉得,通常是错误的方式。上面的意思是你保持标题的所有逻辑很好地包含在描述它的东西中。

答案 1 :(得分:0)

我不是MVC的专家,在寻找我自己的答案时登陆了这个页面。我完全同意Base contoller不应该用于生成菜单项。但是,出于某种原因,如果你想继续使用基本控制器,我建议返回部分视图的控制器(即ArticlesController)不应该从基本控制器继承,它应该从Controller类继承。