This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can trysigning in orchanging directories.
Access to this page requires authorization. You can trychanging directories.
BySteve Smith andDave Brock
This document explains views used in ASP.NET Core MVC applications. For information on Razor Pages, seeRazor Pages architecture and concepts in ASP.NET Core.
In the Model-View-Controller (MVC) pattern, theview handles the app's data presentation and user interaction. A view is an HTML template with embeddedRazor markup. Razor markup is code that interacts with HTML markup to produce a webpage that's sent to the client.
In ASP.NET Core MVC, views are.cshtml files that use theC# programming language in Razor markup. Usually, view files are grouped into folders named for each of the app'scontrollers. The folders are stored in aViews folder at the root of the app:

TheHome controller is represented by aHome folder inside theViews folder. TheHome folder contains the views for theAbout,Contact, andIndex (homepage) webpages. When a user requests one of these three webpages, controller actions in theHome controller determine which of the three views is used to build and return a webpage to the user.
Uselayouts to provide consistent webpage sections and reduce code repetition. Layouts often contain the header, navigation and menu elements, and the footer. The header and footer usually contain boilerplate markup for many metadata elements and links to script and style assets. Layouts help you avoid this boilerplate markup in your views.
Partial views reduce code duplication by managing reusable parts of views. For example, a partial view is useful for an author biography on a blog website that appears in several views. An author biography is ordinary view content and doesn't require code to execute in order to produce the content for the webpage. Author biography content is available to the view by model binding alone, so using a partial view for this type of content is ideal.
View components are similar to partial views in that they allow you to reduce repetitive code, but they're appropriate for view content that requires code to run on the server in order to render the webpage. View components are useful when the rendered content requires database interaction, such as for a website shopping cart. View components aren't limited to model binding in order to produce webpage output.
Views help to establishseparation of concerns within an MVC app by separating the user interface markup from other parts of the app. Following SoC design makes your app modular, which provides several benefits:
Views that are specific to a controller are created in theViews/[ControllerName] folder. Views that are shared among controllers are placed in theViews/Shared folder. To create a view, add a new file and give it the same name as its associated controller action with the.cshtml file extension. To create a view that corresponds with theAbout action in theHome controller, create anAbout.cshtml file in theViews/Home folder:
@{ ViewData["Title"] = "About";}<h2>@ViewData["Title"].</h2><h3>@ViewData["Message"]</h3><p>Use this area to provide additional information.</p>Razor markup starts with the@ symbol. Run C# statements by placing C# code withinRazor code blocks set off by curly braces ({ ... }). For example, see the assignment of "About" toViewData["Title"] shown above. You can display values within HTML by simply referencing the value with the@ symbol. See the contents of the<h2> and<h3> elements above.
The view content shown above is only part of the entire webpage that's rendered to the user. The rest of the page's layout and other common aspects of the view are specified in other view files. To learn more, see theLayout topic.
Views are typically returned from actions as aViewResult, which is a type ofActionResult. Your action method can create and return aViewResult directly, but that isn't commonly done. Since most controllers inherit fromController, you simply use theView helper method to return theViewResult:
HomeController.cs:
public IActionResult About(){ ViewData["Message"] = "Your application description page."; return View();}When this action returns, theAbout.cshtml view shown in the last section is rendered as the following webpage:

