简体   繁体   中英

ASP.NET MVC Base Controller with Initialize() gets executed multiple times with HTml.Action()

This is a question about best-practices in ASP.NET MVC

I've created a website in MVC. Because every page has a menu, I thought I'd create a base controller class which all MVC Controllers in the project inherit from. In The Initialize() function of the base controller class I would then load my Menu. In that way, I could keep my logic for loading the menu in one place and have it executed automatically.

Code (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();
    }
}

That works like a charm. Now here's the problem.

In my View, I present a list of the five latest Articles on the website. Since the Articles have their own logic and their own section on the website, I've created an ArticleController, which inherits from BaseController as well, with an action that displays a PartialResult with my five latest Articles.

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

And the method is called like this in the View:

@Html.Action("Index", new { controller = "Articles" })

But this has one drawback: namely the Initialize() function on my Base Controller is executed twice, which loads the menu two times, which is undesirable (for performance reasons). So far I haven't been able to find a way to avoid this behavior.

What do you suggest in so far as refactoring this code? I want to make sure my logic to load my menu stays somewhere so it gets called automatically, without me or any other developers on the project having to worry about it. I prefer keeping my logic to display the latest Articles in the ArticlesController so everything to do with Articles is kept in its own Controller.

So, how best to proceed?

What you're trying to do is more suited to calling your header menu from a _Layout.cshtml page.

_Layout.cshtml :

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

SharedStuffController.cs

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

Base controllers, I feel, are normally the wrong way to go. The above means that you keep all logic for the header nicely contained in something that describes it.

I am not expert on the MVC and landed on this page while searching for my own answer. I completely agree that Base contoller should not be used for generating menu items. However, for what so ever reason, if you wanted to continue using base controller, I would suggest the controller that returns partial views (ie ArticlesController) should not inherit from base controller and it should inherit from Controller class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM