ASP.NET MVC 是微软官方提供的以MVC模式为基础的ASP.NET Web应用程序(Web Application)框架,它由Castle的MonoRail而来。
MVC 编程模式
MVC 是三种 ASP.NET 编程模式中的一种。
MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式。
(1)Model(模型)表示应用程序核心(比如数据库记录列表)。
(2)View(视图)显示数据(数据库记录)。
(3)Controller(控制器)处理输入(写入数据库记录)。
MVC 模式同时提供了对 HTML、CSS 和 JavaScript 的完全控制。Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
新建一个ASP.NET MVC4应用程序,结构如下图所示:
对各个文件夹的说明:
(1)App_Data 文件夹用于存储应用程序数据。
(2)Content 文件夹用于存放静态文件,比如样式表(CSS 文件)、图标和图像。
(3)Controllers 文件夹包含负责处理用户输入和相应的控制器类。
(4)Models 文件夹包含表示应用程序模型的类。模型控制并操作应用程序的数据。
(5)Views 文件夹用于存储与应用程序的显示相关的 HTML 文件(用户界面)。
(6)Scripts 文件夹存储应用程序的 JavaScript 文件。
下面就主要的Controller、Model和View做出说明。
一、控制器
1、描述
控制器(Controller)主要负责响应用户的输入,并在响应时修改模型(Model)。通过这种方式,控制器主要关注的是应用程序流、输入数据的处理,以及对相关视图(View)输出数据的提供。
2、简单控制器
新建一个ASP.NET MVC4应用程序,会自动生成一个HomeController和AccountController。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; return View(); } } }
直接按F5运行程序即可看到index试图中的内容,此时浏览器的URL为:
http://localhost:4573,或者修改浏览器地址为:
http://localhost:4573/home
http://localhost:4573/home/index
程序默认会托管在VS2013自带的IIS中,采用的端口号为4573。如果程序托管在MyWeb.com中,则URL应为:
http://MyWeb.com/home/index。
3、控制器操作中的参数
前面的例子Action中返回的是字符串常量,下面就让它们通过相应URL传进来的参数动态地执行操作。
在这里,我们使用HttpUtility.HtmlEncode来预处理用户输入。这样就能阻止用户用链接向视图中注入JavaScriptd代码或HTML标记,比如/home/sayhello?content=<script>window.location='http://www.baidu.com'</script>。
public string SayHello(string content) { string message = HttpUtility.HtmlEncode("Hello " + content); return message; }

