首页 > 其他分享 >第23章 Razor Pages

第23章 Razor Pages

时间:2024-05-11 09:53:24浏览次数:13  
标签:Razor Product 23 Pages public context id

  Razor Pages是生成Html响应的一种简化方式。它的简单性,意味着能够比MVC框架更快获得结果。它将单个视图与一个类关联起来,由该类为视图提供功能,并使用基于文件的路由系统来匹配URL。它的灵活性不如MVC,所以不适合复杂的应用程序。

1 准备工作

2 理解Razor Pages

  Razor Pages和MVC并不是二选一的情况,是可以共存的,Razor Pages以牺牲灵活性来换取专注度,将标记与C#代码捆绑在一起。

2.1 配置Razor Pages

在Startup中添加配置。

services.AddRazorPages().AddRazorRuntimeCompilation();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapDefaultControllerRoute();
    endpoints.MapRazorPages();
});

  AddRazorPages用于设置Razor Pages必须用到的服务,而可选的AddRazorRuntimeCompilation则启用运行时重新编译。MapRazorPages创建路由配置,用于将URL匹配到页面。

2.2 创建Razor Pages

  Razor Pages是在Pages文件夹中定义的,添加Pages文件夹并创建Index.cshtml的Razor Pages文件。

@page
@model IndexModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@using MyWebApp.Models

<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <div class="bg-primary text-white text-center m-2 p-2">@Model.Product.Name</div>
</body>
</html>

@functions
{
    public class IndexModel : PageModel
    {
        private DataContext context;

        public Product Product { get; set; }

        public IndexModel(DataContext ctx)
        {
            context = ctx;
        }

        public async Task OnGetAsync(long id = 1)
        {
            Product = await context.Products.FindAsync(id);
        }
    }
}

  在Razor Pages中,@page指令必须第一个出现,这确保不会将该文件误认为与控制器关联在一起的视图。最重要的区别是使用@functions指令在同一个文件中定义支持Razor内容的C#代码。启动程序浏览器请求http://localhost:5000/index。

3 理解Razor Pages的路由

  Razor Pages依赖于cshtml文件位置来进行路由,要添加复杂URL结构,可以添加文件夹。Pages文件夹下添加Suppliers文件夹,再添加List.cshtml的Razor Pages。访问http://localhost:5000/suppliers/list。

@page
@model ListModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@using MyWebApp.Models;

<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <h5 class="bg-primary text-white text-center m-2 p-2">Suppliers</h5>
    <ul class="list-group m-2">
        @foreach (string s in Model.Suppliers)
        {
            <li class="list-group-item">@s</li>
        }
    </ul>
</body>
</html>

@functions {

    public class ListModel : PageModel
    {
        private DataContext context;

        public IEnumerable<string> Suppliers { get; set; }

        public ListModel(DataContext ctx)
        {
            context = ctx;
        }

        public void OnGet()
        {
            Suppliers = context.Suppliers.Select(s => s.Name);
        }
    }
}

  注意:当混和了Razor Pages和MVC时框架时,可以在配置中修改端点路由语句顺序,endpoints.MapRazorPages()放到endpoints.MapControllers()前面,先配置谁就由谁来设置默认路由。

3.1 在Razor Pages中指定路由模式

  使用文件结构来执行路由,可以从URL查询中获取请求处理程序方法的值。请求http://localhost:5000/index?id=2,可以对应上OnGetAsync(long id = 1)方法中定义的参数。
  可以在@page指令中使用路由模式。@page "{id:long?}",请求http://localhost:5000/index/4。
  @page指令可用于覆盖Razor Pages的基于文件的路由约定。@page "/lists/suppliers,请求http://localhost:5000/lists/suppliers。

3.2 为Razor Pages添加路由

  如果想为页面定义多个路由,可在Startup类配置。

services.Configure<RazorPagesOptions>(options =>
{
    options.Conventions.AddPageRoute("/Index", "/extra/page/{id:long?}");
});

  这里RazorPagesOptions类为Razor Pages添加额外路由。AddPageRoute方法的第一个实参相对于Pages文件夹页面路径,第二个实参是要添加路由配置的URL模式。请求http://localhost:5000/extra/page/2。

