第5章〓Razor Pages

Razor Pages 是在 ASP.NET Core中创建基于页面或基于窗体的应用程序的首选方法。基于Razor Pages的编码方式比使用控制器和视图更为轻松和高效。本章主要介绍Razor Pages项目、模型对象、布局、Razor语法的概念和应用。

本章主要学习目标如下: 

 掌握Razor Pages项目的创建。

 掌握模型对象的概念和应用。

 掌握布局的概念和应用。

 掌握Razor语法的概念和应用。

5.1Razor Pages简介

Razor Pages简化了传统的MVC模式,通过使用视图与模型来完成网页的渲染和业务逻辑的处理。模型里包含了数据和方法,通过绑定技术与视图建立联系,即Razor Pages 将操作组合在一起,并在一个类中调用一个名为PageModel的ViewModel类,并将此类链接到名为 Razor 页面的视图,这往往会使 Razor Pages 及其处理程序更小、更集中,同时可以更轻松地查找和处理更改应用程序所需的所有文件。Razor Pages页面是MVC框架的一种简化应用,可以使以页面为中心的编码方案更简单、高效。

所有Razor Pages都在ASP.NET Core项目根目录中的“页面”文件夹,即/Pages目录中。Razor Pages 在此文件夹中根据其名称和位置使用路由约定。

ASP.NET Core Web Application项目文件包括以下部分。

1. Pages文件夹

Pages文件夹包含Razor页面和支持文件。每个Razor页面都是一组文件。

(1) cshtml文件: 其中包含使用Razor语法的C#代码的HTML标记。





(2) cshtml.cs文件: 其中包含处理页面事件的C#代码。

支持文件的名称以下画线开头。例如,_Layout.cshtml文件可配置所有页面通用的UI 元素。此文件设置页面顶部的导航菜单和页面底部的版权声明。

2. wwwroot 文件夹

wwwroot 文件夹包含静态文件,如HTML文件、JavaScript文件和CSS文件。

3. appSettings.json

此文件包含项目配置信息,如连接字符串。

4. Program.cs

此文件包含程序的入口点。

5. Startup.cs

此文件包含配置应用行为的代码。

5.2创建Razor Pages



视频讲解


【例51】创建 Razor Pages Web项目。

① 打开Visual Studio 2019应用程序,选择“创建新项目”选项,如图51所示。



图51创建新项目


② 选择“ASP.NET Core Web 应用程序”选项,单击“下一步”按钮,如图52所示。



图52选择ASP.NET Core Web应用程序


③ 在“配置新项目”对话框中输入项目名称RazorPagesdemo,单击“创建”按钮,如图53所示。



图53配置新项目


④ 在“创建新的ASP.NET Core Web应用程序”对话框中依次在下拉列表中选择.NET Core和ASP.NET Core 3.1选项,同时选择“Web应用程序”选项,然后单击“创建”按钮,如图54所示。



图54选择“Web应用程序”选项


⑤ 项目创建完成,如图55所示。



图55项目创建完成


⑥ 单击IIS Express按钮运行程序,结果如图56所示。



图56应用程序运行结果


5.3Razor基本语法
5.3.1Razor语法
Razor是一种将服务器端的代码嵌入客户端网页中的标记语法。Razor语法由 Razor标记、C#语言和HTML组成,Razor文件的扩展名为.cshtml。Razor默认的语言为HTML,同时支持C#和Visual Basic,可以使用@符号从HTML切换到C#。Razor C#的内联表达式(变量和函数)以@开始,代码语句用分号结束。变量使用var关键字声明,字符串用引号括起来。

5.3.2Razor表达式

Razor能够对C#表达式进行运算并渲染为HTML输出。当@符号后跟Razor保留关键字时为Razor特定标记,否则会表示为C#表达式。

若要对@标记中的符号进行转义,即在HTML中显示@,则需使用第二个@符号,例如: 

<p>@@wswk2001@sina.com</p>

该代码在HTML中呈现单个@符号: 

<p>@wswk2001@sina.com</p>

Razor可以避免由于HTML内容中包含邮件地址@符号,而误将@符号处理为转义字符。以下示例中的电子邮件地址将通过分析而保持不变: 

<a href="mailto:wswk2001@sina.com">wswk2001@sina.com</a>

1. 隐式Razor表达式

