学习Razor知识知多少,2021学习Razor知识整理笔记,,最近使用Razor开发一个组件,到官网查看了相关的文档,记录一些要点
Razor知识整理笔记之Razor布局
- 布局文件可以放到任意目录,最佳的组织方式是放到相同页面风格的根目录,例如XXX管理,具有相同页面风格的 XXXManage根目录。
- 页面添加继承指令,@inherits LayoutComponentBase,这里的页面是指以razor结尾的文件,即 razor组件。
示例代码:
@inherits LayoutComponentBase <header> <h1>Doctor Who™ Episode Database</h1> </header> <nav> <a href="masterlist">Master Episode List</a> <a href="search">Search</a> <a href="new">Add Episode</a> </nav> @Body <footer> @TrademarkMessage </footer> @code { public string TrademarkMessage { get; set; } = "Doctor Who is a registered trademark of the BBC. " + "https://www.doctorwho.tv/"; }
MainLayout 布局组件
创建Blazor项目后,会在Shared默认包含MainLayout.razor文件,是整个应用的默认布局
@inherits LayoutComponentBase <div class="page"> <div class="sidebar"> <NavMenu /> </div> <div class="main"> <div class="top-row px-4"> <a href=https://jhrs.com" target="_blank" class="ml-md-auto">About</a> </div> <div class="content px-4"> @Body </div> </div> </div>
应用布局组件
使用Razor指令@layout 可以将布局组件应用于包含@page指令的页面(Razor页面),编译器转换@layout为LayoutAttribute并将该属性应用于组件类。
示例代码
@layout DoctorWhoLayout <h2>Episodes</h2> <ul> <li> <a href="https://znlive.com/programmes/p00vfknq"> <em>The Ribos Operation</em> </a> </li> <li> <a href="https://znlive.com/programmes/p00vfdsb"> <em>The Sun Makers</em> </a> </li> <li> <a href="https://znlive.com/programmes/p00vhc26"> <em>Nightmare of Eden</em> </a> </li> </ul>
直接在组件中指定布局会覆盖默认布局:
由@layout从_Imports组件 ( _Imports.razor)导入的指令设置。设置为应用程序的默认布局,如本文后面的将默认布局应用于应用程序部分中所述。
将布局应用到组件文件夹
应用程序的每个文件夹都可以选择包含一个名为_Imports.razor. 编译器将导入文件中指定的指令包含在同一文件夹中的所有 Razor 模板中,并递归地包含在其所有子文件夹中。因此,_Imports.razor包含的文件@layout DoctorWhoLayout可确保文件夹中的所有组件都使用该DoctorWhoLayout组件。无需重复添加@layout DoctorWhoLayout到.razor文件夹和子文件夹中的所有 Razor 组件 ( )。
_Imports.razor: @layout DoctorWhoLayout
路由知识点
一个razor组件可以有多个路由模板,示例代码:
@page “/BlazorRoute”
@page “/DifferentBlazorRoute”
这样的意思就是针对一个页面,可以输入如 https://jhrs.com/blazorroute 或者 https://jhrs.com/differentblazorroute来访问。对于服务器来说都是在一个页面上。
多程序集路由
多程序集路由允许从其它程序集(其它项目里面扫描路由,这样就支持子网站),示例代码:
<Router AppAssembly="@typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(Component1).Assembly }"> @* ... Router component elements ... *@ </Router>
路由参数
@page "/RouteParameter/{text}" <h1>Blazor is @Text!</h1> @code { [Parameter] public string Text { get; set; } }
支持可选参数。在以下示例中,text可选参数将路由段的值分配给组件的Text属性。如果该段不存在,则将 的值Text设置为fantastic。
Pages/RouteParameter.razor: @page "/RouteParameter/{text?}" <h1>Blazor is @Text!</h1> @code { [Parameter] public string Text { get; set; } protected override void OnInitialized() { Text = Text ?? "fantastic"; } }
路由约束
路由约束是限制路由参数,当参数类型正确匹配到路由后就呈现相关页面。
@page "/user/{Id:int}" <h1>User Id: @Id</h1> @code { [Parameter] public int Id { get; set; } }
参见路由约束文档:
https://docs.microsoft.com/zh-cn/aspnet/core/blazor/fundamentals/routing?view=aspnetcore-5.0#route-parameters-1
通配路由
通配路由是指通过使用*来匹配所有路由,无论有多少段组成都匹配成功,即URL通杀。
@page "/catch-all/{*pageRoute}" @code { [Parameter] public string PageRoute { get; set; } }
上面的匹配模式代码为/catch-all/{*pageRoute},对于像/catch-all/this/is/a/test的地址, PageRoute设置为this/is/a/test,即通配了 this/is/a/test 段的URL。
捕获路径的斜线和段被解码。对于 的路由模板/catch-all/{*pageRoute},URL/catch-all/this/is/a%2Ftest%2A产生this/is/a/test*。
NavigationManager(导航管理器)用于通过C#代码进行路由跳转(页面跳转),跟传统的asp.net webform使用重定向跳转类似。
NavigationManager提供的方法和事件如下表所示:
使用示例代码:
@page "/navigate" @using Microsoft.Extensions.Logging @implements IDisposable @inject ILogger<Navigate> Logger @inject NavigationManager NavigationManager <h1>Navigate in component code example</h1> <button class="btn btn-primary" @onclick="NavigateToCounterComponent"> Navigate to the Counter component </button> @code { private void NavigateToCounterComponent() { NavigationManager.NavigateTo("counter"); } protected override void OnInitialized() { NavigationManager.LocationChanged += HandleLocationChanged; } private void HandleLocationChanged(object sender, LocationChangedEventArgs e) { Logger.LogInformation("URL of new location: {Location}", e.Location); } public void Dispose() { NavigationManager.LocationChanged -= HandleLocationChanged; } }
查询字符串与解析
一个请求的查询字符串从NavigationManager.Uri 属性获得
@inject NavigationManager NavigationManager ... var query = new Uri(NavigationManager.Uri).Query;
要解析查询字符串的参数,一种方法是URLSearchParams与JavaScript (JS) interop 一起使用:
下面是js代码:
export createQueryString = (string queryString) => new URLSearchParams(queryString);
路由器组件可以向用户指示正在发生页面转换。
在顶层(根目录)的App.razor)文件中使用@using指令添加命名空间Microsoft.AspNetCore.Components.Routing 的引用
@using Microsoft.AspNetCore.Components.Routing
将 <Navigating> 标记添加到带有标记的组件,以便在页面转换事件期间显示。在 App 组件(App.razor)的路由器元素内容(<Router>…</Router>)中:
<Navigating> <p>Loading the requested page…</p> </Navigating>
路由器组件支持 OnNavigateAsync 功能。 当用户执行以下操作时调用 OnNavigateAsync 处理程序:
通过直接在浏览器中导航到该路线,首次访问该路线。
使用链接或 NavigationManager.NavigateTo 调用导航到新路线。
在 App 组件(App.razor)中:
<Router AppAssembly="@typeof(Program).Assembly" OnNavigateAsync="@OnNavigateAsync"> ... </Router> @code { private async Task OnNavigateAsync(NavigationContext args) { ... } }
有关使用OnNavigateAsync的示例,请参阅ASP.NET Core Blazor WebAssembly 中的延迟加载程序集。
在 Blazor 服务器应用程序或托管的 Blazor WebAssembly 应用程序中的服务器上进行预渲染时,OnNavigateAsync执行两次:
一旦请求的端点组件最初静态呈现。
第二次当浏览器呈现端点组件时。
为了防止OnNavigateAsync 中的开发人员代码执行两次,App
组件可以存储NavigationContext以供在OnAfterRender
/ 中OnAfterRenderAsync
使用,在那里firstRender
可以检查。有关详细信息,请参阅Blazor 生命周期文章中的检测应用程序何时预呈现。
传递给OnNavigateAsync回调的NavigationContext对象包含在发生新导航事件时设置的CancellationToken。该OnNavigateAsync当该取消标记设置为避免继续运行回调必须抛出OnNavigateAsync一个过时的导航回调。
如果用户导航到一个终结点,但随后立即导航到一个新的终结点,应用程序不应继续为第一个终结点运行OnNavigateAsync回调。
在以下App
组件示例中:
取消令牌在对 的调用中传递PostAsJsonAsync
,如果用户导航离开/about
端点,则可以取消 POST 。
如果用户导航离开/store
端点,则在产品预取操作期间设置取消令牌。
App.razor
:
@inject HttpClient Http @inject ProductCatalog Products <Router AppAssembly="@typeof(Program).Assembly" OnNavigateAsync="@OnNavigateAsync"> ... </Router> @code { private async Task OnNavigateAsync(NavigationContext context) { if (context.Path == "/about") { var stats = new Stats = { Page = "/about" }; await Http.PostAsJsonAsync("api/visited", stats, context.CancellationToken); } else if (context.Path == "/store") { var productIds = [345, 789, 135, 689]; foreach (var productId in productIds) { context.CancellationToken.ThrowIfCancellationRequested(); Products.Prefetch(productId); } } } }
创建导航链接时,使用NavLink组件代替 HTML 超链接元素 ( <a>
)。一个NavLink像一个组件的行为<a>
元素,但它切换的active
基础上无论是其CSS类href
匹配当前的URL。本active
类帮助用户了解哪些页面显示的导航链接中的活动页面。可以指派一个CSS类名NavLink.ActiveClass到自定义CSS类适用于渲染链接时,当前的路由匹配href
。
以下NavMenu
组件创建一个Bootstrap
导航栏,演示如何使用NavLink组件:
<div class="@NavMenuCssClass" @onclick="@ToggleNavMenu"> <ul class="nav flex-column"> <li class="nav-item px-3"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="oi oi-home" aria-hidden="true"></span> Home </NavLink> </li> <li class="nav-item px-3"> <NavLink class="nav-link" href="component" Match="NavLinkMatch.Prefix"> <span class="oi oi-plus" aria-hidden="true"></span> Link Text </NavLink> </li> </ul> </div> @code { private string NavMenuCssClass; private void ToggleNavMenu() {} }
有两个NavLinkMatch选项可以分配给元素的Match
属性<NavLink>
:
- NavLinkMatch.All:当NavLink匹配整个当前 URL 时,它处于活动状态。
- NavLinkMatch.Prefix(默认):NavLink在匹配当前 URL 的任何前缀时处于活动状态。
在前面的示例中,Home NavLink href=""
匹配主页 URL,并且仅接收active
应用程序默认基本路径 URL(例如,https://localhost:5001/
)处的 CSS 类。当用户访问任何带有前缀(例如,和)的URL 时,第二个NavLink接收active
该类。componenthttps://localhost:5001/componenthttps://localhost:5001/component/another-segment
其他NavLink组件属性会传递到呈现的锚标记。在以下示例中,NavLink组件包含target
属性:
<NavLink href=”example-page” target=”_blank”>Example page</NavLink>
呈现以下 HTML 标记:
<a href=”example-page” target=”_blank”>Example page</a>
循环输出的导航链接代码需要注意的是在循环体中要引用一个临时变量:
@for (int c = 0; c < 10; c++) { var current = c; <li ...> <NavLink ... href="@c"> <span ...></span> @current </NavLink> </li> }
如果使用foreach输出的话,则这样:
@foreach(var c in Enumerable.Range(0,10)) { <li ...> <NavLink ... href="@c"> <span ...></span> @c </NavLink> </li> }
依赖注入
razor组件中注入方法@inject
@page "/customer-list" @inject IDataAccess DataRepository @if (customers != null) { <ul> @foreach (var customer in customers) { <li>@customer.FirstName @customer.LastName</li> } </ul> } @code { private IReadOnlyList<Customer> customers; protected override async Task OnInitializedAsync() { customers = await DataRepository.GetAllCustomersAsync(); } private class Customer { public string FirstName { get; set; } public string LastName { get; set; } } private interface IDataAccess { public Task<IReadOnlyList<Customer>> GetAllCustomersAsync(); } }
在内部,生成的属性 ( DataRepository
) 使用[Inject]
属性。通常,不直接使用此属性。如果组件需要基类并且基类也需要注入的属性,请手动添加[Inject]
属性:
using Microsoft.AspNetCore.Components; public class ComponentBase : IComponent { [Inject] protected IDataAccess DataRepository { get; set; } ... }
在从基类派生的组件中,@inject
不需要该指令。基类的InjectAttribute就足够了:
@page "/demo" @inherits ComponentBase <h1>Demo Component</h1>
在服务中使用DI
复杂的服务可能需要额外的服务。在以下示例中,DataAccess
需要HttpClient默认服务。@inject
(或[Inject]
属性)不可用于服务。必须改用构造函数注入。通过向服务的构造函数添加参数来添加所需的服务。当 DI 创建服务时,它会在构造函数中识别它需要的服务并相应地提供它们。在以下示例中,构造函数通过 DI接收HttpClient。HttpClient是默认服务。
using System.Net.Http; public class DataAccess : IDataAccess { public DataAccess(HttpClient http) { ... } }
构造函数注入的先决条件:
- 必须存在一个构造函数,其参数都可以由 DI 实现。如果指定默认值,则允许 DI 未涵盖的其他参数。
- 适用的构造函数必须是public.
- 必须存在一个适用的构造函数。如果出现歧义,DI 会抛出异常。
Razor组件日志记录
使用日志功能时,只需要从依懒注入容器里面获取出日志接口对象,然后调用写日志方法即可,示例代码如下:
@page "/counter" @using Microsoft.Extensions.Logging; @inject ILogger<Counter> logger; <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { logger.LogWarning("Someone has clicked me!"); currentCount++; } } 也可以使用IloggerFactory接口记录日志,示例代码如下: @page "/counter" @using Microsoft.Extensions.Logging; @inject ILoggerFactory LoggerFactory <h1>Counter</h1> <p>Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { var logger = LoggerFactory.CreateLogger<Counter>(); logger.LogWarning("Someone has clicked me!"); currentCount++; } }
ASP.NET Core SignalR
ASP.NET Core SignalR支持两种编码消息协议,JSON和MessagePack,每个协议都有序列化的配置项,可以使用AddJsonProtocol扩展方法配置。
在启动类中引入命名空间:Microsoft.Extensions.DependencyInjection
服务器端配置:
services.AddSignalR() .AddJsonProtocol(options => { options.PayloadSerializerOptions.PropertyNamingPolicy = null; });
客户端配置:
// At the top of the file: using Microsoft.Extensions.DependencyInjection; // When constructing your connection: var connection = new HubConnectionBuilder() .AddJsonProtocol(options => { options.PayloadSerializerOptions.PropertyNamingPolicy = null; }) .Build();
提示:目前无法配置 JavaScript 客户端中的 JSON 序列化。
SignalR配置项
可以通过在中提供对调用的选项委托,为所有中心配置选项 AddSignalR
Startup.ConfigureServices
。
public void ConfigureServices(IServiceCollection services) { services.AddSignalR(hubOptions => { hubOptions.EnableDetailedErrors = true; hubOptions.KeepAliveInterval = TimeSpan.FromMinutes(1); }); }
服务器端高级 HTTP 配置选项
用于 HttpConnectionDispatcherOptions 配置与传输和内存缓冲区管理相关的高级设置。 通过向 中的 MapHub 传递委托来配置 <T> 这些选项 Startup.Configure 。
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapHub<ChatHub>("/chathub", options => { options.Transports = HttpTransportType.WebSockets | HttpTransportType.LongPolling; }); }); }
下表介绍了用于配置 ASP.NET Core 的高级 HTTP SignalR 选项的选项:
客户端配置项
客户端使用SignalR时,需要实例化一个对象,按照官方文档如下:
可以在 HubConnectionBuilder
.net 和 JavaScript 客户端) 中可用的类型 (上配置客户端选项。 它在 Java 客户端中也可用,但 HttpHubConnectionBuilder
子类是包含生成器配置选项的内容,也是其 HubConnection
本身。
C#示例代码:需要引用,Microsoft.Extensions.Logging.Console。
var connection = new HubConnectionBuilder() .WithUrl("https://znlive.com/chathub") .ConfigureLogging(logging => { logging.SetMinimumLevel(LogLevel.Information); logging.AddConsole(); }) .Build();
Javascript代码:
let connection = new signalR.HubConnectionBuilder() .withUrl("/chathub") .configureLogging(signalR.LogLevel.Information) .build();
LogLevel您还可以提供一个 string 表示日志级别名称的值,而不是一个值。 当 SignalR 你在无法访问常量的环境中配置日志记录时,这非常有用 LogLevel 。
let connection = new signalR.HubConnectionBuilder() .withUrl("/chathub") .configureLogging("warn") //直接传入字符串 .build();
下表列出了可用的日志级别。 提供的值用于 configureLogging 设置 要记录 的最小日志级别。 将记录在此级别记录的消息或表 中列出的 级别。
提示:禁用日志 signalR.LogLevel.None
指定 方法 configureLogging
中的
配置允许的传输
可以在 JavaScript (调用中 SignalR 配置 WithUrl withUrl 使用的传输) 。 的值的按位 OR HttpTransportType 可用于限制客户端仅使用指定的传输。 默认启用所有传输。
例如,若要禁用事件Server-Sent,但允许 WebSockets 和长轮询连接:
var connection = new HubConnectionBuilder() .WithUrl("https://znlive.com/chathub", HttpTransportType.WebSockets | HttpTransportType.LongPolling) .Build();
在 JavaScript 客户端中,通过设置提供给 的选项对象 transport 上的 字段来配置传输 withUrl :
let connection = new signalR.HubConnectionBuilder() .withUrl("/chathub", { transport: signalR.HttpTransportType.WebSockets | signalR.HttpTransportType.LongPolling }) .build();
配置 bearer 身份验证
如果调用的接口需要登录验证身份,若要与请求一起提供身份验证数据 SignalR ,请使用 AccessTokenProvider accessTokenFactory JavaScript) 中 (选项来指定返回所需访问令牌的函数。 在 .NET 客户端中,此访问令牌作为 HTTP “持有者身份验证” 令牌传入 (使用 Authorization) 类型的标头 Bearer 。 在 JavaScript 客户端中,访问令牌用作持有者令牌, 但 在某些情况下,浏览器 api 会限制在 Server-Sent 事件和 websocket 请求) (具体应用标头的能力。 在这些情况下,访问令牌作为查询字符串值提供 access_token 。
在 .NET 客户端中, AccessTokenProvider 可使用中的选项委托指定选项 WithUrl :
var connection = new HubConnectionBuilder() .WithUrl("https://znlive.com/chathub", options => { options.AccessTokenProvider = async () => { // Get and return the access token. }; }) .Build();
在 JavaScript 客户端中,通过 accessTokenFactory 在中设置 “选项” 对象上的字段来配置访问令牌 withUrl :
let connection = new signalR.HubConnectionBuilder() .withUrl("/chathub", { accessTokenFactory: () => { // Get and return the access token. // This function can return a JavaScript Promise if asynchronous // logic is required to retrieve the access token. } }) .build();
配置超时和 keep-alive 选项
用于配置超时和保持活动状态的其他选项可用于 HubConnection 对象本身:
配置其它选项
可以在中的 WithUrl withUrl JavaScript) 方法 (上 HubConnectionBuilder 或在 HttpHubConnectionBuilder Java 客户端中的各种配置 api 上配置其他选项:
在 .NET 客户端中,可以通过提供给的 options 委托来修改这些选项 WithUrl
:
var connection = new HubConnectionBuilder() .WithUrl("https://znlive.com/chathub", options => { options.Headers["Foo"] = "Bar"; options.SkipNegotiation = true; options.Transports = HttpTransportType.WebSockets; options.Cookies.Add(new Cookie(/* ... */); options.ClientCertificates.Add(/* ... */); }) .Build();
在 JavaScript 客户端中,可以在提供给的 JavaScript 对象中提供这些选项 withUrl
:
let connection = new signalR.HubConnectionBuilder() .withUrl("/chathub", { // "Foo: Bar" will not be sent with WebSockets or Server-Sent Events requests headers: { "Foo": "Bar" }, transport: signalR.HttpTransportType.LongPolling }) .build();
【江湖人士】(jhrs.com) 投稿作者:IT菜鸟,不代表江湖人士立场,如若转载,请注明出处:https://jhrs.com/2021/43890.html
扫码加入电报群,让你获得国外网赚一手信息。
文章标题:2024学习Razor知识整理笔记