4 理解页面模型类

  页面模型派生自PageModel类,它提供一些方法处理请求,并使用一些属性提供上下文数据。但在Razor Pages开发中常常不需要使用他们,因为开发更关注选择必要数据来渲染页面的视图部分。

4.1 使用代码隐藏类文件

  把@functions指令中的类移到Index.cshtml.cs中,并修修改Index.cshtml。

@page "{id:long?}"
@model MyWebApp.Pages.IndexModel
<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <div class="bg-primary text-white text-center m-2 p-2">@Model.Product.Name</div>
</body>
</html>

添加视图导入文件
  视图导入文件可用于避免在视图文件中使用模型的全类名,添加_ViewImports.cshtml文件。这样Index.cshtml中就这样写@model IndexModel

@namespace MyWebApp.Pages
@using MyWebApp.Models

4.2 理解Razor Pages的操作结果

  Razor Pages处理程序方法使用IActionResult接口来控制生成的响应。

public async Task<IActionResult> OnGetAsync(long id = 1)
{
    Product = await context.Products.FindAsync(id);
    return Page();
}

使用操作结果
  在没请求到数据时,相比使用NotFound方法,更好的方法是将客户端重定向到另一个URL。添加NotFound.cshtml的Razor Pages。

@page "/noid"
@model NotFoundModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@using WebApp.Models;

<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <title>Not Found</title>
</head>
<body>
    <div class="bg-primary text-white text-center m-2 p-2">No Matching ID</div>
    <ul class="list-group m-2">
        @foreach (Product p in Model.Products) {
            <li class="list-group-item">@p.Name (ID: @p.ProductId)</li>                
        }
    </ul>    
</body>
</html>

@functions {

    public class NotFoundModel: PageModel {
        private DataContext context;

        public IEnumerable<Product> Products { get; set; }

        public NotFoundModel(DataContext ctx) {
            context = ctx;
        }

        public void OnGetAsync(long id = 1) {
            Products = context.Products;
        }
    }
}

  更新了IndexModel类的处理如下,当请求http://localhost:5000/index/500时,Product没有查询到数据,则将用户重定向到NotFound页面。

public async Task<IActionResult> OnGetAsync(long id = 1)
{
    Product = await context.Products.FindAsync(id);
    if(Product == null)
    {
        return RedirectToPage("NotFound");
    }
    return Page();
}

4.3 处理多个HTTP方法

  Razor Pages可以定义多个处理程序方法来响应HTTP方法。常见的GET、POST方法。下面添加Editor.cshtml的Razor Pages。

@page "{id:long}"
@model EditorModel

<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <div class="bg-primary text-white text-center m-2 p-2">Editor</div>
    <div class="m-2">
        <table class="table table-sm table-striped table-bordered">
            <tbody>
                <tr><th>Name</th><td>@Model.Product.Name</td></tr>
                <tr><th>Price</th><td>@Model.Product.Price</td></tr>
            </tbody>
        </table>
        <form method="post">
            @Html.AntiForgeryToken()
            <div class="form-group">
                <label>Price</label>
                <input name="price" class="form-control" 
                       value="@Model.Product.Price" />
            </div>
            <button class="btn btn-primary" type="submit">Submit</button>
        </form>
    </div>
</body>
</html>

  此视图定义的form元素不包含action特性,这意味着当单击Submit按钮时发送一个Post请求。
  在Editor.cshtml.cs中添加如下。OnGetAsync方法用于处理Get请求,OnPostAsync处理Post请求。

    public class EditorModel : PageModel
    {
        private DataContext context;

        public Product Product { get; set; }

        public EditorModel(DataContext ctx)
        {
            context = ctx;
        }

        public async Task OnGetAsync(long id)
        {
            Product = await context.Products.FindAsync(id);
        }

        public async Task<IActionResult> OnPostAsync(long id, decimal price)
        {
            Product p = await context.Products.FindAsync(id);
            p.Price = price;
            await context.SaveChangesAsync();
            return RedirectToPage();
        }
    }

  请求http://localhost:5000/editor/1,编辑字段修改价格并提交,数据将被更新。

4.4 选择处理程序方法

  页面模型类可定义多个处理程序方法,允许请求使用handler查询字符串参数或者路由片段来选择方法。添加HandlerSelector.cshtml的Razor Pages如下。

