There are many cases need to extract data based on the request context and show something on layout pages. For example:
- You may want to show logged-in user info
- You may want to show number of visitors or online visitors
- You you may want to show the current language and let the user to change the language.
- You may want to load site menu or side-bar or footer from database
To do so you can consider the following points:
Partial View: You can create some small partial views for those parts having a specific model for each partial view and render them in the layout page.
Use context to get data: You can initialize the model by extracting information from Request
, ViewContext
, RouteData
, ValueProvider
and other context objects.
Access to data by HTML Helpers: You can create a HtmlHelper
to get data from context and use the helper in the layout or partial views.
Access to data by dependency injection: You can define some services for extracting data and then inject those data to layout pages. In the service, you will initialize the model using context objects. If you are using ASP.NET CORE, this is a good way to go.
Access to data as property of base controller: You can have a property in the base controller and initialize it in constructor of the controller or in OnActionExecuting
. Then in the layout, get the property by casting ViewContext.Controller
to type of your base controller and read the property.
Access to data by ViewBag: You can initialize an instance of the model in constructor of a base controller or in OnActionExecuting
method of the base controller and then put it in ViewBag. Then you can easily use it in view.
Layout Pages: Don't forget you can define different layout pages and use different layouts based on your requirement. You can set the layout in the action or in _ViewStart
.
Example
Trying to resolve id in each request, means you need to have id as part of all requests or you need to know what should you do in absence of id. Considering this fact and to keep things simple for a minimal example, I'll define the following model and base controller and try to resolve id in OnActionExecuting
method of the base controller and then will derive all my controllers which needs such behavior from this base controller.
You can do the same using an ActionFilter
or a global action filter of the OnActionExecuting
method of your controller.
Using the following code:
- If you browse
/home/index
you will see a red bar at bottom of the page.
- If you browse
/home/index/1
you will see a blue bar at the bottom of the page
- If you browse
/home/index/2
you will see a green bar at the bottom of the page
Layout Model
public class LayoutViewModel
{
public int? Id { get; set; }
public string Color { get; set; }
}
Base Controller
public class BaseControllr : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Get the id from route
var id = int.TryParse(ValueProvider.GetValue("id")?.AttemptedValue, out var temp)
? temp : default(int?);
var model = new LayoutViewModel();
//Your logic to initialize the model, for example
model.Id = id;
if (model.Id == null)
model.Color = "FF0000";
else if (model.Id%2==0)
model.Color = "00FF00";
else
model.Color = "0000FF";
//Set ViewBag
ViewBag.MainLayoutViewModel = model;
base.OnActionExecuting(filterContext);
}
}
Home Controller
public class HomeController : BaseControllr
{
public ActionResult Index(int? id)
{
return View();
}
}
_Layout.cshtml
Then in the _Layout.cshtml
, add the following code before closing <body/>
tag for test:
@{
string color = ViewBag.MainLayoutViewModel?.Color;
int? id = ViewBag.MainLayoutViewModel?.Id;
}
<div style="background-color:#@color;">
Id:@id
</div>