隐式Razor表达式以@开始,后面为C#代码: 

<p>现在时间是:@DateTime.Now</p>

<p>今年是否为闰年:@DateTime.IsLeapYear(2022)</p>

2. 显式Razor表达式

显式Razor表达式由@带一对小括号组成。若要显示上个月的时间,则可以使用以下标记: 

<p>上月的时间: @(DateTime.NowTimeSpan.FromDays(30))</p>

Razor将计算@后的小括号中的所有内容,并将其显示输出。



视频讲解


【例52】Razor表达式。

① 创建RazorPagedemo项目后,打开Pages文件夹下的Index.cshtml页面,输入Razor表达式内容,代码如下。

<div class="textcenter">

<p>@@wswk2001@sina.com</p>

<p>现在时间是:@DateTime.Now</p>

<p>今年是否为闰年:@DateTime.IsLeapYear(2022)</p>

<p>上月的时间: @(DateTime.Now  TimeSpan.FromDays(30))</p>

</div>

② 运行该程序,结果如图57所示。



图57Razor表达式运行结果


隐式表达式通常不能包含空格,@后面必须紧跟有效的标识符或关键字、 “(”或“{”等。

③ 在本例中再添加一行代码,如下。

<p>上月时间: @DateTime.Now  TimeSpan.FromDays(30)</p>

运行后结果如图58所示。



图58结果对比


可以看出,因为去掉了括号,代码只输出了@DateTime.Now表达式的值,@DateTime.Now后面的语句原样输出了。

3. 表达式编码

C#表达式计算结果是字符串时会采用HTML编码; 如果为IHtmlContent,则通过IHtmlContent.WriteTo渲染到页面; 如果不是IHtmlContent,则通过 ToString转换为字符串并在渲染前进行编码。

【例53】表达式编码。

① 新建RazorPagedemo项目,打开Pages文件夹下的Index.cshtml页面,输入如下代码。

<div class="textcenter">

@("<span>Razor Pages是一种新型的Web框架</span>")

</div>

运行后显示结果如图59所示。



图59表达式编码运行结果


② 如果想以HTML标记进行输出,则需要加上Html.Raw()方法,将上面代码修改如下。

<div class="textcenter">

@Html.Raw("<span>Razor Pages是一种新型的Web框架</span>")

</div>

再次运行该程序,结果如图510所示。



图510使用Html.Raw()方法运行结果


5.3.3Razor代码块
1. 代码块定义
Razor代码块包含在@{…}中,代码块内的C#代码不会渲染到页面中。与表达式不同,Razor页面中的代码块和表达式将共享同一个作用域并按顺序定义。



视频讲解


【例54】Razor代码块。

① 创建RazorPagedemo项目,打开Pages文件夹下的Index.cshtml页面,输入Razor代码块内容,如下所示。

<div class="textcenter">

@{

var quote = "课程名称: C++程序设计";

}

<p>@quote</p>

@{

quote = "课程名称:ASP.NET Core程序设计";

}

<p>@quote</p>

</div>

② 运行该程序,结果如图511所示。



图511Razor代码块运行结果


③ 在代码块中,可以使用标记将本地函数声明为模板化方法,代码如下所示。

<div class="textcenter">

@{

void RenderName(string name)

{

<p>姓名:<strong>@name</strong></p>

}

RenderName("李志伟");

RenderName("赵宏杰");

}

</div>

④ 运行该程序,结果如图512所示。



图512函数模板化运行结果


2. 隐式转换

代码块中的默认语言是C#,但Razor可随时将页面切换到HTML,并且代码块内HTML标记能够被正确渲染和执行。



视频讲解


【例55】隐式转换。

① 创建RazorPagedemo项目,打开Pages文件夹下的Index.cshtml页面,输入如下代码。

<div class="textcenter">

@{ 

var inScore = "A+";

<p>王洪明同学在本次考试中的成绩为 @inScore </p>

}

</div>

② 运行该程序,结果如图513所示。



图513Razor隐式转换运行结果


3. 带分隔符的显式转换

如果要在代码块中定义需要渲染的HTML的子区域,应用Razor<text>标记包含要渲染的字符。使用此方法可渲染未使用HTML标记的HTML内容,用于在渲染内容时控制空格。此语句仅渲染标记之间的内容,标记之前或之后的空格不会显示在 HTML 中。



视频讲解


【例56】带分隔符的显式转换。

① 创建RazorPagedemo项目,打开Pages文件夹下的Index.cshtml页面,输入如下代码。

<div class="textcenter">

@{

var tree1 = "杨树";

var tree2 = "柳树";

var tree3 = "槐树";

}

<text>北方常见的树种有:@tree1 @tree2 @tree3</text>

 </div>

② 运行该程序,结果如图514所示。



图514带分隔符的显式转换运行结果


5.3.4Razor控制语句

控制语句是对代码块的扩展,用于对程序流程的控制。

1. 条件结构

条件语句用到的命令包括 @if、else if、else和@switch。

几种常见的条件结构如下。

1) 标准if结构

语法如下: 

@if(表达式)

{

代码块1;

}else

{

代码块2;

}

当表达式的值为真时,执行代码块1中的语句,否则执行代码块2中的语句。

2) 嵌套if结构

