I'm creating an ASP.NET MVC4 web site with Forms authentication and am encountering difficulties in the correct way to include multiple models within a view.
Specifically, there is a model that belongs to a given view, say "CartModel". However, given the current UI of the site, there is a model used within a partial view that is included in the master layout view with information about the currently logged in user.
My current approach for solving this issue is to include the LoginModel as a part of every view model. However, this seems repetitive and doesn't work correctly.
What is the most correct way to resolve an issue such as this?
There are two ways to make it accessible.
OnActionExecuting method in a base controller your controllers all derive from) that add a models you need to ViewBag/ViewData.WebViewPage to expose the models, but you'll still need to populate it. Thus, it may need to access your APIs, and done correctly, would probably require some dependency injection.public abstract MyBaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (User != null && User.Identity.IsAuthenticated) // check if user is logged in if you need to
{
ViewBag.LoginModel = /* add data here */;
}
}
}
Then use it as the base class (or somewhere further up the inheritance):
public MyController : MyBaseController
{
//etc.
}
PopulateLoginModelAttribute : ActionFilterAttribute, IActionFilter
{
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User != null && filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Controller.ViewBag.LoginModel = /* add data here */;
}
this.OnActionExecuting(filterContext);
}
}
Then decorate a controller class, action method, or add as a global filter.
[PopulateLoginModel] // will be applied to all actions in this controller
public class MyController : Controller // note you can use the normal base type, or whatever you need
{
public ActionResult MyView()
{
return View(new CartModel());
}
}
ViewBag in referenced partials, layouts, etc., but keep using Model for the action's view.Access the ViewBag normally in your view (also accessible to layouts, and I made up a property value on LoginModel type to illustrate):
<span>@ViewBag.LoginModel.Name</span> <!-- available because of the filter !-->
Number of items in your cart: @Model.Items.Count <!-- the model provided by the action method !-->
ViewBag.LoginModel will be available for all actions that derive from this controller without extra work. I'd recommend making it an attribute as it will give you more flexibility with base classes and to which controllers/actions you want to apply it to.
It is less likely you'll want to use your own WebPageView base class. If you want to add members to assist in working through data or whatever for a view, it's great for that. But it's not the right place to add to or otherwise manipulate viewdata or the model, although it's possible.
public abstract class MyWebViewPage<T> : WebViewPage<T>
{
protected LoginModel GetLoginModel()
{
// you could resolve some dependency here if you need to
return /* add data here */
}
}
Make sure your web.config in the views folder is updated correctly.
<span>@GetLoginModel().Name</span>
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