I currently have a MVC site that needs to have dynamic content on the header of every page.
I currently get the required data as normal in the controller and place it in a View Model. In the view, I take the data and stick the template parts in to the Viewbag and finally, on the main layout page, I take the Viewbag data and pass it to the partial which controls the header.
I've read that I shouldn't use Viewbag where possible, and the amount of times I pass the data round just doesn't feel right.
The only way I can think of to improve this is to create a section on the main layout, and then put the partial/data in the section of the view - however, there are ~30 pages and this again doesn't feel like the correct route.
Is there a better way to do this/what are the best practices for taking dynamic data that has to go to the main view?
You can do this with Child Actions. You can reuse this action and even include it in the _Layout page.
Here's a child action to display some header info. It is marked ChildActionOnly
so it can only be called within another view. It also takes advantage of OutputCache
to save a result for 5 minutes.
[ChildActionOnly]
[OutputCache(Duration = 5 * 60)]
public ActionResult Header(string section)
{
var info = new HeaderInfo
{
Section = section,
Today = DateTime.Now
};
return PartialView("_header", info);
}
_header.cshtml
@model HeaderInfo
<div>
<span>@Model.Section</span>
<span>@Model.Today.ToLongTimeString()</span>
</div>
Then use this in a view or layout with Html.Action() or .RenderAction().
@Html.Action("Header", "Home", new { section = "Cake" })
// or
@{Html.RenderAction("Header", "Home", new { section = "Pie" });}
You can specify a section inside your layout then conditionally render if present in the view.
_Layout.cshtml
@RenderSection("header", required: false)
main view
@section header {
@{Html.RenderAction("Header", "Home", new { section = "Cake" })}
}