语法如下: 

@if(表达式1)

{

代码块1;

}else if (表达式2)

{

代码块2;

}

else

{

代码块3;

}

当表达式1的值为真时执行代码块1中的语句,否则继续判断表达式2的值,当表达式2的值为真时执行代码块2,否则执行代码块3。

3) switch结构

语法如下: 

@switch (表达式)

{

case 1:表达式1;break;

case 2:表达式2;break;

…

case n:表达式n;break;

default:表达式n+1;break;

}

首先计算switch后面表达式的值,然后分别与case语句后面的表达式的值进行比较,如果相同则执行该case后面的语句,如果都不相同则执行默认的default后面的语句。该语句适合于三种及三种以上的多分支情况。



视频讲解


【例57】已知学生成绩,当成绩大于或等于85分时为优秀,当成绩大于或等于60分并且成绩小于85分时为合格,当成绩小于60分时为不合格,用if和switch两种方法编写代码并输出结果。

① 创建RazorPagedemo项目,打开Pages文件夹下的Index.cshtml页面,输入如下代码。

<div class="textcenter">

@{

var cj = 85;

}

@if (cj < 60)

{

<p>该同学成绩为"不合格"</p>

}

else if (cj >= 60 && cj < 85)

{

<p>该同学成绩为"合格"</p>

}

else

{

<p>该同学成绩为"优秀"</p>

}



@switch (cj / 10)

{

case 10:

case 9:

case 8:<p>该同学成绩为"优秀"</p>; break;

case 7:

case 6:<p>该同学成绩为"合格"</p>; break;

default: <p>该同学成绩为"不合格"</p>;break;

}

</div>

② 运行该程序,结果如图515所示。



图515条件语句运行结果


2. 循环结构

循环结构用到的命令包括@for、@foreach、@while和@do…while。

几种常见的循环结构如下。

1) for结构

语法如下: 

@for([初始化表达式];[条件表达式];[迭代表达式])

{

语句块;

}

该结构语句运行时首先执行初始化表达式且只执行一次,接着执行条件表达式,如果为真则执行语句块,语句块执行结束后执行迭代表达式,然后再回到条件表达式进行判断。如果为假则结束for循环。

2) foreach结构

语法如下: 

@foreach(类型 变量名 in 集合名)

{

语句块;

}

该结构语句可以遍历集合中的所有元素。每次进行循环遍历时该语句就会从集合中取出一个新的元素值放到只读变量中去,然后执行语句块。当集合中的所有元素都已经被访问到,整个表达式的值即为假值,控制流程就会从foreach中退出。

3) while结构

语法如下: 

@while(条件表达式)

{

语句块;

}

该结构语句首先判断条件表达式的值,如果该值为真则执行语句块,否则退出该while循环。

4) do…while结构

语法如下: 

@do

{

语句块;

} while (条件表达式);

该结构语句首先执行语句块中的语句,然后判断条件表达式的值,如果该值为真则继续执行语句块,否则退出该while循环。



视频讲解


【例58】使用for结构语句求1~100中所有素数之和。

① 创建RazorPagedemo项目,打开Pages文件夹下的Index.cshtml页面,输入如下代码。

<div class="textcenter">

@{

var sum = 0;

var flag = true;

}

@for (var i = 2; i <= 100; i++)