@page
@model HandlerSelectorModel
@using Microsoft.AspNetCore.Mvc.RazorPages
@using Microsoft.EntityFrameworkCore

<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
    <div class="bg-primary text-white text-center m-2 p-2">Selector</div>
    <div class="m-2">
        <table class="table table-sm table-striped table-bordered">
            <tbody>
                <tr><th>Name</th><td>@Model.Product.Name</td></tr>
                <tr><th>Price</th><td>@Model.Product.Name</td></tr>
                <tr><th>Category</th><td>@Model.Product.Category?.Name</td></tr>
                <tr><th>Supplier</th><td>@Model.Product.Supplier?.Name</td></tr>
            </tbody>
        </table>
        <a href="/handlerselector" class="btn btn-primary">Standard</a>
        <a href="/handlerselector?handler=related" class="btn btn-primary">
            Related
        </a>
    </div>
</body>
</html>

@functions{

    public class HandlerSelectorModel: PageModel {
        private DataContext context;

        public Product Product { get; set; }

        public HandlerSelectorModel(DataContext ctx) {
            context = ctx;
        }

        public async Task OnGetAsync(long id = 1) {
            Product = await context.Products.FindAsync(id);
        }

        public async Task OnGetRelatedAsync(long id = 1) {
            Product = await context.Products
                .Include(p => p.Supplier)
                .Include(p => p.Category)
                .FirstOrDefaultAsync(p => p.ProductId == id);
            Product.Supplier.Products = null;
            Product.Category.Products = null;
        }
    }
}

  本页面模型定义了OnGetAsync和OnGetRelatedAsync两个方法,请求http://localhost:5000/handlerselector默认使用OnGetAsync,可以用参数来决定目标URL,/handlerselector?handler=related,参数可以不用On前缀和Async后缀。

5 理解Razor Pages视图

  Razor Pages视图语法等与控制器的基本相同。

5.1 为Razor Pages创建布局

  创建Shared文件夹,添加_Layout.cshtml文件。

<!DOCTYPE html>
<html>
<head>
    <link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <title>@ViewBag.Title</title>
</head>
<body>
    <h5 class="bg-secondary text-white text-center m-2 p-2">
        Razor Page
    </h5>
    @RenderBody()
</body>
</html>

  在Pages文件夹中添加_ViewStart.cshtml的文件。

@{
    Layout = "_Layout";
}

  修改Index.cshtml。

@page "{id:long?}"
@model IndexModel

<div class="bg-primary text-white text-center m-2 p-2">@Model.Product.Name</div>

  _ViewStart文件将布局应用到所有覆盖Layout属性值的页面。
  Editor.cshtml中禁用布局。

@{
    Layout = null;
}

  请求http://localhost:5000/index看到新布局,请求http://localhost:5000/editor/1将看到没有布局。

5.2 在Razor Pages中使用分部视图

  使用分部视图拉避免重复公共内容。
  在Pages/_ViewImports.cshtml中添加如下。

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

  在Pages/Shared添加_ProductPartial.cshtml视图。

@model Product

<div class="m-2">
    <table class="table table-sm table-striped table-bordered">
        <tbody>
            <tr><th>Name</th><td>@Model.Name</td></tr>
            <tr><th>Price</th><td>@Model.Price</td></tr>
        </tbody>
    </table>
</div>

  在Index.cshtml中使用分部视图。

@page "{id:long?}"
@model IndexModel

<div class="bg-primary text-white text-center m-2 p-2">@Model.Product.Name</div>
<partial name="_ProductPartial" model="Model.Product" />

5.3 创建没有页面模型的Pazor Pages

  如果Pazor Pages只是简单地向用户展示数据,那么结果可以是一个页面模型类。
  在Pages文件夹中添加Data.cshtml的Pazor Pages。当页面模型只用于访问服务,而不添加其他操作时,可使用@inject指令在视图中获取服务,并不需要使用页面模型。

@page
@inject DataContext context;

<h5 class="bg-primary text-white text-center m-2 p-2">Categories</h5>
<ul class="list-group m-2">
    @foreach (Category c in context.Categories)
    {
        <li class="list-group-item">@c.Name</li>
    }
</ul>

标签:Razor,Product,23,Pages,public,context,id
From: https://www.cnblogs.com/nullcodeworld/p/18185810

