asp.net core系列 39 Razor 介绍与详细示例
原文:asp.net core系列 39 Razor 介绍与详细示例
一. Razor介绍
在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor。 这样开发Web包括了MVC框架和Razor框架。对于Razor来说它是一个新特性,在官方介绍ASP.NET Core的优点中提到“Razor Pages可以使基于页面的编码方式更简单高效”。
1.1 Razor结构介绍
(1) Pages文件夹
存放所有Razor页面,包括Razor 页面和支持文件。 每个 Razor 页面都是一对文件:
一个 .cshtml 文件,其中包含使用 Razor 语法的 C# 代码的 HTML 标记。
一个 .cshtml.cs 文件,其中包含处理页面事件的 C# 代码。
支持文件的名称以下划线开头。 例如,_Layout.cshtml 文件可配置所有页面通用的 UI 元素。 此文件设置页面顶部的导航菜单和页面底部的版权声明(后面讲布局时再介绍)。
(2) wwwroot 文件夹
包含静态文件,如 HTML 文件、JavaScript 文件和 CSS 文件(后面再讲)。
(3) appSettings.json
包含配置数据,如连接字符串。参考asp.net core 系列第 10和11篇
(4) Program.cs
包含程序的入口点,启动主机。参考asp.net core 系列第 16和17篇
(5) startup.cs
包含配置应用行为的代码,例如,是否需要同意 cookie。参考asp.net core 系列第 2篇

1.2 启动Razor关键代码
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Includes support for Razor Pages and controllers.
services.AddMvc();
} public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
}
1.3 @page指令
对于每一个Razor 页面,在.cshtml视图文件中,@page指令必须是页面上的第一个 Razor 指令。@page 使文件转换为一个 MVC 操作 ,这意味着它将直接处理请求, 而不通过控制器(Controllers)处理。@page 将影响其他 Razor 构造的行为。下面是一个直接处理请求的示例:
//index.cshtml.cs
public class IndexModel : PageModel
{
public string Message { get; private set; } = "PageModel in C#"; //加载时调用
public void OnGet()
{
Message += $" Server time is { DateTime.Now }";
}
} //Index.cshtml,直接输出后端的Message属性信息,也这是Razor的优势,使用页面的编码方式更简单高效。
@page
@using RazorPagesIntro.Pages
@model IndexModel <h2>Separate page model</h2>
<p>
@Model.Message
</p>
1.4 页面url路径
URL路径是与页面的关联,由页面在文件系统中的位置决定,下表显示了Razor Page路径和匹配的URL:
| 文件路径 | 访问网址 |
| /Pages/Index.cshtml | / or /Index |
| /Pages/Contact.cshtml | /Contact |
| /Pages/Store/Contact.cshtml | /Store/Contact |
| /Pages/Store/Index.cshtml | /Store or /Store/Index |
二. 完整示例介绍
2.1 安装EF数据提供程序
这里使用内存数据库Microsoft.EntityFrameworkCore.InMemory,Entity Framework Core 和内存数据库一起使用, 这对测试非常有用。
PM> Install-Package Microsoft.EntityFrameworkCore.InMemory
2.2 新建数据模型类(POCO )和EF上下文类
public class Customer
{
public int Id { get; set; } //保存不能为空,字符长度小于100
[Required, StringLength()]
public string Name { get; set; }
} public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions options)
: base(options)
{
} public DbSet<Customer> Customers { get; set; }
}
2.3 启动类关键代码
public class Startup
{
public IHostingEnvironment HostingEnvironment { get; } public void ConfigureServices(IServiceCollection services)
{
// 使用内存数据库
services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("name"));
services.AddMvc();
} public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
}
2.4 新增页 Pages/Create
@page
@model StudyRazorDemo.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<html>
<body>
<p>
Enter your name.
</p>
<div asp-validation-summary="All"></div>
<form method="POST">
<!-- 这里的Customer对象来自后端-->
<div>Name: <input asp-for="Customer.Name" /></div>
<input type="submit" />
</form>
</body>
</html>
public class CreateModel : PageModel
{
private readonly AppDbContext _db; public CreateModel(AppDbContext db)
{
_db = db;
} //模型绑定,通过绑定使用相同的属性显示窗体字段<input asp-for="Customer.Name" />来减少代码,并接受输入,是双向绑定。
[BindProperty]
public Customer Customer { get; set; } public async Task<IActionResult> OnPostAsync()
{
//验证Customer对象属性值
if (!ModelState.IsValid)
{
return Page();
} //添加到EF上下文,再保存到内存数据库
_db.Customers.Add(Customer);
await _db.SaveChangesAsync(); // 重定向到index主页
return RedirectToPage("/Index");
}
}
点击提交后,cs后端的Customer对象将自动绑定来自前端转来的值,如下图所示:

2.5 查询主页Pages/Index 关键代码
<form method="post">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<!--Customers集合对象来自cs后端 -->
@foreach (var contact in Model.Customers)
{
<tr>
<td>@contact.Id</td>
<td>@contact.Name</td>
<td>
<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a> <button type="submit" asp-page-handler="delete"
asp-route-id="@contact.Id">
delete
</button>
</td>
</tr>
}
</tbody>
</table>
<a asp-page="./Create">Create</a>
</form>
public IList<Customer> Customers { get; private set; }
//代替OnGet方法
public async Task OnGetAsync()
{
//异步获取数据,EF上下文不跟踪该集合对象
Customers = await _db.Customers.AsNoTracking().ToListAsync();
}
所有asp- 开头的都是TagHelper内置标记,查询如下图所示:

2.6 修改页Pages/Edit关键代码
在主页中(<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a> )是导航到编辑页。例如:http://localhost:5000/Edit/1。
第一行包含 @page "{id:int}" 指令,是用来路由约束,如果页面请求未包含可转换为 int 的路由数据,则运行时返回 HTTP 404。若要使 ID可选,请将 ? 追加到路由约束( @page "{id:int?}" )
@page "{id:int}"
@model StudyRazorDemo.Pages.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<h1>Edit Customer - @Model.Customer.Id</h1>
<form method="post">
<!--验证失败时,提示所有错误信息 -->
<div asp-validation-summary="All"></div> <input asp-for="Customer.Id" type="hidden" />
<div>
<label asp-for="Customer.Name"></label>
<div>
<input asp-for="Customer.Name" /> <!--后端验证Name,当失败时提示错误信息 -->
<span asp-validation-for="Customer.Name"></span>
</div>
</div> <div>
<button type="submit">Save</button>
</div>
</form>
[BindProperty]
public Customer Customer { get; set; } public async Task<IActionResult> OnGetAsync(int id)
{
Customer = await _db.Customers.FindAsync(id); if (Customer == null)
{
return RedirectToPage("/Index");
}
return Page();
} public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
} _db.Attach(Customer).State = EntityState.Modified; try
{
await _db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
throw new Exception($"Customer {Customer.Id} not found!");
} return RedirectToPage("/Index");
}
通过ID来修改数据,如下图所示:

2.7 删除 Pages/index
删除动作是在index页面完成。使用处理事件asp-page-handler="delete" 来指定后端的action 为delete方法处理。 按照约定,方法命名为: OnPost[handler]Async ,方法参数为 asp-route-id传来的值。
/// <summary>
/// index后端,根据ID删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<IActionResult> OnPostDeleteAsync(int id)
{
var contact = await _db.Customers.FindAsync(id); if (contact != null)
{
_db.Customers.Remove(contact);
await _db.SaveChangesAsync();
} return RedirectToPage();
}
参考文献
asp.net core系列 39 Razor 介绍与详细示例的更多相关文章
- asp.net core 系列 8 Razor框架路由(下)
三.页面路由操作约定 接着上篇讲asp.net core 系列 7 Razor框架路由.在上篇继续第三节 "页面路由操作约定" 的最后一小节 AddPageRoute . 3.3. ...
- asp.net core系列 39 Web 应用Razor 介绍与详细示例
一. Razor介绍 在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor. 这样开发Web包括了MVC框架和Razor框架.对于Razor来说 ...
- asp.net core系列 46 Identity介绍
一. Identity 介绍 ASP.NET Core Identity是一个会员系统,可为ASP.NET Core应用程序添加登录功能.可以使用SQL Server数据库配置身份以存储用户名,密码和 ...
- asp.net core 系列 7 Razor框架路由(上)
一.概述 在上二篇中,主要是介绍了asp.net core mvc中路由的使用,这篇继续介绍路由在ASP.NET Core Razor中的使用.Razor Pages应该使用默认的传统路由,从应用程序 ...
- asp.net core 系列 19 EFCore介绍
一.概述 目前最新的EF Core版本是3.0,最稳定的EF Core版本是2.2.EF Core 的计划与 .NET Core以及 ASP.NET Core 版本同步.EF Core 是一个 .NE ...
- asp.net core系列 66 Dapper介绍--Micro-ORM
一.概述 目前对于.net的数据访问ORM工具很多,EF和EF Core是一个重量级的框架.最近在搭建新的项目架构,来学习一下轻量级的数据访问ORM工具Dapper.Dapper支持SQL Serve ...
- asp.net core系列 59 Ocelot 构建基础项目示例
一.入门概述 从这篇开始探讨Ocelot,Ocelot是一个.NET API网关,仅适用于.NET Core,用于.NET面向微服务/服务的架构中.当客户端(web站点.ios. app 等)访问we ...
- asp.net core系列 60 Ocelot 构建服务认证示例
一.概述 在Ocelot中,为了保护下游api资源,用户访问时需要进行认证鉴权,这需要在Ocelot 网关中添加认证服务.添加认证后,ReRoutes路由会进行身份验证,并使用Ocelot的基于声明的 ...
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
随机推荐
- core组件进阶
访问图像像素 存储方式 BGR连续存储有助于提升图像扫描速度. isContinuous()判断是否是连续存储. 颜色空间缩减 仅用这些颜色中具有代表性的很小的部分,就足以达到同样的效果. 将现有颜色 ...
- Linux Shell脚本编程-函数
函数介绍 定义:把一段独立功能的的代码当做一个整体,并为之一个名字,命名的代码段,此即为函数: 功能:函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程. 注意: ...
- HDU 4917 Permutation 拓扑排序的计数
题意: 一个有n个数的排列,给你一些位置上数字的大小关系.求合法的排列有多少种. 思路: 数字的大小关系可以看做是一条有向边,这样以每个位置当点,就可以把整个排列当做一张有向图.而且题目保证有解,所以 ...
- 【习题 8-19 UVA-1312】Cricket Field
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 添加两个y坐标0和h 然后从这n+2个y坐标中任选两个坐标,作为矩形的上下界. 然后看看哪些点在这个上下界中. 定义为坐标集合S S ...
- 洛谷—— P1877 [HAOI2012]音量调节
https://www.luogu.org/problem/show?pid=1877#sub 题目描述 一个吉他手准备参加一场演出.他不喜欢在演出时始终使用同一个音量,所以他决定每一首歌之前他都需要 ...
- hbase启动报错
前一段时间vmware上的ubuntu的hbase用不了了,而hadoop能正常的操作,非常的奇怪. 错误信息好像是connect fail, RPC什么的,看来跟网路有关. 想起以前曾经解决过hba ...
- 最全Pycharm教程(10)——Pycharm调试器总篇
最全Pycharm教程(1)--定制外观 最全Pycharm教程(2)--代码风格 最全Pycharm教程(3)--代码的调试.执行 最全Pycharm教程(4)--有关Python解释器的相关配置 ...
- HIToj--1076--Ordered Fractions(水题)
Ordered Fractions Source : Unknown Time limit : 3 sec Memory limit : 32 M Submitted : 1510, Ac ...
- centos7 双网卡设置(先NAT和后桥接)
摘要:VMware中搭建一台虚拟机192.168.161.5(NAT转发) 首先在VM虚拟机设置里面添加一块网卡适配器 设置为桥接模式 完成后等待自动配置 此时出现多了一个ens37 和本地网段一样的 ...
- 洛谷P3807 【模板】卢卡斯定理exgcd
题目背景 这是一道模板题. 题目描述 给定n,m,p(1\le n,m,p\le 10^51≤n,m,p≤105 ) 求 C_{n+m}^{m}\ mod\ pCn+mm mod p 保证P为pri ...