{

flag = true;

@for (var j = 2; j < i - 1; j++)

{

if (i % j == 0)

{

flag = false;

break;

}

}

if (flag)

{

sum = sum + i;

}

}

<p>1~100中素数的和为 @sum </p>

</div>

② 运行该程序,结果如图516所示。



图516for循环语句运行结果


5.3.5Razor复合语句

在C#中,using语句用于确保对象被正确释放。在 Razor 中,可使用相同的机制来创建包含附加内容的HTML帮助程序。



视频讲解


【例59】Razor复合语句。

① 创建RazorPagedemo项目,打开Pages文件夹下的Index.cshtml页面,输入如下代码。

<div class="textcenter">

@using (Html.BeginForm())

{

<div>

<p>

用户名:<input type="text" id="user" value="">

</p> 

<p>

密  码:<input type="text" id="password" value="">

</p>

<p>

<button>登录</button>

</p>

</div>

}

</div>

在上面的代码中,HTML帮助程序使用@using语句呈现<form>标记。

② 运行该程序,结果如图517所示。



图517复合语句运行结果


5.3.6Razor异常处理

Razor异常处理与C#语法相似,使用@前缀声明即可。语法如下。

@try

{

//可能导致异常的语句

}

catch (Exception ex)

{

//处理异常的语句

}

finally

{

//清理代码

}



视频讲解


【例510】Razor异常处理。

① 创建RazorPagedemo项目,打开Pages文件夹下的Index.cshtml页面,输入如下代码。

<div class="textcenter">

@try

{

throw new InvalidOperationException("异常操作");

}

catch (Exception ex)

{

<p>出现错误的信息: @ex.Message</p>

}

finally

{

<p>执行清理代码</p>

}

</div>

② 运行该程序,结果如图518所示。



图518异常语句运行结果


5.3.7Razor注释语句

(1) Razor支持C#和HTML语法的注释,如符合C#语法规定的单行和多行注释方式:

@{

// <p>单行注释</p> 

/* <p>

多行

注释 

</p> 

*/

}

符合HTML语法规定的注释方式: 

<!HTML语句注释>

(2) Razor自身特有的注释。

语法格式为:  

@*注释的内容*@ 

该注释支持单行和多行,示例如下。

@{

@* <p>单行注释</p> *@

@* <p>

多行

注释

</p>

*@

}

5.4Razor页面实现

在本节中将通过一个图书管理的例子来说明如何创建基于Razor页面添加、修改和删除页面的实现过程。

5.4.1添加模型

对于简单的Razor应用只要在文档中加入@page指令,并将其放在Pages目录下就可以通过URL进行访问。如果涉及复杂的业务逻辑就需要创建页面模型类编写独立的代码,使得视图和代码分离。页面模型类需要从Page Model类派生,通过约定的方法与视图交互,页面视图通过handler的路由参数调用这些方法,方法的命名规则如下。

On<HTTP method><handler name>[Async]

 方法以On开始。

 HTTP method参数为GET、POST、DELETE等。

 handler name为方法的正式名称,可以直接作为路由参数handler的值。

 Async表示为异步方法,此项为可选项。



视频讲解


【例511】建立图书管理页面图书模型。

① 在Visual Studio 2019中新建Razor Pages项目,项目的名称为books。

② 在项目名称下新建一个data目录,在该目录下新建Bookinfo实体类并添加以下代码。

public class Bookinfo

{

public int bid { get; set; }

public string bname { get; set; }

public string ISBN { get; set; }

public string author { get; set; }

public  string press { get; set; }

public DateTime pubtime { get; set; }

}

③ 在data目录下新建IBookinfoRepository接口文件,添加Get()、Add()、Update()和Delete()四个方法,代码如下所示。

public interface IBookinfoRepository

{

List<Bookinfo> List();

Bookinfo Get(int id);

bool Add(Bookinfo bookinfo);

bool Update(Bookinfo bookinfo);

bool Delete(int id);

}

④ 在data目录下新建BookinfoRepository类,实现IBookinfoRepository接口,并且使用静态变量保存的数据,模拟数据库中的数据,代码如下所示。

public class BookinfoRepository:IBookinfoRepository