TheView helper method has several overloads. You can optionally specify:
An explicit view to return:
return View("Orders");Amodel to pass to the view:
return View(Orders);Both a view and a model:
return View("Orders", Orders);When an action returns a view, a process calledview discovery takes place. This process determines which view file is used based on the view name.
The default behavior of theView method (return View();) is to return a view with the same name as the action method from which it's called. For example, theAboutActionResult method name of the controller is used to search for a view file namedAbout.cshtml. First, the runtime looks in theViews/[ControllerName] folder for the view. If it doesn't find a matching view there, it searches theShared folder for the view.
It doesn't matter if you implicitly return theViewResult withreturn View(); or explicitly pass the view name to theView method withreturn View("<ViewName>");. In both cases, view discovery searches for a matching view file in this order:
Views/\[ControllerName]/\[ViewName].cshtmlViews/Shared/\[ViewName].cshtmlA view file path can be provided instead of a view name. If using an absolute path starting at the app root (optionally starting with "/" or "~/"), the.cshtml extension must be specified:
return View("Views/Home/About.cshtml");You can also use a relative path to specify views in different directories without the.cshtml extension. Inside theHomeController, you can return theIndex view of yourManage views with a relative path:
return View("../Manage/Index");Similarly, you can indicate the current controller-specific directory with the "./" prefix:
return View("./About");Partial views andview components use similar (but not identical) discovery mechanisms.
You can customize the default convention for how views are located within the app by using a customIViewLocationExpander.
View discovery relies on finding view files by file name. If the underlying file system is case sensitive, view names are probably case sensitive. For compatibility across operating systems, match case between controller and action names and associated view folders and file names. If you encounter an error that a view file can't be found while working with a case-sensitive file system, confirm that the casing matches between the requested view file and the actual view file name.
Follow the best practice of organizing the file structure for your views to reflect the relationships among controllers, actions, and views for maintainability and clarity.
Pass data to views using several approaches:
ViewData (ViewDataAttribute)ViewBagThe most robust approach is to specify amodel type in the view. This model is commonly referred to as aviewmodel. You pass an instance of the viewmodel type to the view from the action.
Using a viewmodel to pass data to a view allows the view to take advantage ofstrong type checking.Strong typing (orstrongly typed) means that every variable and constant has an explicitly defined type (for example,string,int, orDateTime). The validity of types used in a view is checked at compile time.
Visual Studio andVisual Studio Code list strongly typed class members using a feature calledIntelliSense. When you want to see the properties of a viewmodel, type the variable name for the viewmodel followed by a period (.). This helps you write code faster with fewer errors.
Specify a model using the@model directive. Use the model with@Model:
@model WebApplication1.ViewModels.Address<h2>Contact</h2><address> @Model.Street<br> @Model.City, @Model.State @Model.PostalCode<br> <abbr title="Phone">P:</abbr> 425.555.0100</address>To provide the model to the view, the controller passes it as a parameter:
public IActionResult Contact(){ ViewData["Message"] = "Your contact page."; var viewModel = new Address() { Name = "Microsoft", Street = "One Microsoft Way", City = "Redmond", State = "WA", PostalCode = "98052-6399" }; return View(viewModel);}There are no restrictions on the model types that you can provide to a view. We recommend using Plain Old CLR Object (POCO) viewmodels with little or no behavior (methods) defined. Usually, viewmodel classes are either stored in theModels folder or a separateViewModels folder at the root of the app. TheAddress viewmodel used in the example above is a POCO viewmodel stored in a file namedAddress.cs:
namespace WebApplication1.ViewModels{ public class Address { public string Name { get; set; } public string Street { get; set; } public string City { get; set; } public string State { get; set; } public string PostalCode { get; set; } }}Nothing prevents you from using the same classes for both your viewmodel types and your business model types. However, using separate models allows your views to vary independently from the business logic and data access parts of your app. Separation of models and viewmodels also offers security benefits when models usemodel binding andvalidation for data sent to the app by the user.
ViewData,[ViewData] attribute, andViewBag)ViewBagisn't available by default for use in Razor PagesPageModelclasses.
In addition to strongly typed views, views have access to aweakly typed (also calledloosely typed) collection of data. Unlike strong types,weak types (orloose types) means that you don't explicitly declare the type of data you're using. You can use the collection of weakly typed data for passing small amounts of data in and out of controllers and views.
| Passing data between a ... | Example |
|---|---|
| Controller and a view | Populating a dropdown list with data. |
| View and alayout view | Setting the<title> element content in the layout view from a view file. |
| Partial view and a view | A widget that displays data based on the webpage that the user requested. |
This collection can be referenced through either theViewData orViewBag properties on controllers and views. TheViewData property is a dictionary of weakly typed objects. TheViewBag property is a wrapper aroundViewData that provides dynamic properties for the underlyingViewData collection. Note: Key lookups are case-insensitive for bothViewData andViewBag.
ViewData andViewBag are dynamically resolved at runtime. Since they don't offer compile-time type checking, both are generally more error-prone than using a viewmodel. For that reason, some developers prefer to minimally or never useViewData andViewBag.
ViewDataViewData is aViewDataDictionary object accessed throughstring keys. String data can be stored and used directly without the need for a cast, but you must cast otherViewData object values to specific types when you extract them. You can useViewData to pass data from controllers to views and within views, includingpartial views andlayouts.
The following is an example that sets values for a greeting and an address usingViewData in an action:
public IActionResult SomeAction(){ ViewData["Greeting"] = "Hello"; ViewData["Address"] = new Address() { Name = "Steve", Street = "123 Main St", City = "Hudson", State = "OH", PostalCode = "44236" }; return View();}Work with the data in a view:
@{ // Since Address isn't a string, it requires a cast. var address = ViewData["Address"] as Address;}@ViewData["Greeting"] World!<address> @address.Name<br> @address.Street<br> @address.City, @address.State @address.PostalCode</address>[ViewData] attributeAnother approach that uses theViewDataDictionary isViewDataAttribute. Properties on controllers or Razor Page models marked with the[ViewData] attribute have their values stored and loaded from the dictionary.
In the following example, the Home controller contains aTitle property marked with[ViewData]. TheAbout method sets the title for the About view:
public class HomeController : Controller{ [ViewData] public string Title { get; set; } public IActionResult About() { Title = "About Us"; ViewData["Message"] = "Your application description page."; return View(); }}In the layout, the title is read from the ViewData dictionary:
<!DOCTYPE html><html lang="en"><head> <title>@ViewData["Title"] - WebApplication</title> ...ViewBagViewBagisn't available by default for use in Razor PagesPageModelclasses.
ViewBag is aMicrosoft.AspNetCore.Mvc.ViewFeatures.Internal.DynamicViewData object that provides dynamic access to the objects stored inViewData.ViewBag can be more convenient to work with, since it doesn't require casting. The following example shows how to useViewBag with the same result as usingViewData above:
public IActionResult SomeAction(){ ViewBag.Greeting = "Hello"; ViewBag.Address = new Address() { Name = "Steve", Street = "123 Main St", City = "Hudson", State = "OH", PostalCode = "44236" }; return View();}@ViewBag.Greeting World!<address> @ViewBag.Address.Name<br> @ViewBag.Address.Street<br> @ViewBag.Address.City, @ViewBag.Address.State @ViewBag.Address.PostalCode</address>ViewData andViewBag simultaneouslyViewBagisn't available by default for use in Razor PagesPageModelclasses.
SinceViewData andViewBag refer to the same underlyingViewData collection, you can use bothViewData andViewBag and mix and match between them when reading and writing values.
Set the title usingViewBag and the description usingViewData at the top of anAbout.cshtml view:
@{ Layout = "/Views/Shared/_Layout.cshtml"; ViewBag.Title = "About Contoso"; ViewData["Description"] = "Let us tell you about Contoso's philosophy and mission.";}Read the properties but reverse the use ofViewData andViewBag. In the_Layout.cshtml file, obtain the title usingViewData and obtain the description usingViewBag:
<!DOCTYPE html><html lang="en"><head> <title>@ViewData["Title"]</title> <meta name="description" content="@ViewBag.Description"> ...Remember that strings don't require a cast forViewData. You can use@ViewData["Title"] without casting.
Using bothViewData andViewBag at the same time works, as does mixing and matching reading and writing the properties. The following markup is rendered:
<!DOCTYPE html><html lang="en"><head> <title>About Contoso</title> <meta name="description" content="Let us tell you about Contoso's philosophy and mission."> ...ViewData andViewBagViewBagisn't available by default for use in Razor PagesPageModelclasses.
ViewDataContainsKey,Add,Remove, andClear.ViewData["Some Key With Whitespace"]string must be cast in the view to useViewData.ViewBagMicrosoft.AspNetCore.Mvc.ViewFeatures.Internal.DynamicViewData, so it allows the creation of dynamic properties using dot notation (@ViewBag.SomeKey = <value or object>), and no casting is required. The syntax ofViewBag makes it quicker to add to controllers and views.@ViewBag.Person?.NameViewData orViewBagBothViewData andViewBag are equally valid approaches for passing small amounts of data among controllers and views. The choice of which one to use is based on preference. You can mix and matchViewData andViewBag objects, however, the code is easier to read and maintain with one approach used consistently. Both approaches are dynamically resolved at runtime and thus prone to causing runtime errors. Some development teams avoid them.
Views that don't declare a model type using@model but that have a model instance passed to them (for example,return View(Address);) can reference the instance's properties dynamically:
<address> @Model.Street<br> @Model.City, @Model.State @Model.PostalCode<br> <abbr title="Phone">P:</abbr> 425.555.0100</address>This feature offers flexibility but doesn't offer compilation protection or IntelliSense. If the property doesn't exist, webpage generation fails at runtime.
Tag Helpers make it easy to add server-side behavior to existing HTML tags. Using Tag Helpers avoids the need to write custom code or helpers within your views. Tag helpers are applied as attributes to HTML elements and are ignored by editors that can't process them. This allows you to edit and render view markup in a variety of tools.
Generating custom HTML markup can be achieved with many built-in HTML Helpers. More complex user interface logic can be handled byView Components. View components provide the same SoC that controllers and views offer. They can eliminate the need for actions and views that deal with data used by common user interface elements.
Like many other aspects of ASP.NET Core, views supportdependency injection, allowing services to beinjected into views.
Isolate CSS styles to individual pages, views, and components to reduce or avoid:
To add ascoped CSS file for a page or view, place the CSS styles in a companion.cshtml.css file matching the name of the.cshtml file. In the following example, anIndex.cshtml.css file supplies CSS styles that are only applied to theIndex.cshtml page or view.
Pages/Index.cshtml.css (Razor Pages) orViews/Index.cshtml.css (MVC):
h1 { color: red;}CSS isolation occurs at build time. The framework rewrites CSS selectors to match markup rendered by the app's pages or views. The rewritten CSS styles are bundled and produced as a static asset,{APP ASSEMBLY}.styles.css. The placeholder{APP ASSEMBLY} is the assembly name of the project. A link to the bundled CSS styles is placed in the app's layout.
In the<head> content of the app'sPages/Shared/_Layout.cshtml (Razor Pages) orViews/Shared/_Layout.cshtml (MVC), add or confirm the presence of the link to the bundled CSS styles:
<link rel="stylesheet" href="~/{APP ASSEMBLY}.styles.css" />In the following example, the app's assembly name isWebApp:
<link rel="stylesheet" href="WebApp.styles.css" />The styles defined in a scoped CSS file are only applied to the rendered output of the matching file. In the preceding example, anyh1 CSS declarations defined elsewhere in the app don't conflict with theIndex's heading style. CSS style cascading and inheritance rules remain in effect for scoped CSS files. For example, styles applied directly to an<h1> element in theIndex.cshtml file override the scoped CSS file's styles inIndex.cshtml.css.
Note
In order to guarantee CSS style isolation when bundling occurs, importing CSS in Razor code blocks isn't supported.
CSS isolation only applies to HTML elements. CSS isolation isn't supported forTag Helpers.
Within the bundled CSS file, each page, view, or Razor component is associated with a scope identifier in the formatb-{STRING}, where the{STRING} placeholder is a ten-character string generated by the framework. The following example provides the style for the preceding<h1> element in theIndex page of a Razor Pages app:
/* /Pages/Index.cshtml.rz.scp.css */h1[b-3xxtam6d07] { color: red;}In theIndex page where the CSS style is applied from the bundled file, the scope identifier is appended as an HTML attribute:
<h1 b-3xxtam6d07>The identifier is unique to an app. At build time, a project bundle is created with the convention{STATIC WEB ASSETS BASE PATH}/Project.lib.scp.css, where the placeholder{STATIC WEB ASSETS BASE PATH} is the static web assets base path.
If other projects are utilized, such as NuGet packages orRazor class libraries, the bundled file:
CSS preprocessors are useful for improving CSS development by utilizing features such as variables, nesting, modules, mixins, and inheritance. While CSS isolation doesn't natively support CSS preprocessors such as Sass or Less, integrating CSS preprocessors is seamless as long as preprocessor compilation occurs before the framework rewrites the CSS selectors during the build process. Using Visual Studio for example, configure existing preprocessor compilation as aBefore Build task in the Visual Studio Task Runner Explorer.
Many third-party NuGet packages, such asAspNetCore.SassCompiler, can compile SASS/SCSS files at the beginning of the build process before CSS isolation occurs, and no additional configuration is required.
CSS isolation permits configuration for some advanced scenarios, such as when there are dependencies on existing tools or workflows.
In this section, the{Pages|Views} placeholder is eitherPages for Razor Pages apps orViews for MVC apps.
By default, scope identifiers use the formatb-{STRING}, where the{STRING} placeholder is a ten-character string generated by the framework. To customize the scope identifier format, update the project file to a desired pattern:
<ItemGroup> <None Update="{Pages|Views}/Index.cshtml.css" CssScope="custom-scope-identifier" /></ItemGroup>In the preceding example, the CSS generated forIndex.cshtml.css changes its scope identifier fromb-{STRING} tocustom-scope-identifier.
Use scope identifiers to achieve inheritance with scoped CSS files. In the following project file example, aBaseView.cshtml.css file contains common styles across views. ADerivedView.cshtml.css file inherits these styles.
<ItemGroup> <None Update="{Pages|Views}/BaseView.cshtml.css" CssScope="custom-scope-identifier" /> <None Update="{Pages|Views}/DerivedView.cshtml.css" CssScope="custom-scope-identifier" /></ItemGroup>Use the wildcard (*) operator to share scope identifiers across multiple files:
<ItemGroup> <None Update="{Pages|Views}/*.cshtml.css" CssScope="custom-scope-identifier" /></ItemGroup>The scoped CSS file is generated at the root of the app. In the project file, use theStaticWebAssetBasePath property to change the default path. The following example places the scoped CSS file, and the rest of the app's assets, at the_content path:
<PropertyGroup> <StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath></PropertyGroup>To opt out of how framework publishes and loads scoped files at runtime, use theDisableScopedCssBundling property. When using this property, other tools or processes are responsible for taking the isolated CSS files from theobj directory and publishing and loading them at runtime:
<PropertyGroup> <DisableScopedCssBundling>true</DisableScopedCssBundling></PropertyGroup>When aRazor class library (RCL) provides isolated styles, the<link> tag'shref attribute points to{STATIC WEB ASSET BASE PATH}/{PACKAGE ID}.bundle.scp.css, where the placeholders are:
{STATIC WEB ASSET BASE PATH}: The static web asset base path.{PACKAGE ID}: The library'spackage identifier. The package identifier defaults to the project's assembly name if the package identifier isn't specified in the project file.In the following example:
_content/ClassLib.ClassLib.Pages/Shared/_Layout.cshtml (Razor Pages) orViews/Shared/_Layout.cshtml (MVC):
<link href="_content/ClassLib/ClassLib.bundle.scp.css" rel="stylesheet">For more information on RCLs, see the following articles:
For information on Blazor CSS isolation, seeASP.NET Core Blazor CSS isolation.
Was this page helpful?
Need help with this topic?
Want to try using Ask Learn to clarify or guide you through this topic?
Was this page helpful?
Want to try using Ask Learn to clarify or guide you through this topic?