相关文章

  • NewStarCTF 2023 week1 writeup
    NewStarCTF2023week1writeup花了几天时间,终于把week1的题目做完了,还是学到不少东西的,题目质量大多都挺高的,很适合新手入门。Web1.泄漏的秘密url/robots.txt查看robots协议,找到第一部分的flagPARTONE:flag{r0bots_1s_s0_us3fulurl/www.zip查看网站备份,找到第二部分的fla......
  • 力扣-232. 用栈实现队列
    1.题目信息2.题解2.1双栈的使用(用栈实现队列)思路我们一开始可能会想到对于每次入栈操作——由于我们可能希望他是加在队尾(栈底)而不是队头(栈首),所以我们就进行一次首尾互换,将instack中的数据倒腾到outstack,由于栈先进后出的特性,所以这时候原来的栈底在头部,我们直接将元素pus......
  • hdu1233还是畅通工程
    首先按每两个村庄的距离从小到大排序,因为最小距离的那条道路是必建造的;每输入两个数,看他俩的老大是否一样,如果一样的话,说明这两已经连通了,不需要建造了,反之则建造。importjava.util.Arrays;importjava.util.Scanner;publicclasshdu1233{ publicstaticvoidmain(Str......
  • 2023年书单
    2023年书单:01.柏拉图《理想国》(2023.01.20读完)02.尼科洛·马基雅维里(意)《君主论》(2023.02.26读完)03.杨绛《我们仨》(2023.03.07读完)04.毛姆(英)《面纱》(2023.03.16读完)05.伊塔洛·卡尔维诺(意)《分成两半的子爵》(2023.04.22读完)06.赫尔曼·黑塞(德)《悉达多》(2023.05.04读完)07.罗......
  • 界面控件开发包DevExpress v23.2.6全新发布|附高速下载
    DevExpress拥有.NET开发需要的所有平台控件,包含600多个UI控件、报表平台、DevExpressDashboardeXpressApp框架、适用于VisualStudio的CodeRush等一系列辅助工具。屡获大奖的软件开发平台DevExpress近期重要版本v23.2已正式发布,该版本拥有众多新产品和数十个具有高影响力的功......
  • #23 2024.5.7
    838.soj2066聚会839.soj2067重复序列840.soj2068白兔的村庄一个很厉害的题。841.soj2069量子计算842.soj2070字符串模板题厉害。843.soj2071美丽魔法844.soj2072moon845.soj2073为了你唱下去846.loj3523「IOI2021」分糖果847.loj3524「IOI202......
  • 2023数模国赛学习——(C)
    题目在生鲜商超中,一般蔬菜类商品的保鲜期都比较短,且品相随销售时间的增加而变差,大部分品种如当日未售出,隔日就无法再售。因此,商超通常会根据各商品的历史销售和需求情况每天进行补货。由于商超销售的蔬菜品种众多、产地不尽相同,而蔬菜的进货交易时间通常在凌晨3:00~4:00,为此......
  • P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G
    链接:https://www.luogu.com.cn/problem/P2341题目:思路:tarjan缩点:把所有强连通分量缩成一个点,然后统计出度为0的缩点,如果只有一个,那么能成为明星的数量就是该缩点扩充后的个数;如果不止一个,那就是0.代码:额,就是不知道为什么debug了两节课.......#include<iostream>#include<v......
  • 在SpringCloud2023中快速集成SpringCloudGateway网关
    你好,这里是codetrend专栏“SpringCloud2023实战”。本文主要简单介绍SpringCloud2023实战中SpringCoudGateway的搭建。后续的文章将会介绍在微服务中使用熔断Sentinel、鉴权OAuth2、SSO等技术。前言网关的选型不多,目前spring支持和维护的项目是SpringCloudGateway。Spring......
  • 界面组件DevExpress Blazor UI v23.2亮点 - 图表组件全新升级
    DevExpress BlazorUI组件使用了C#为BlazorServer和BlazorWebAssembly创建高影响力的用户体验,这个UI自建库提供了一套全面的原生BlazorUI组件(包括PivotGrid、调度程序、图表、数据编辑器和报表等)。DevExpress Blazor控件目前已经升级到v23.2版本了,此版本进一步增强了图表组......