{

private static List<Bookinfo> books = new List<Bookinfo> {

new Bookinfo{ bid=1, bname="ASP.NET程序设计基础教程",ISBN="9787302322108", author="陈长喜", press="清华大学出版社",pubtime=DateTime.Parse("20130801")},

new Bookinfo{ bid=2, bname="ASP.NET程序设计高级教程",ISBN="9787302476351", author="陈长喜", press="清华大学出版社",pubtime=DateTime.Parse("20171001")}               

};

public bool Add(Bookinfo bookinfo)

{

books.Add(bookinfo);

return true;

}

public bool Delete(int id)

{

var book = books.FirstOrDefault(s => s.bid == id);

if (book != null)

{

books.Remove(book);

}

return true;

}

public Bookinfo Get(int id)

{

return books.FirstOrDefault(s => s.bid == id);

}

public List<Bookinfo> List()

{

return books;

}

public bool Update(Bookinfo bookinfo)

{

var book = books.FirstOrDefault(s => s.bid == bookinfo.bid);

if (book != null)

{

books.Remove(book);

}

books.Add(bookinfo);

return true;

}

}

至此,books模型文件建立完成,其目录结构如图519所示。



图519books模型文件的目录结构


5.4.2显示页面

【例512】在例511的基础上添加列表图书页面。

① 在项目Pages目录下新建Bookinfo文件夹。选择Bookinfo文件夹,右击,在弹出的快捷菜单中选择“添加”→“Razor页面”命令,如图520所示。



图520选择“添加”→“Razor页面”命令


② 在“添加已搭建基架的新项”对话框中选择Razor页面,单击“添加”按钮,如图521所示。



图521选择Razor页面


③ 在“添加Razor页面”对话框中添加Razor页面的名称为List,并在下面的“选项”中选中“生成PageModel类”复选框,单击“添加”按钮,如图522所示。



图522添加Razor页面


④ 打开List.cshtml页面,填写如下代码。

<table class="table">

<tr>

<th>序号</th>

<th>书名</th>

<th>ISBN</th>

<th>作者</th>

<th>出版社</th>

<th>出版时间</th>

<th></th>

</tr>

@foreach (var book in Model.bookinfo)

{

<tr>

<td>@book.bid</td>

<td>@book.bname</td>

<td>@book.ISBN</td>

<td>@book.author</td>

<td>@book.press</td>

<td>@book.pubtime</td>

<td>

<a class="btn btnprimary" asppage="Add">添加 </a>

<a class="btn btnprimary" asppage="Update" asprouteid="@book.bid">修改</a>

<a class="btn btndanger" href="/bookinfo/delete?id=@book.bid">删除</a>

</td>

</tr>

}

</table>

⑤ 打开List.cshtml.cs文件,修改ListModel类代码,如下所示。

public class ListModel : PageModel

{

public void OnGet()

{

bookinfo = _bookinfoRepository.List();

}

private readonly IBookinfoRepository _bookinfoRepository;

public List<Bookinfo> bookinfo { get; set; }

public ListModel(IBookinfoRepository bookinfoRepository)

{

_bookinfoRepository = bookinfoRepository;

}

}

⑥ 打开Startup.cs文件,在ConfigureServices()方法中注册repository,代码如下所示。

public void ConfigureServices(IServiceCollection services)

{

services.AddRazorPages();

//注册repository

services.AddScoped<IBookinfoRepository,BookinfoRepository>();

}

⑦ 调试、运行该程序,在现有浏览器地址后面输入/bookinfo/list并按Enter键,结果如图523所示。



图523图书信息显示页面


List.cshtml.cs文件即ListModel类,该类具备MVC中的Controller和Model的概念,其包含的数据可以用来生成Razor视图; 包含方法可以用来处理业务逻辑,此方法可以认为是Controller中的Action。

以上示例中,使用Razor Pages的asppage属性实现页面跳转,如:

<a class="btn btnprimary" asppage="Add">添加 </a>

在a元素上添加了asppage="Add",表示单击添加链接会跳转到Add页面。

使用Razor Pages的asprouteid属性可以完成页面间的参数传递。例如“修改”按钮,需要跳转至Update页面并且传递一个id参数,代码如下所示。

<a class="btn btnprimary" asppage="Update" asprouteid="@book.bid">修改</a>

5.4.3添加页面

【例513】在例512的基础上添加图书信息页面。

① 打开例512项目后在Bookinfo文件夹中添加Razor页面,页面名称为Add。

② 打开Add.cshtml添加页面并填写如下代码。

