Learn

Most web apps have a common layout that provides the user with a consistent experience as they navigate from page to page. Certain layouts may include a header, footer, menus, and so on, that may be shared amongst different pages.

Let’s say we’re building an application that contains a header throughout most (if not all) of your pages. If we’re creating the markup for all these pages, the header will still need to be added to each one. That’s a lot of copy-pasting if the header does not change. We can avoid redundancy by essentially storing the header somewhere separate and rendering its content on each page. If our website needs an update we can simply change a single file and the changes will be reflected everywhere the content has been inserted.

Standard practice is to specify the location of the main layout page in the _ViewStart.cshtml file. This file is automatically generated under /Pages when we create a template with ASP.NET and it looks like this:

@{ Layout = "_Layout"; }

Here, we’re directing our app to use the _Layout file as the main layout for all of our content. But where is _Layout coming from? Well, Razor Pages searches by walking up the directory tree from the location of the calling page looking for the filename specified, followed by the /Pages/Shared folder. In this case, our generated template has a _Layout.cshtml file under /Pages/Shared.

Once we specify the location of the layout page, that layout will affect all content pages. You can think of this layout as the main layout that’s used throughout your whole application.

By convention, layout pages use a leading underscore in their filename: _Layout.cshtml.

In the generated Razor Pages template the _Layout.cshtml file will contain a method call, @RenderBody() within the <body> tags:

<div class="container"> <main role="main" class="pb-3"> @RenderBody() </main> </div>

When we work on our own view pages, the content will be rendered wherever @RenderBody() is being called on the layout page.

One other advantage of sharing pages this way is that we can use our handy ViewData dictionary and pass data down into our layout page! Let’s say that different pages in our app will have their own title tags. We can create a ViewData key/value pair set to title as the property, and unique titles as the values for different pages:

About.cshtml

@{ ViewData["Title"] = "About"; }

With our key/value pair defined, all we need to do is simply call the property in our Layout page as so:

<title>@ViewData["Title"] - Razor App</title>

Our Layout will render the value for the title of the page depending on where it’s defined, this allows us to avoid creating unnecessary properties in our PageModel and save us some space!

We don’t always have to use the main layout provided for all of our content. If we want to specify our own layout pages we can do this at the top of our content page. Razor is smart enough to search through a set of predefined locations so we don’t need to provide the whole path of where our layout is located. The filename (.cshtml not needed) should suffice:

@{ Layout = "_NewLayout"; }

Instructions

1.

If we look at both the Privacy and Index page, there’s still some code being duplicated! Let’s consolidate this and add it to our layout page.

  1. Remove the footer and header content from Privacy.cshtml
  2. Remove the footer and header content from Index.cshtml
  3. Add the footer and header content in the appropriate place in_Layout.cshtml.
2.

Now that we have refactored our code, we can define what Layout the application should use.

Navigate to _ViewStart.cshtml

Open some code blocks and assign the Layout property to "_Layout" so it’s executed upon each rendered view page.

3.

The application crashed! Let’s go ahead and fix that.

At the moment the layout page, _Layout.cshtml is not running because it’s missing the required RenderBody() method.

Add a @RenderBody() method between the footer element and the header element. Otherwise, it won’t render any content from other pages!

4.

Let’s make use of ViewData to see how its properties can be shared amongst pages.

In _Layout.cshtml, below your RenderBody() method call, create an <h1> heading and access the ViewData["Title"] property in order to display the following in the Privacy and Home page.

Greetings from the Home page!
Greetings from the Privacy Policy page!

NOTE: You’ll only be adding the line once.

5.

We can now run our application and see what occurred. Run the app and try clicking on the navigation links you added in the header and the footer. You’ll notice that even when changing pages, we’re still having the same content being produced! This is because our main layout page is being executed on every rendered view page. Take note that the only content changing is the actual markup that was provided in Privacy.cshtml and Index.cshtml. This is being rendered wherever RenderBody() is called.

Sign up to start coding

Mini Info Outline Icon
By signing up for Codecademy, you agree to Codecademy's Terms of Service & Privacy Policy.

Or sign up using:

Already have an account?