1.3 本章示例的布局和创建办法
在后续的章节中,各种布局页、导航页以及每个例子的运行和调试办法都非常相似,这一节我们先学习如何创建本书各章示例公用的布局页,然后再以本章为例,介绍各章示例的创建和运行办法。
1.3.1 创建多个区域公用的布局页
在ASP.NET MVC中,控制器文件和视图文件默认分别保存在Controllers和Views文件夹下,这种默认的项目结构可满足大多数Web应用项目的需求。但是,当应用程序具有大量控制器,而每个控制器又可能与若干个视图关联时,默认的项目结构可能不实用,比如不同的模块无法仅仅通过一个_ViewStart.cshtml文件来引用不同的默认布局页、各模块之间无法有效分离等。为了解决这些问题,可通过在项目中添加区域(Area)的办法,将大型Web应用程序划分为各自独立的模块。
在Mvc5Examples解决方案中,我们可以将每一章的示例都看作一个独立的模块,这样就把整个应用程序划分为多个区域,区域名分别定义为Chapter01、Chapter02、……、Chapter10。这样做的好处是:由于每个区域都有自己的Controllers、Models和Views文件夹以及_ViewStart.cshtml文件,因此,这样做既可以让模块功能各自独立,又可以让这些不同的模块共享相同的资源(如图像文件、.css文件、js文件等),同时还能在某个模块中调用其他模块的功能。
所有区域默认都保存在项目根目录的Areas子文件夹下。
1.添加区域
下面以添加Chapter01为例,说明添加区域的办法。
在【解决方案资源管理器】中,鼠标右击项目名,单击【添加】→【区域】命令,在弹出的窗口中,输入区域名称为“Chapter01”,单击【添加】按钮。
此时系统将自动检查项目根目录下是否已经存在Areas文件夹,如果不存在Areas文件夹,则自动创建该文件夹,然后在该文件夹下创建Chapter01区域;如果已经存在Areas文件夹,则自动在Areas文件夹下创建Chapter01区域。
在Chapter01区域中,系统会自动创建Controllers子文件夹、Models子文件夹、Views子文件夹以及web.config文件和其他相关的文件。
有一点需要注意,项目根目录下的Web.config文件首字母是大写字母(保存整个项目的配置),而区域中Views子文件夹下的web.config文件首字母是小写字母(保存对应区域下的模块配置)。
添加区域后,系统会自动在Global.asax文件中,通过AreaRegistration类注册所有添加的区域。打开项目中的Global.asax文件,可看到下面的代码:
AreaRegistration.RegisterAllAreas();
正是由于这行代码的作用,MVC才能正确找到项目中添加的所有区域。
2.添加分部页(_AreasPartialRef.cshtml文件)
_AreasPartialRef.cshtml文件用于保存布局页引用的CSS和脚本,这样可避免在每个布局页中都重复定义它。
在Shared子文件夹下添加一个文件名为“_AreasPartialRef.cshtml”的分部页文件,然后将该文件改为下面的内容:
@Styles.Render("~/Content/themes/base/jquery-ui") @* 下面的代码是将文件直接拖放到此处添加的,不是手工键入的。 另外,不要用Styles.Render实现,否则所有3D例子加载时都会出现界面短暂停顿的现象 *@ <link href="~/Content/bootstrap.css" rel="stylesheet" /> <link href="~/Content/bootstrap-theme.css" rel="stylesheet" /> <style> body { margin-top: 2px; margin-bottom: 2px; } #demo { margin-right: -15px; } #demo .list-group-item { font-size: 14px; margin-left: -33px; margin-right: -33px; padding-top: 7px; padding-bottom: 7px; } #demo .list-group-item:first-child { margin-top: -15px; } #demo .list-group-item:last-child { margin-bottom: -15px; } </style> @* 由于子视图(分部视图)中不能使用@section指定脚本放置的位置,为了能在视图以及分部视图中都 能调用布局页引用的脚本,需要将这些引用放到head块内,而不是放到body块的末尾。 *@ @Scripts.Render("~/bundles/modernizr") @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/jqueryui") @*Ajax帮助器是利用jQuery的Ajax来实现的,所以需要添加下面的引用*@ @Scripts.Render("~/bundles/jquery/unobtrusive-ajax") @*输入验证需要添加下面的引用(也可以用到时再在相应页面中添加,而不是添加到此处)*@ @Scripts.Render("~/bundles/jquery/validate") @*将下面的引用放在最后,是为了确保在调用Bootstrap之前先调用jQuery*@ @Scripts.Render("~/bundles/bootstrap")
在这个文件的代码中,需要关注以下两个方面。
(1)下面的2行代码
<link href="~/Content/bootstrap.css" rel="stylesheet" /> <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
是通过将文件直接从【解决方案资源管理器】中拖放到_AreasHeadPartial.cshtml文件中而得到的,而不是直接键入这些代码。另外,之所以通过<link.../>来实现,而不是通过@Style.Render(...)来实现,是为了避免加载3D页面的例子时界面出现短暂停顿的现象。
(2)该文件中的所有代码都全部存放在布局页的<head>与<head/>之间,这是因为本书的示例有些是通过视图实现的,有些则是通过分部视图实现的,由于子视图或者分部视图中不能使用@section指定脚本放置的位置,为了能在视图以及分部视图中都能调用布局页引用的脚本,因此需要将这些引用全部都放到head块内,而不是放到body块的末尾。
3.添加分部页(_AreasPartialAjax.cshtml文件)
_AreasPartialAjax.cshtml文件用于保存各章示例导航页调用的Ajax和jQuery UI的Accordion方法,这样可避免在每个导航文件中都重复定义它。
鼠标右击项目根目录Views文件夹下的Shared子文件夹,选择【添加】→【新建项】命令,在弹出的窗口中选择【MVC 5分部页(Razor)】模板,将名称改为“_AreasPartialAjax.cshtml”,单击【添加】按钮,然后将该文件改为下面的内容:
@* 将Ajax功能保存到一个单独文件中是因为有些页面并不需要它, 比如呈现三维图形的主界面就不需要这个文件。另外,这样也容易看出相关的代码 *@ <style> body { margin-top: 2px; margin-bottom: 2px; } .accordionDemo { margin-right: -15px; padding-bottom: 0; } .accordionDemo :first-child { margin-top: 0; } .accordionDemo .list-group { margin-bottom: 0; border-radius:0; } .accordionDemo .list-group-item { font-size: 14px; margin-left: -34px; margin-right: -34px; padding-top: 7px; padding-bottom: 7px;} .accordionDemo .list-group-item:first-child { margin-top: -15px; } .accordionDemo .list-group-item:last-child { margin-bottom: -15px; } .accordionDemo .list-group-item:hover { background-color: #fbe77a; color: red; } .accordionDemo .list-group-item:focus{ color: red; } </style> @{ var ajaxOptions = new AjaxOptions { LoadingElementId = "loading", UpdateTargetId = "bodyContent", OnFailure = "OnFailure" }; TempData["AjaxOptions"] = ajaxOptions; } <script> function OnFailure(xhr, textStatus, errorThrown) { $("body").html(xhr.responseText); } </script>
4.添加布局页(_AreasLayout.cshtml文件)
_AreasLayout.cshtml是本书所有区域(Areas)中的示例共同使用的布局页。
所有区域共用的布局页一般保存在项目根目录下的Views/Shared文件夹下,某个区域专用的布局页则保存在该区域内的Views/Shared文件夹下。在某个区域中创建的视图页,既可以引用整个项目公用的布局页,也可以引用本区域内定义的布局页。
用前面介绍的添加布局页的办法,在项目根目录下的Views/Shared文件夹下添加一个文件名为“_AreasLayout.cshtml”的文件,并将其改为下面的内容:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title</title> @Html.Partial("~/Views/Shared/_AreasPartialRef.cshtml") @Html.Partial("~/Views/Shared/_AreasPartialAjax.cshtml") </head> <body> @{ int chapter = ViewContext.ViewBag.Chapter; } <div class="container"> <div class="panel panel-default" style="min-height: 350px;"> <div class="panel-heading"> <span>第@(chapter)章</span> <span class="pull-right">@Html.ActionLink("返回主页", "MainIndex", "Home", new { area = "" }, null)</span> <span id="loading" class="pull-right" style="display: none; color: red; margin-right:20px;">(正在加载,请稍等...)</span> </div> <div class="panel-body"> <div class="row"> <div class="col-md-3"> @Html.Partial(string.Format("ch{0:d2}Demos", chapter)) </div> <div id="bodyContent" class="col-md-9"> @RenderBody() </div> </div> </div> </div> </div> </body> </html>
在后续的章节中,我们还会详细介绍布局页中代码的含义和具体用法,这里只需要关注如何链接到各章示例的默认页面即可。
1.3.2 创建本章示例使用的布局页和导航页
创建Chapter01区域之后,就可以在该区域中编写第1章的示例代码了。
1.添加本章示例使用的默认页面
当首次转到某一章的示例页面时,当用户还没有选择某个例子时,可以先显示一个默认的页面,如在该页面中介绍本章应该掌握的内容等。
Chapter01区域中ch01NavDemos子文件夹下的ch01Index.cshtml文件用于实现该区域的默认页面。
在【解决方案资源管理器】中,鼠标右击Chapter01区域下的Controllers文件夹,选择【添加】→【控制器】命令,此时系统会首先弹出如图1-16所示的基架(Scalffolder)模板,让开发人员选择使用哪种基架模板来添加控制器。
图1-16 选择基架模板
选择【MVC 5控制器—空】模板,在后续的弹出窗口中,将控制器名称改为“ch01NavDemosController”,单击【添加】按钮,如图1-17所示。
图1-17 添加控制器
注意:控制器名称必须带Controller后缀,这是ASP.NET MVC的命名规定。
此时,系统就会自动在Controllers文件夹下添加一个文件名为“ch01NavDemosController.cs”的文件,并自动在该文件中添加一个Index操作方法。同时,系统还会自动在该区域的Views文件夹下创建一个名为“ch01NavDemos”的子文件夹(ch01NavDemosController去掉Controller后缀得到的名称)。
将ch01NavDemosController.cs文件中的Index方法改为下面的内容:
public class ch01NavDemosController : Controller { public ActionResult Index(string id) { return View(id); } }
鼠标右击Index操作方法,选择【添加视图】,在弹出的窗口中,将视图名称改为“ch01Index”,勾选“使用布局页”,如图1-18所示,单击【添加】按钮。
图1-18 添加视图
此时,系统就会自动在ch01NavDemos文件夹下添加一个文件名为“ch01Index.cshtml”的文件。双击该文件,将其改为下面的内容:
@{ ViewBag.Title = "ch01Index"; } <div class="jumbotron"> <h2 class="text-danger">第1章 概述</h2> <p class="text-primary">本章重点:MVC项目的创建和配置,布局页的创建和代码设计。</p> </div>
2.修改本章布局页
在区域中首次添加视图时,系统会自动在对应区域的Shared文件夹下创建一个_Layout.cshtml文件,将该文件换名为“_ch01Layout.cshtml”(这样做的目的仅仅是为了能明确看出是哪一章使用的布局页,但这并不是必需的步骤),然后将代码改为下面的内容:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>@ViewBag.Title</title> <link href="~/Content/bootstrap.css" rel="stylesheet" /> @Scripts.Render("~/bundles/modernizr") @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") </head> <body> <div class="container"> <nav class="navbar navbar-default"> <div class="navbar-header"> <div class="navbar-brand">第1章</div> </div> <div class="navbar-collapse"> @Html.Partial("ch01NavDemos") <ul class="nav navbar-nav navbar-right"> <li>@Html.ActionLink("返回主页", "MainIndex", "Home", new { area = "" }, new { @class = "navbar-link" })</li> </ul> </div> </nav> </div> <div class="container"> <div class="panel panel-primary"> <div class="panel-body"> @RenderBody() </div> </div> </div> </body> </html>
3.修改本章的_ViewStart.cshtml文件
打开Chapter01区域中的_ViewStart.cshtml文件,将其改为下面的内容:
@{ Layout = "~/Areas/Chapter01/Views/Shared/_ch01Layout.cshtml"; }
这样一来,Chapter01区域内的所有视图除非明确指定引用的是那个布局页,否则默认都会将_ch01Layout.cshtml作为它所引用的布局页。
4.添加本章示例导航页
用前面介绍的添加分部页的办法,在Chapter01区域的Shared子文件夹下添加一个文件名为ch01NavDemos.cshtml的文件,然后将其改为下面的内容:
<ul class="nav navbar-nav"> <li>@Html.ActionLink("例1-各章布局示意", "Index", "ch01NavDemos", new { id = "LayoutDemo" }, null)</li> <li>@Html.ActionLink("例2-获取Web服务器信息", "Index", "ch01NavDemos", new { id = "ServerInfo" }, null)</li> </ul>
5.观察本章导航页和默认页面的运行效果
在快捷工具栏中,选择【Internet Explorer】选项,然后按<F5>键运行应用程序(调试模式),或者按<Ctrl>+<F5>键运行应用程序(非调试模式),通过主页的菜单导航到本章后,就会在IE 11.0浏览器中看到程序运行的效果,如图1-19所示。
图1-19 本章示例导航的运行效果
完成这些步骤以后,就可以在ch01NavDemos文件夹下添加本章示例的代码了。
1.3.3 添加本章示例代码
本章的例子有两个用途:一是让读者观察本书各章示例的布局,二是让读者观察呈现当前网页的Web服务器配置。
1.观察各章示例的主页布局
本书所有章节的示例源程序都采用以下的布局形式(根据需要,可以同时用两个导航区,也可以只使用其中的一个导航区)。
Demos导航区(左侧导航区):利用区域中的超链接导航到主窗口,即在主窗口中显示基本用法示例的运行结果。
NavDemos导航区(上方导航区):其结果也是在“主窗口”中显示对应示例的运行效果。另外,在该导航区的右侧,有一个可返回到主页的链接。
为了让示例导航的代码修改起来更方便,我们将在导航区显示的所有链接内容都保存在独立的分部页中。例如,第1章只在上方显示导航区,导航文件名为“ch01NavDemos.cshtml”;第2章仅在左侧显示导航区,导航文件名为“ch02Demos.cshtml”;而第3章则演示了同时显示两个导航区的情况,导航文件名分别为“ch03Demos.cshtml”和“ch03NavDemos.cshtml”。
下面通过例子演示各章布局示意图。
【例1-1】演示各章示例的布局,运行效果如图1-20所示。
图1-20 LayoutDemo.cshtml文件的运行效果
该例子的源程序请参看ch01NavDemos文件夹下的LayoutDemo.cshtml文件,此处不再列出源代码。
2.观察承载当前网页的Web服务器环境信息
下面的例子演示如何通过System.Web.Helps命名空间下的ServerInfo方法,显示当前网页使用的ASP.NET Web Pages版本以及该页面请求的Web服务器的环境信息。
【例1-2】显示承载当前网页的Web服务器环境信息,在IE 11.0浏览器中运行的效果,如图1-21所示。
图1-21 ServerInfo.cshtml文件的运行效果
该例子的源程序见ServerInfo.cshtml文件,在这个文件中只有下面2行代码:
<h3 class="text-center">获取承载当前网页的Web服务器环境信息</h3> @ServerInfo.GetHtml()