abenci
abenci

Reputation: 8651

ViewBag.Title vs. Page.Title in ASP.NET MVC 3

Why sometimes @ViewBag.Title contains the right page title while @Page.Title is null? We are debugging our View/Layout code and we noticed this difference.

Thanks.

Upvotes: 1

Views: 8997

Answers (2)

Ben Janecke
Ben Janecke

Reputation: 157

When your are using asp.Net MVC you have a few tools you can use to get data to your page.

  1. The model you send to the view.
  2. The ViewBag.
  3. TempData.
  4. Cookies.
  5. Session.

Each one of theese has their own use cases The example we will be using is a basic List and update View For a collection of companies

The Model

The model Should be used whenever you have a defined dataset being sent to a view and should contain the primary data for the page and usally a model is specific to a page or controller.

The ViewBag

The ViewBag should be used whenever you need to send general data to a page that is not defined on the model or data that is used across your view tree.

Temp Data

Temp Data is as the name states storage for temporary data this should be used in cases where you are unsure if the data will reach its destination or when you want to pass data between actions without adding parameters.

Cookies

Cookies are like Global variables the host data across your entire application.

Session

Sessions like cookies are global variables but differ in their lifetime sessions can be used for things like Storing form data between requests dont use session to do this rather use something like http://garlicjs.org/

Lets look at the example We have the following ViewModel

public class Company 
{
  public int? id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
}

The layout page looks like this

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    //This looks for the Title property on the ViewBag and inserts it in the title tags
    <title>@ViewBag.Title</title>
</head>
<body>
   @Html.Action("Header", "PageElements")
   @RenderBody()
</body>
</html>

The Header Action on the PageElements Contoller looks like this

public PartialViewResult Header()
{
  ViewBag.CurrentLink = HttpContext.Current.Request.Cookies["CurrentLink"];

  return PartialView();
}

The Header Partial View looks like this

<header>
   <ul> 
      <li class="@(ViewBag.CurrentLink == "Home" ? "Current" : "")"> 
          @Html.ActionLink("Home", "Index", "Home")
      </li>
      <li  class="@(ViewBag.CurrentLink == "Companies" ? "Current" : "")"> 
          @Html.ActionLink("Companies", "Index", "Companies")
      </li>
   </ul>
</header>

The controller action for update looks like this

public ViewResult Update(int id)
{  

  //Gets a company from the database
  var model = db.GetCompany(id);

  //Sets The Title property on the ViewBag to Update : CompanyName
  ViewBag.Title = String.Format("Update : {0}", model.Name);  

  //Sends the company to the view
  return View(model);
}

The update view looks like this

@model Application.Models.Company
@{
   Layout = "_layout.cshtml";
}

@using (Html.BeginForm())
{ 
   @Html.HiddenFor(model => Model.id)

   @Html.LabelFor(model => Model.Name)
   @Html.TextBoxFor(model => Model.Name)

   @Html.LabelFor(model => Model.Description)
   @Html.TextAreaFor(model => Model.Description)
   <button>Submit</button>
}

The Post Action for Update looks like this

[HttpPost]
public ActionResult Update(Company model)
{ 
  //Attempts to update the model 
  if (model.Update())
  {
     //Set the message to update succeeded
     TempData["Message"] = String.Format("{0} Successfully updated");
  }
  else   
  {
     //Set the message to update failed
     TempData["Message"] = String.Format("{0} filed to update");
  } 

  return RedirectToAction("Index");
}

The Controller action for companies looks like this

public ViewResult Index()
{
  //Index is the entrypoint for companies so we set the currentlink to companies while we are in companies
  HttpContext.Current.Request.Cookies["CurrentLink"] = "Companies";      

  //Gets the success or failure message from the temp data
  ViewBag.Message = TempData["Message"]; 

  //Sets The Title property on the ViewBag to List of companies
  ViewBag.Title = "List of companies";

  var model = db.GetAllCompanies();

  return View(model);
}

The view for the list looks like this

@model IEnumrable<Application.Models.Company>
@{
   Layout = "_layout.cshtml";
}
<span>@ViewBag.Message</span>
<ul>
@foreach (var company in Model) 
{
  <li>@company.Name : @company.Description @Html.AnchorLink("Edit", "Update", new { company.id}) </li>
}
</ul>

Lets discuss how the flow of this application works

  1. The Index Action gets triggered on companies.
  2. We set the current link to companies in a Cookie
  3. Then we set the Title in the ViewBag
  4. We check the TempData for messages and put them into the ViewBag
  5. Then we put the collection of companies into a Model and send it to the page.
  6. Now razor kicks in and starts renders the page first
  7. Then the layout renders and gets the Title value from the ViewBag
  8. Then the header partial view renders and gets the currentlink value from a Cookie
  9. We click the update button for a company
  10. The update action runs
  11. Gets the company from a database and sends it to the view in a Model
  12. We change the title to update in the ViewBag
  13. The page renders first and puts the company data on the form, from the Model
  14. Then the layout renders and Gets the title value from the ViewBag
  15. Then the header renders and gets the currentlink from a cookie (the value is still companies we did not have to change it)
  16. Then we submit the form and add a message to the TempData
  17. now we are back at the company list and we can get the success or failure message from the TempData

We used the Model to send Specific data to the view. We used the ViewBag to send General data to the view and the layout. We used TempData to pass data between actions without using parameters. We used Cookies to Store data that wouldn't change for a while.

Upvotes: 9

Felipe Oriani
Felipe Oriani

Reputation: 38608

The correct is using ViewBag.Title, because it is on the context of your ViewBag property of your View while Page.Title is something that comes from asp.net webforms. That is the reason why Page.Title is null, there is no context for it.

Upvotes: 4

Related Questions