4、路由---将URL映射到动作
框架是如何知道将URL映射到一个特定的控制动作的?答案就在Global.asax文件的RegisterRoutes方法中。该方法定义了将一个URL模式映射到控制器或动作的路由。
using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace MvcApplication1 { // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明, // 请访问 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MvcApplication1 { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
5、控制器总结
(1)不需要做任何配置,只需浏览到/控制器/动作URL即可;
(2)控制器是一个非常简单的类,继承自System.Web.Mvc.Controller类;
(3)用控制器在浏览器中显示文本,没有用到View或Model。
二、视图
1、作用
提供用户界面。一个控制器可以对应多个试图,一个视图可以被多个控制器使用。
在Action名上右键→添加试图→View1。
2、指定视图
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>View1</title> </head> <body> <div> <h2>@ViewBag.Message</h2> </div> </body> </html>
3、ViewData和ViewBag的区别于联系
在前面的例子中,使用了ViewBag的Message属性从控制器往视图传递数据,ViewData是一个特殊的字典类,可以按标准语法进行使用:ViewData["CurrentTime"]=DateTime.Now;
这种语法也可以用动态封装器ViewBag:ViewBag.CurrentTime=DateTime.Now;
注意:
(1)尽管只有当要访问的关键字是有效的C#标识符是,ViewBag才起作用,如在ViewData["Key With Spaces"]就不能使用ViewBag访问,编译不通过;
(2)动态值不能作为一个参数传递给扩展方法。因为C#编译器为了选择正确的扩展方法,在编译是必须知道每个参数真正类型。如:@Html.TextBox("name",ViewBag.Name)不会编译通过,可以改为:
①@Html.TextBox("name",ViewData["Name"])
②@Html.TextBox("name",(string)ViewBag.Name)
4、强类型视图
现在需要编写一个显示Album实例列表的视图。一简单的方法就是通过ViewBag属性把那些Album实例添加到视图数据字典中,然后在视图中迭代他们。
(1)首先,在Models文件夹下新建一个Album类,为了简单起见,只定义一个Title属性。
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcApplication1.Models { public class Album { public string Title { get; set; } } }
public ActionResult List() { var album = new List<Album>(); for (int i = 0; i < 10; i++) { album.Add(new Album { Title = "Product " + i.ToString() }); } //一、使用ViewBag传值 //ViewBag.Album = album; //return View("ListView"); //二、使用ViewData传值 ViewData["Album"] = album; return View("ListView"); }
(3)视图
在List上右键→添加视图。
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @*一、使用ViewBag传值*@ @*@foreach(MvcApplication1.Models.Album a in (ViewBag.Album as IEnumerable <MvcApplication1.Models.Album>)) { <li>@a.Title</li> }*@ @*二、使用ViewBag传值*@ @foreach (MvcApplication1.Models.Album a in (ViewData["Album"] as IEnumerable<MvcApplication1.Models.Album>)) { <li>@a.Title</li> } </ul> <pre name="code" class="html"> <ul> @foreach(dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul> </div> </body> </html>
运行效果:

<ul> @foreach (dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul>
请记住,ViewData是ViewDataDictionary类型的,它有一个额外的Model属性,可以用来在视图中获取指定的模型对象。由于在ViewData中只能传递一个模型对象,因此,我们利用这一点可以很容易的实现向视图传递一个特定的类对象。
在Controller方法中,可以通过重载的List方法中传递模型实例来指定模型,代码如下:
public ActionResult List() { var album = new List<Album>(); for (int i=0;i < 10; i++) { album.Add(new Album { Title="Product " + i.ToString() }); } ViewData["Album"]=album; return View("ListView",album); } @model IEnumerable<MvcApplication1.Models.Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach(dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
如果不想输入模型类型的完全限定类型名,可使用using关键字声明,如下所示:
@using MvcApplication1.Models @model IEnumerable<Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach (dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
对于在视图中经常使用的名称空间,一个较好的方法就是在Views目录下的web.config文件中声明。
<system.web.webPages.razor> <host factoryType = "System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> < pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Optimization"/> <add namespace="System.Web.Routing" /> <add namespace="MvcApplication1.Models"/> </namespaces> </pages> </system.web.webPages.razor>
5、Razor视图引擎
5.1 先来看一个简单的例子。
@{ Layout = null; } @{ var items = new string[] { "one", "two", "three" }; } <!DOCTYPE html> <html> <head> <title>ListView</title> </head> <body> <div> <ul> @foreach (var item in items) { <li>@item</li> } </ul> </div> </body> </html>
5.2 Html编码
因为在很多情况下需要用视图显示用户输入,如博客评论等,所以总是存在着潜在的跨站脚本注入攻击(也成XSS),值得称赞的是,Razor表达式是Html自动编码的,如下不会弹出一个警示框,而是直接显示html代码。
@{ string message = "<script>alert('haacked!');</script>"; }
然而,如果想要展示Html标签,就要返回一个System.Web.IHtml对象的实例,Razor并不对它进行编码。当然也可以创建一个HtmlStringl实例或者使用Html.Raw便捷方法。
@{ string message = "<script>alert('haacked!');</script>"; } <span>@Html.Raw(message)</span>

虽然这种自动的HTML编码通过对一HTML形式显示的用户输入进行编码能有效的缓和XSS的脆弱性,但是对于在JavaScript中时远远不够的。例如:
<script type="text/javascript"> $(function () { var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Message)'; $("#message").html(message).show('slow'); }); </script>
5.3 布局
Razor的布局有助于使用应用程序中的多个视图保持一致的外观,可使用布局为网站定义公共模板(或只是其中的一部分),公共模板包含一个或多个占位符,应用程序中的其他视图为他们提供内容。
下面看一个非常简单的布局,新建一个名称为MyLayout.cshtml的视图,由于要作为公共模板,所以将其放在/Views/Shared/路径下。
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> </body> </html>
接下来新建一个视图,将使用其作为模板。
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; ViewBag.Title = "GoodLuck"; } <p>This is the main content</p>

布局可能有多个节,例如下面示例在前面的布局基础上添加了一个页脚节:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> <footer>@RenderSection("Footer")</footer> </body> </html>

默认情况下,视图必须为布局中定义的没一个节提供相应的内容。更新后的View1视图如下所示:
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; ViewBag.Title = "GoodLuck"; } <p>This is the main content</p> @section Footer{ This is the <strong>footer</strong>. }

RenderSection方法有一个重载的版本,允许在布局中指定不需要的节,可以给required参数传递一个false值来标记Footer节是可选的:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> <footer>@RenderSection("Footer", required: false)</footer> </body> </html>
5.4 ViewStart
在前面的例子中,每一个视图都是用Layout属性来指定它的布局,如果多个视图使用同一个布局,就会产生冗余,并且很难维护。
_ViewStart.cshtml页面可用来消除这种冗余,这个文件的代码先于同目录下任何视图代码的执行,这个文件也可以递归地应用到子目录下的任何视图。
@{
Layout="~/Views/Shared/_Layout.cshtml";
}
因为这个代码先于任何视图执行,所以一个视图可以重写Layout属性的默认值,从而重新选择一个不同的布局。
5.4 指定部分视图
除了返回视图之外,操作方法也可以通过PartialView方法以PartialResult的形式返回部分视图。
The end
ASP.NET MVC 是微软官方提供的以MVC模式为基础的ASP.NET Web应用程序(Web Application)框架,它由Castle的MonoRail而来。
MVC 编程模式
MVC 是三种 ASP.NET 编程模式中的一种。
MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式。
(1)Model(模型)表示应用程序核心(比如数据库记录列表)。
(2)View(视图)显示数据(数据库记录)。
(3)Controller(控制器)处理输入(写入数据库记录)。
MVC 模式同时提供了对 HTML、CSS 和 JavaScript 的完全控制。Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
新建一个ASP.NET MVC4应用程序,结构如下图所示:
对各个文件夹的说明:
(1)App_Data 文件夹用于存储应用程序数据。
(2)Content 文件夹用于存放静态文件,比如样式表(CSS 文件)、图标和图像。
(3)Controllers 文件夹包含负责处理用户输入和相应的控制器类。
(4)Models 文件夹包含表示应用程序模型的类。模型控制并操作应用程序的数据。
(5)Views 文件夹用于存储与应用程序的显示相关的 HTML 文件(用户界面)。
(6)Scripts 文件夹存储应用程序的 JavaScript 文件。
下面就主要的Controller、Model和View做出说明。
一、控制器
1、描述
控制器(Controller)主要负责响应用户的输入,并在响应时修改模型(Model)。通过这种方式,控制器主要关注的是应用程序流、输入数据的处理,以及对相关视图(View)输出数据的提供。
2、简单控制器
新建一个ASP.NET MVC4应用程序,会自动生成一个HomeController和AccountController。
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application."; return View(); } } }
直接按F5运行程序即可看到index试图中的内容,此时浏览器的URL为:
http://localhost:4573,或者修改浏览器地址为:
http://localhost:4573/home
http://localhost:4573/home/index
程序默认会托管在VS2013自带的IIS中,采用的端口号为4573。如果程序托管在MyWeb.com中,则URL应为:
http://MyWeb.com/home/index。
3、控制器操作中的参数
前面的例子Action中返回的是字符串常量,下面就让它们通过相应URL传进来的参数动态地执行操作。
在这里,我们使用HttpUtility.HtmlEncode来预处理用户输入。这样就能阻止用户用链接向视图中注入JavaScriptd代码或HTML标记,比如/home/sayhello?content=<script>window.location='http://www.baidu.com'</script>。
public string SayHello(string content) { string message = HttpUtility.HtmlEncode("Hello " + content); return message; }

public string Details(int Id) { return "ID:" + Id; }

4、路由---将URL映射到动作
框架是如何知道将URL映射到一个特定的控制动作的?答案就在Global.asax文件的RegisterRoutes方法中。该方法定义了将一个URL模式映射到控制器或动作的路由。
using System.Linq; using System.Web; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace MvcApplication1 { // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明, // 请访问 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); } } }
在RegisterRoutes方法上按F12,转到该方法的定义,如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MvcApplication1 { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
5、控制器总结
(1)不需要做任何配置,只需浏览到/控制器/动作URL即可;
(2)控制器是一个非常简单的类,继承自System.Web.Mvc.Controller类;
(3)用控制器在浏览器中显示文本,没有用到View或Model。
二、视图
1、作用
提供用户界面。一个控制器可以对应多个试图,一个视图可以被多个控制器使用。
在Action名上右键→添加试图→View1。
2、指定视图
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>View1</title> </head> <body> <div> <h2>@ViewBag.Message</h2> </div> </body> </html>
3、ViewData和ViewBag的区别于联系
在前面的例子中,使用了ViewBag的Message属性从控制器往视图传递数据,ViewData是一个特殊的字典类,可以按标准语法进行使用:ViewData["CurrentTime"]=DateTime.Now;
这种语法也可以用动态封装器ViewBag:ViewBag.CurrentTime=DateTime.Now;
注意:
(1)尽管只有当要访问的关键字是有效的C#标识符是,ViewBag才起作用,如在ViewData["Key With Spaces"]就不能使用ViewBag访问,编译不通过;
(2)动态值不能作为一个参数传递给扩展方法。因为C#编译器为了选择正确的扩展方法,在编译是必须知道每个参数真正类型。如:@Html.TextBox("name",ViewBag.Name)不会编译通过,可以改为:
①@Html.TextBox("name",ViewData["Name"])
②@Html.TextBox("name",(string)ViewBag.Name)
4、强类型视图
现在需要编写一个显示Album实例列表的视图。一简单的方法就是通过ViewBag属性把那些Album实例添加到视图数据字典中,然后在视图中迭代他们。
(1)首先,在Models文件夹下新建一个Album类,为了简单起见,只定义一个Title属性。
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcApplication1.Models { public class Album { public string Title { get; set; } } }
(2)控制器
public ActionResult List() { var album = new List<Album>(); for (int i=0;i < 10 ;i++) { album.Add(new Album { Title="Product " + i.ToString() }); } //一、使用ViewBag传值 //ViewBag.Album = album; //return View("ListView"); //二、使用ViewData传值 ViewData["Album"] = album; return View("ListView"); }
(3)视图
在List上右键→添加视图。
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @*一、使用ViewBag传值*@ @*@foreach(MvcApplication1.Models.Album a in (ViewBag.Album as IEnumerable<MvcApplication1.Models.Album>)) { <li>@a.Title</li> }*@ @*二、使用ViewBag传值*@ @foreach (MvcApplication1.Models.Album a in (ViewData["Album"] as IEnumerable<MvcApplication1.Models.Album>)) { <li>@a.Title</li> } </ul> <pre name="code" class="html"> <ul> @foreach(dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul> </div> </body> </html>
运行效果:

<ul> @foreach (dynamic d in ViewBag.Album) { <li>@d.Title</li> } </ul>
请记住,ViewData是ViewDataDictionary类型的,它有一个额外的Model属性,可以用来在视图中获取指定的模型对象。由于在ViewData中只能传递一个模型对象,因此,我们利用这一点可以很容易的实现向视图传递一个特定的类对象。
在Controller方法中,可以通过重载的List方法中传递模型实例来指定模型,代码如下:
public ActionResult List() { var album = new List<Album>(); for (int i=0;i < 10;i++) { album.Add(new Album { Title="Product " + i.ToString() }); } ViewData["Album"]=album; return View("ListView",album); } @model IEnumerable<MvcApplication1.Models.Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach(dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
如果不想输入模型类型的完全限定类型名,可使用using关键字声明,如下所示:
@using MvcApplication1.Models @model IEnumerable<Album> @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>ListView</title> </head> <body> <div> <ul> @foreach (dynamic d in Model) { <li>@d.Title</li> } </ul> </div> </body> </html>
对于在视图中经常使用的名称空间,一个较好的方法就是在Views目录下的web.config文件中声明。
<system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Optimization" /> <add namespace="System.Web.Routing" /> <add namespace="MvcApplication1.Models" /> </namespaces> </pages> </system.web.webPages.razor>
5、Razor视图引擎
5.1 先来看一个简单的例子。
@{ Layout = null; } @{ var items = new string[] { "one", "two", "three" }; } <!DOCTYPE html> <html> <head> <title>ListView</title> </head> <body> <div> <ul> @foreach (var item in items) { <li>@item</li> } </ul> </div> </body> </html>
5.2 Html编码
因为在很多情况下需要用视图显示用户输入,如博客评论等,所以总是存在着潜在的跨站脚本注入攻击(也成XSS),值得称赞的是,Razor表达式是Html自动编码的,如下不会弹出一个警示框,而是直接显示html代码。
@{ string message = "<script>alert('haacked!');</script>"; } <span>@message</span>
然而,如果想要展示Html标签,就要返回一个System.Web.IHtml对象的实例,Razor并不对它进行编码。当然也可以创建一个HtmlStringl实例或者使用Html.Raw便捷方法。
@{ string message = "<script>alert('haacked!');</script>"; } <span>@Html.Raw(message)</span>

虽然这种自动的HTML编码通过对一HTML形式显示的用户输入进行编码能有效的缓和XSS的脆弱性,但是对于在JavaScript中时远远不够的。例如:
<script type="text/javascript"> $(function() { var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Message)'; $("#message").html(message).show('slow'); }); </script>
当在JavaScript中将用户提供的值赋给变量时,要使用JavaScript字符串编码而不仅仅是HTML编码,记住这一点是很重要的,也就是要用@Ajax.JavaScriptStringEncode方法对用户输入进行编码。
5.3 布局
Razor的布局有助于使用应用程序中的多个视图保持一致的外观,可使用布局为网站定义公共模板(或只是其中的一部分),公共模板包含一个或多个占位符,应用程序中的其他视图为他们提供内容。
下面看一个非常简单的布局,新建一个名称为MyLayout.cshtml的视图,由于要作为公共模板,所以将其放在/Views/Shared/路径下。
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> </body> </html>
接下来新建一个视图,将使用其作为模板。
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; ViewBag.Title = "GoodLuck"; } <p>This is the main content</p>

布局可能有多个节,例如下面示例在前面的布局基础上添加了一个页脚节:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> <footer>@RenderSection("Footer")</footer> </body> </html>

默认情况下,视图必须为布局中定义的没一个节提供相应的内容。更新后的View1视图如下所示:
@{ Layout = "~/Views/Shared/MyLayout.cshtml"; ViewBag.Title = "GoodLuck"; } <p>This is the main content</p> @section Footer{ This is the <strong>footer</strong> }

RenderSection方法有一个重载的版本,允许在布局中指定不需要的节,可以给required参数传递一个false值来标记Footer节是可选的:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> </head> <body> <h1>@ViewBag.Title</h1> <div id="Container">@RenderBody()</div> <footer>@RenderSection("Footer", required: false)</footer> </body> </html>
5.4 ViewStart
在前面的例子中,每一个视图都是用Layout属性来指定它的布局,如果多个视图使用同一个布局,就会产生冗余,并且很难维护。
_ViewStart.cshtml页面可用来消除这种冗余,这个文件的代码先于同目录下任何视图代码的执行,这个文件也可以递归地应用到子目录下的任何视图。
@{
Layout="~/Views/Shared/_Layout.cshtml";
}
因为这个代码先于任何视图执行,所以一个视图可以重写Layout属性的默认值,从而重新选择一个不同的布局。
5.4 指定部分视图
除了返回视图之外,操作方法也可以通过PartialView方法以PartialResult的形式返回部分视图。
The end