Cornwell
Cornwell

Reputation: 3410

Putting a model on every view

I'm trying to pass my UserModel to every view, so it can show on top the current user information.

This is my BaseViewModel:

public class BaseViewModel
{
    public UserModel currentUser { get; set; }
}

BaseController:

public class BaseController : Controller
{
    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        UserRepository userRep = new UserRepository();
        BaseViewModel model = new BaseViewModel
        {
            currentUser = userRep.getCurrentUser()
        };
        base.OnActionExecuted(filterContext);
    }
}

HomeController: (default)

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        ListRepository listRep = new ListRepository();
        return View(listRep.GetAllLists());//returns IEnumerable<ListModel>
    }
}

My shared _layout.cshtml:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - My ASP.NET Application</title>
    @Styles.Render("~/Public/css")
</head>
<body>
        <header>
            @Html.Partial("_Header")
        </header>
    @RenderBody()
</body>
</html>

and finally, my _Header.cshtml:

<div id="logo">
    <h1>Hello @Model.currentUser.username</ h1 >
</div>

But I get this error message when I run it:

'System.Collections.Generic.List' does not contain a definition for 'currentUser'

I thought my BaseViewModel would always get appended

Upvotes: 1

Views: 93

Answers (3)

Deepak Kumar
Deepak Kumar

Reputation: 683

Another possible solution using BaseController.

Instantiate your BaseViewModel model in OnResultExecuting method instead of OnActionExecuted. And save the model in ViewData to access it in _Header partial view.

E.g.

public class BaseController : Controller
    {
        protected override void OnResultExecuting(ResultExecutingContext filterContext)
        {
        UserRepository userRep = new UserRepository();
        BaseViewModel model = new BaseViewModel
        {
            currentUser = userRep.getCurrentUser()
        };
        filterContext.Controller.ViewData["customData"] = model;
        }
    }

Now you need to pass ViewData to _Header partial view.

E.g.

@Html.Partial("_Header", ViewData["customData"])

In _Header partial view, you can simply access the data.

<div id="logo">
    <h1>Hello @Model.currentUser.username</ h1 >
</div>

Upvotes: 0

Shyju
Shyju

Reputation: 218852

If you want that in every view, you may consider calling a child action method using Html.Action.

So replace

<header>@Html.Partial("_Header")</header>

with

<header>@Html.Action("Header","YourControllerName")</header>

Now have an action method called Header where you will pass the needed data to it's partial view

[ChildActionOnly]
public ActionResult Header()
{
  var vm = new YourHeaderViewModel();
  vm.UserName="Shyju"; // Replace with whatever you want.
  return PartialView(vm);
}

Where YourHeaderViewModel is your view mode for the header with the properties needed for the header.

public class YourHeaderViewModel
{
  public string UserName {set;get;}
}

Now in your Header partial view which is strongly typed to the YourHeaderViewModel class,

@model YourHeaderViewModel
<div id="logo">
    <h1>Hello @Model.UserName</ h1 >
</div>

Upvotes: 2

user3559349
user3559349

Reputation:

The model in the view is IEnumerable<ListModel> and that is what will be passed to the partial unless you specify a model, for example, using

@Html.Partial("_Header", someOtherModel)

Instead, create a ChildActionOnly method that returns your user data to the _Header.cshtml partial view and in the main view use @Html.Action() to render it

[ChildActionOnly]
public ActionResult _Header()
{
   var model = .... // get the model you want to render in the partial
   return PartialView(model);
}

and in the main view

@{ Html.RenderAction("_Header", controllerName); }

Upvotes: 2

Related Questions