<form method="post">

<div class="formgroup">

<label>序号</label>

<input type="number" aspfor="bookinfo.bid" class="formcontrol" />

</div>

<div class="formgroup">

<label>书名</label>

<input type="text" aspfor="bookinfo.bname" class="formcontrol" />

</div>

<div class="formgroup">

<label>ISBN</label>

<input type="number" aspfor="bookinfo.ISBN" class="formcontrol" />

</div>

<div class="formgroup">

<label>作者</label>

<input type="text" aspfor="bookinfo.author" class="formcontrol" />

</div>

<div class="formgroup">

<label>出版社</label>

<input type="text" aspfor="bookinfo.press" class="formcontrol" />

</div>

<div class="formgroup">

<label>出版时间</label>

<input type="text" aspfor="bookinfo.pubtime" class="formcontrol" />

</div>

<div class="formgroup">

<button type="submit" class="btn btnprimary" asppagehandler="Save">保存</button>

<a asppage="list" class="btn btndark">取消</a>

</div>

</form>

③ 打开Add.cshtml.cs文件,修改AddModel类代码,如下所示。

public class AddModel : PageModel

{

public void OnGet()

{

}

private readonly IBookinfoRepository _bookinfoRepository;

public AddModel(IBookinfoRepository bookinfoRepository)

{

_bookinfoRepository = bookinfoRepository;

}

[BindProperty]

public Bookinfo bookinfo { get; set; }

public IActionResult OnPostSave()

{

_bookinfoRepository.Add(bookinfo);

return RedirectToPage("List");

}

}

④ 调试、运行该程序,在现有浏览器地址后面输入/bookinfo/add并按Enter键,结果如图524所示。



图524添加图书信息页面


在“添加页面”页面中输入相关数据后单击“保存”按钮,系统将保存当前数据并返回到List显示页面。

在Add.cshtml页面中通过使用asppagehandler="Save"映射模型中的OnPostSave()方法。

public IActionResult OnPostSave()

{

_bookinfoRepository.Add(bookinfo);

return RedirectToPage("List");

}

添加的图书信息需要从前端传递到后端并进行提取,使用BindProperty来完成提交的表单数据与模型属性之间的映射,实现简单的前后端绑定。其代码如下。

[BindProperty]

public Bookinfo bookinfo { get; set; }

5.4.4修改页面

【例514】在例513的基础上实现修改图书信息页面。

① 打开例513项目后在Bookinfo文件夹中添加Razor页面,页面名称为Update。

② 打开Update.cshtml修改页面并填写如下代码。

<form method="post">

<div class="formgroup">

<label>序号</label>

<input type="number" aspfor="book.bid" class="formcontrol" />

</div>

<div class="formgroup">

<label>书名</label>

<input type="text" aspfor="book.bname" class="formcontrol" />

</div>

<div class="formgroup">

<label>ISBN</label>

<input type="number" aspfor="book.ISBN" class="formcontrol" />

</div>

<div class="formgroup">

<label>作者</label>

<input type="text" aspfor="book.author" class="formcontrol" />

</div>

<div class="formgroup">

<label>出版社</label>

<input type="text" aspfor="book.press" class="formcontrol" />

</div>

<div class="formgroup">

<label>出版时间</label>

<input type="text" aspfor="book.pubtime" class="formcontrol" />

</div>

<div class="formgroup">

<button type="submit" class="btn btnprimary" asppagehandler="Edit">保存</button>

<a asppage="list" class="btn btndark">取消</a>

</div>

</form>

③ 打开Update.cshtml.cs文件,修改UpdateModel类代码,如下所示。

public class UpdateModel : PageModel

{

[BindProperty]

public Bookinfo book { get; set; }

public void OnGet(int id)

{

book = _bookinfoRepository.Get(id);

}

private readonly IBookinfoRepository _bookinfoRepository;

public UpdateModel(IBookinfoRepository bookinfoRepository)

{

_bookinfoRepository = bookinfoRepository;

}

public IActionResult OnPostEdit()

{

_bookinfoRepository.Update(book);

return RedirectToPage("list");

}

}

④ 调试、运行该程序,在现有浏览器地址后面输入/bookinfo/list并按Enter键,显示图书列表页面,在该页面中单击序号为1的记录中的“修改”按钮跳转到修改页面,结果如图525所示。



