Following the NerdDinners example, I am interested in creating a strongly typed Master Page. In order to achieve this, I use a base controller which retrieves the data for the master page. All other controllers inherit this class. Similarly, I have ViewModels
for the master page and any other views. The view ViewModel
classes inherit from the master page's ViewModel
.
How should a child controller ensure that the master page's data is passed to the View without setting the properties of its ViewModel
that pertain to the master page itself?
My the master page will display a number of buttons, which are determined in an XML file, hence the Buttons
class that I am populating.
MasterPage ViewModel Code Snippet
using System.Collections.Generic;
namespace Site1.Models
{
public class MasterViewModel
{
public List<Button> Buttons{set; get;}
}
}
View ViewModel
namespace Site1.Models
{
public class View1ViewModel : MasterViewModel
{
public SomeDataClass SomeData { get; set; }
}
}
using System.Collections.Generic;
using System.Web.Mvc;
using Site1.Models;
namespace Site1.Controllers
{
public abstract class BaseController : Controller
{
protected MasterViewModel model = new MasterViewModel();
public BaseController()
{
model.Buttons = new List<Button>();
//populate the button classes (doesn't matter how)
PopulateButtons(model.Buttons);
}
}
}
View's controller:
using System.Web.Mvc;
namespace Site1.Controllers
{
public class View1Controller : BaseController
{
public ActionResult Index()
{
Models.View1ViewModel viewModel = new Models.View1ViewModel();
SomeDataClass viewData = new SomeDataClass()
//populate data class (doesn't matter how)
PopulateDataClass(viewData);
viewModel.SomeData = viewData;
//I WANT TO ELIMINATE THE FOLLOWING LINE!
viewModel.Buttons = model.Buttons;
return View("Index", viewModel);
}
}
}
The master page inherits System.Web.Mvc.ViewMasterPage<Site1.Models.MasterViewModel>
.
The view inherits System.Web.Mvc.ViewMasterPage<Site1.Models.View1ViewModel>
.
In addition to supporting partial views, ASP.NET MVC also supports the ability to create "master page" templates that can be used to define the common layout and top-level html of a site.
The ASP.NET Core provides the ability to pass strongly typed models or objects to a view. This approach helps us with the intellisense and better compile-time checking of our code. The scaffolding mechanism in Visual Studio can be used to create the View.
You could create an after action executed filter which looks for a model of that type and sets the properties accordingly, perhaps by calling a base controller function. You would then put the filter on the base class, and all actions would see it automatically.
The action filter attribute gets the controller's ViewModel
, and passes it to the controller's SetModel
function:
using System.Web.Mvc;
using Site1.Controllers;
namespace Site1.Models
{
public class MasterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
MasterViewModel viewModel = (MasterViewModel)((ViewResultBase)filterContext.Result).ViewData.Model;
BaseController controller = (BaseController)filterContext.Controller;
controller.SetModel(viewModel);
}
}
}
This function is added to the BaseController
:
public void SetModel(MasterViewModel childViewModel)
{
childViewModel.Buttons = model.Buttons;
}
Rather than creating an attribute, why not just override Controller.OnActionExecuted and put the initialization code there? Seems a bit simpler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With