创建和引入
在创建Razor
页面时的时候,如果勾选:
就可以看到,在.cshtml
文件中,有这样的代码:
@model Demo.Pages.RegisterModel
在RegisterModel
上F12转到定义,可以知道RegisterModel
其实是一个类,继承自PageModel
。
(演示:略)
注意其命名规范:类名同Page
名,后加Model
后缀
此外,注意:
- 组合之后的
page
可以有多个@model
声明,但只能有一个@page
声明
Handler Methods
PageModel
可以自定义的处理HTTP请求。
如果razor页面没有model
声明,ASP.NET按默认设置直接输出.cshtml文件编译后的HTML内容;
否则,会进入Handler Mthods
PageModel
根据 HTTP请求的方式(request methods)来确定调用方法:On+RequestMethod(),所以除了OnGet()
方法,还有OnPost()
方法等
OnGet()
和OnPost()
PageModel
可以:按Http请求的Method
不同,分别处理。
复习:Get
和Post
在razor
页面被添加的时候,其PageModel
中就自动包含了一个OnGet()
方法,这被称之为handler methods
。用于处理HTTP GET
请求。
因为在运行时,ASP.NET会在PageModel
中选择调用OnGet()/OnPost()方法,所以一个PageModel
中:
- 可以同时有
OnGet()
和OnPost()
方法,但 - 不可以有多个
OnGet()
方法(或者多个OnPost()
方法等),用参数重载区分也不行(会运行时错误) OnGet()
和OnPost()
不用带参数
(演示)
Request
和Response
在OnGet()
方法中,因为继承了PageModel
,所以可以调用PageModel
的一些常用属性,如:
Request
:Http请求相关信息,常用的有:Header/Body、Cookies、Form/Query、Path、Schema
等Response
:返回客户端的相应信息,常用的有:Header/Body、Cookies、StatusCode
等ViewData
:存储页面(View
)所需要的数据(Data
)HttpContext
:当前请求的上下文信息,除了Request
和Response
,还有Connection、Session、WebSocket
等有用信息- ……
以及一些方法,比如:RedirectToPage()
,用于重定向到某一个页面。
@想一想@:Request
对象是怎么生成的?
SampleModel model = new SampleModel(); //反射
model.Request = new HttpRequest{ Header = }
model.OnGet();
强调:一个注册过程,里面至少是两次请求
还有可能再加一个重定向(Redirect
),后文详述。
其指定的
作为数据容器:在Page
和PageModel
之间传递数据
向Razor
页面传递数据
方式(一)强类型
通过在Razor
页面调用@Model
,可以得到PageModel
中的公共类成员(通常是属性)
public string Greet { get; } = "Hello, 源栈欢迎您!";
<h4>@Model.Greet</h4>
方式(二)弱类型
另外一种方法是使用ViewData[]
:
public void OnGet()
{
ViewData["title"] = "注册";
}
<title>@ViewData["title"]</title>
注意:ViewData[]
的优势是方便,但它是Object
类型,且Key
值没有智能提示,使用时需要格外注意
常见错误:NullReferenceException
public void OnGet()
{
if (LogOnSuccess())
{
//其他代码……
ViewData["Success"] = true;
}
}
@if ((bool)ViewData["Success"])
{
<h3>欧耶!成功登陆</h3>
}
else
{
<h3 style="color:red;" >登录失败</h3>
}
背后原理
ViewData
是哪里蹦出来的?(复习)
所有的页面数据存储在ViewData
中,其中又分为两种形式:
-
索引器:在
PageModel
和.cshtml
中都可以读/写(演示:_Layout
使用内容页的ViewData["title"]
) -
Model
属性:
如果说.cshtml文件标明了@page
且指定了@model
,ViewData.Model
就会(通过泛型)被设定为@model
指定的实例对象;public class Pages_LogOn : global::Microsoft.AspNetCore.Mvc.RazorPages.Page { public LogOnModel Model => ViewData.Model; }
否则,
ViewData.Model
就会被编译成dynamic
类型变量(布局页)或页面类型(奇怪?)public class Pages_Layout__All :global::Microsoft.AspNetCore.Mvc.Razor.RazorPage<dynamic>
public class Pages_Index : global::Microsoft.AspNetCore.Mvc.RazorPages.Page { public Pages_Index Model => ViewData.Model; }
(演示:查看.cshtml编译后文件)
所以,在_Layout
中使用内容页的数据,可以通过三种方式实现:
ViewData["Title"]
:内容页赋值,_Layout
直接使用@Model.Title
:Title
是PageModel
属性。因为是dynamic
,所以没有智能提示哟PageModel
继承
为添加_Layout.cshtml
添加一个_LayoutModel
类,并在_Layout.cshtml
页面引入
public class _LayoutModel : PageModel
{
public string Title { get; set; }
}
@model Demo.Pages.Shared._LayoutModel
让内容页的Model
继承自_LayoutModel
,并在其中为Title
赋值
public class IndexModel : _LayoutModel
{
public void OnGet([Bind("invitedBy")]string invitedBy)
{
Title = "首页·一起帮";
//ViewData["title"] = "首页·一起帮";
}
}
演示:求助列表呈现
ProblemRepository.Get()
模拟- 分页链接(传递和获取)
- 显示当前第n页
告诉服务器:想要哪一页 pageIndex = 3
服务器再根据每一页呈现的数量 pageSize = 10
进行计算,呈现:21-30 条
计算公式:从(pageIndex-1)*pageSize+1
开始,取pageSize
条
URL:/Article?pageIndex=3
后台OnGet()
里面
int pageIndex = Convert.ToInt32(Request.Query["pageIndex"][0]);