图525修改图书信息


⑤ 在图书修改页面将书名“ASP.NET程序设计基础教程”修改为“ASP.NET程序设计基础教程 (第二版)”,然后单击“保存”按钮,程序将返回图书列表页面,此时会看到已完成序号为1的记录中的书名被修改,如图526所示。



图526完成图书信息修改


5.4.5删除页面

【例515】在例514的基础上实现删除图书信息页面。

① 打开例514项目后在Bookinfo文件夹中添加Razor页面,页面名称为Delete。

② 打开Delete.cshtml删除页面并填写如下代码。

<h2 class="textdanger">

确定删除?

</h2>

<form method="post">

<div class="formgroup">

序号: @Model.Bookinfo.bid

</div>

<div class="formgroup">

书名:@Model.Bookinfo.bname

</div>

<div class="formgroup">

ISBN: @Model.Bookinfo.ISBN

</div>

<div class="formgroup">

作者: @Model.Bookinfo.author

</div>

<div class="formgroup">

出版社: @Model.Bookinfo.press

</div>

<div class="formgroup">

出版时间: @Model.Bookinfo.pubtime

</div>

<div class="formgroup">

<button type="submit" class="btn btnprimary" asppagehandler="Delete" asprouteid="@Model.Bookinfo.bid">删除</button>

<a asppage="list" class="btn btndark">取消</a>

</div>

</form>

③ 打开Delete.cshtml.cs文件,修改DeleteModel类代码如下。

public class DeleteModel : PageModel

{

public Bookinfo Bookinfo { get; set; }

public void OnGet(int id)

{

Bookinfo = _bookinfoRepository.Get(id);

}

private readonly IBookinfoRepository _bookinfoRepository;

public List<Bookinfo> bookinfo { get; set; }

public DeleteModel(IBookinfoRepository bookinfoRepository)

{

_bookinfoRepository = bookinfoRepository;

}

public IActionResult OnPostDelete(int id)

{

_bookinfoRepository.Delete(id);

return RedirectToPage("list");

}

}

④ 调试、运行该程序,在现有浏览器地址后面输入/bookinfo/list并按Enter键,显示图书列表页面,在该页面中单击序号为1的记录中的“删除”按钮跳转到删除页面,结果如图527所示。



图527删除图书信息页面


单击“删除”按钮将删除当前记录并返回列表页。

5.5Razor中的布局
5.5.1布局文件



图528Razor布局文件

大多数Web应用都具有一个通用布局,在页面间切换时为用户提供一致性体验。该布局通常包括应用导航或菜单元素以及页脚等常见的用户界面元素。应用中的页面也经常使用常见的HTML结构,如脚本和样式表。所有这些共享元素都可以在布局文件中定义,然后在Web应用内使用的视图都可以引用该布局文件,减少视图中的重复代码。项目解决方案中可以定义多个布局,其中不同的视图可以指定不同的布局。

Razor Pages应用程序的默认布局文件名为 _Layout.cshtml,该文件存在于项目根目录中Pages/Shared文件夹下,如图528所示。

5.5.2布局规则
1. 指定布局

指定的布局可以使用完整路径和部分名称。例如/Pages/Shared/_Layout.cshtml或_Layout。使用部分名称时,Razor视图引擎首先搜索处理程序方法(或控制器)所在的文件夹,然后搜索 Shared文件夹。

HTML可以将某个位置指定的布局模板应用到整个项目的多个页面中。布局模板中会使用标签 @RenderBody()和@RenderSection(),RenderBody是一个占位符,它可以显示子页面的全部内容,其代码如下所示。

<div class="container">

<main role="main" class="pb3">

@RenderBody()

</main>

</div>

布局可以通过调用RenderSection来选择引用一个或多个节。节通过方法来组织某些页面元素放置的位置,即在母版页中占一个位置来解决页面不同布局的问题。每次调用RenderSection()时可通过required指定该部分是必需还是可选,其中required默认为true,表示引用这个布局页的所有View必须含有该Section,若设为false则表示可以有也可以没有,示例代码如下。

<script type="text/javascript" src="~/scripts/global.js"></script>

@RenderSection("Scripts", required: false)

2. 导入共享指令

在视图和页面中可以使用Razor指令导入命名空间。由多个视图共享的操作可以在_ViewImports.cshtml 文件中进行指定,代码如下所示。

@using layout

@namespace layout.Pages

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

_ViewImports文件不支持函数和节定义,但是支持以下指令: @addTagHelper、@removeTagHelper、@tagHelperPrefix、@using、@model、@inherits、@inject,代码如下。

@using WebApplication1

@using WebApplication1.Models

@using WebApplication1.Models.AccountViewModels

@using WebApplication1.Models.ManageViewModels

@using Microsoft.AspNetCore.Identity 

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

_ViewImports.cshtml文件一般放在Pages或Views文件夹中。该文件只能应用于所在文件夹及其子文件夹中的页面或视图。如果在文件层次结构中找到多个_ViewImports.cshtml 文件,则指令的规则如下。

@addTagHelepr、@removeTagHelper: 按顺序全部运行; 

@tagHelperPrefix: 距离视图最近的tagHelperPrefix会覆盖任何其他tagHelperPrefix;  

@model: 距离视图最近的model会覆盖任何其他model; 

@inherits: 距离视图最近的inherits会覆盖任何其他inherits; 

@using: 全部包括在内,忽略重复项; 

@inject: 针对每个属性,最接近视图的属性会替代具有相同属性名的其他属性。

3. 先于视图文件之前执行

_ViewStart.cshtml会在所有视图被执行之前运行,如一些不便或不能在母版页中进行的统一操作可以将这些代码置于_ViewStart.cshtml文件中。通常这些应用级别版本的文件应直接放置在 /Pages(或/Views)文件夹中。

_ViewStart.cshtml与_ViewImports.cshtml文件类似,也采用分层结构。如果在View的某个目录下(例如Home目录)存在一个同名的_ViewStart.cshtml文件,那么这个_ViewStart文件也会被调用,但最先调用根目录下的_ViewStart文件,然后才是Home目录下的_ViewStart文件。

5.5.3使用布局



视频讲解


【例516】使用布局。

① 打开例515项目,选择Pages/Shared目录,右击,在弹出的快捷菜单中选择“添加”→“新建项”命令,如图529所示。



图529添加新建项


② 选择“Razor布局”选项,文件名称默认为_Layout1.cshtml,单击“添加”按钮,如图530所示。



图530添加Razor布局


③ 修改_Layout1.cshtml,代码如下。

<html>

<head>

<meta name="viewport" content="width=devicewidth" />

<title>@ViewBag.Title</title>

</head>

<body>

<h1>图书信息</h1>

<div id="mainDiv">

@RenderBody()

</div>

</body>

</html>

④ 设置所有页面使用_Layout1布局。打开_ViewStart.cshtml文件,修改Layout并设置为_Layout1。代码如下: 

@{

Layout = "_Layout1";

}

⑤ 调试、运行该程序,在现有浏览器地址后面输入/bookinfo/list并按Enter键,显示图书列表页面,如图531所示。



图531列表页面


⑥ 单击“添加”“修改”“删除”链接后结果如图532~图534所示。


⑦ 如果只有项目列表页面使用_Layout1布局,打开List.cshtml文件,添加代码如下。

@{

ViewData["Title"] = "List";

Layout = "_Layout1";

}




图532添加页面





图533修改页面





图534删除页面


⑧ 调试、运行该程序,发现只有列表页面布局发生了改变,其他页面并没有变化。读者可自行调试、运行。

小结

本章首先介绍了Razor Pages的基本概念,通过一个简单的示例介绍了Razor Pages应用程序的建立过程,然后介绍了Razor基本语法的使用,并通过一个示例介绍了Razor Pages中数据模型的建立及页面的添加、修改和删除过程,最后介绍了布局的概念及其应用。本章应重点掌握Razor Pages应用程序的建立。

习题

一、 作业题

1.  简述什么是Razor Pages技术。

2.  ASP.NET Core Web Application项目文件包含哪几部分?

3.  ASP.NET的布局方式有哪几种?

4.  简述Razor语法的特点。

二、 上机实践题

使用Razor Pages技术创建ASP.NET Core Web应用程序,可以显示学生个人信息,包含学生的学号、姓名、性别、家庭地址和联系方式,实现对学生个人信息的显示、添加、修改和删除,结果如图535~图538所示。



图535显示学生信息





图536添加学生信息





图537修改学生信息





图538删除学生信息