1 asp.net core中的两种前端文件对比
Razor 标记页(文件扩展名为 .razor)文件中包含了html 代码和cs代码。
asp.net core中前端文件中既有.razor文件也有.cshtml文件。
Razor引擎对于.cshtml文件和.razor文件的解析过程基本上是相似的,但是也有细微的差异。
1.1 razor与cshtml相似性
- 对于.cshtml文件和.razor文件,Razor引擎都会解析其中的HTML和Razor代码,并将其转换成可执行的C#代码。
- 无论是.cshtml文件还是.razor文件,它们最终都会被编译成C#类,这些类会负责处理页面逻辑、渲染和与后端交互等任务。
1.2 差异
- 在ASP.NET Core中,.cshtml文件通常用于创建传统的MVC视图或页面,而.razor文件用于创建基于Blazor的Web组件。
- .razor文件中的C#代码更加紧密地与HTML代码交织在一起,因为Blazor组件的核心就是将前端的HTML和后端的C#代码封装到同一个文件中。而.cshtml文件中的C#代码通常用于控制视图的动态行为和数据呈现,与HTML代码相对独立。
- 在Blazor中,.razor文件中的C#代码经常使用基于Razor语法的@符号来嵌入到HTML代码中,而.cshtml文件中的C#代码则使用@符号来标识Razor代码块,但不会嵌入到HTML标记中。
2 razor引擎解析razor/cshtml的过程
2.1 原理概述
Razor引擎的主要作用之一就是将包含HTML和C#代码的Razor标记页文件(扩展名为.razor)编译成C#类代码。这个C#类代码实际上是一个继承自Microsoft.AspNetCore.Components.ComponentBase的组件类,它包含了HTML中的静态内容以及与C#代码交织在一起的动态内容。
在编译过程中,Razor引擎会解析Razor标记页文件中的HTML和Razor代码,将其中的Razor代码转换成对应的C#代码,并将其嵌入到生成的组件类中。Razor引擎的编译过程是将Razor标记页文件中的HTML和C#代码转换成可执行的C#类代码,从而实现了页面逻辑与呈现的分离,同时保留了编写页面逻辑的便利性。
生成的C#类代码会负责处理组件的渲染、事件处理等逻辑,以及与页面中的HTML元素进行交互。
Razor引擎会根据以下规则处理HTML代码:
- HTML标记: Razor引擎会将HTML标记识别为静态内容,并将其保留在生成的C#代码中。这意味着HTML标记会以原样保留,并且不会被编译成C#代码的字符串。
- Razor代码块: 如果在.razor或.cshtml文件中包含了Razor代码块(以@符号开头),Razor引擎会将其识别为动态代码块,并将其中的C#代码解析并编译成相应的C#语句或表达式。这些动态代码块会嵌入到生成的C#类中,以便在运行时执行。
- HTML属性: Razor引擎会识别HTML标记中的属性,并将其解析为C#属性或字段。对于使用@符号绑定的属性,Razor引擎会将其识别为动态属性,并在生成的C#代码中生成相应的属性访问或绑定逻辑。
2.2 示例
这里我们用一个简单的示例来说明Razor引擎解析.razor或.cshtml文件的原理。
假设有如下的.razor文件:
代码语言:razor复制<h1>Welcome, @Name!</h1>
@if (ShowMessage)
{
<p>This is a message for you.</p>
}
<button @onclick="HandleClick">Click me</button>
@code {
private string Name = "John";
private bool ShowMessage = true;
private void HandleClick()
{
ShowMessage = !ShowMessage;
}
}
当Razor引擎解析这个.razor文件时,它会根据一定的规则将其中的HTML代码和C#代码分别解析并转换成相应的C#类代码。下面是大致的生成文件:
代码语言:C#复制using Microsoft.AspNetCore.Components;
namespace MyNamespace
{
public class MyComponent : ComponentBase
{
private string Name = "John";
private bool ShowMessage = true;
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenElement(0, "h1");
builder.AddContent(1, "Welcome, ");
builder.AddContent(2, Name);
builder.CloseElement();
if (ShowMessage)
{
builder.OpenElement(3, "p");
builder.AddContent(4, "This is a message for you.");
builder.CloseElement();
}
builder.OpenElement(5, "button");
builder.AddAttribute(6, "onclick", EventCallback.Factory.Create(this, HandleClick));
builder.AddContent(7, "Click me");
builder.CloseElement();
}
private void HandleClick()
{
ShowMessage = !ShowMessage;
StateHasChanged();
}
}
}
在这个生成的C#类代码中:
BuildRenderTree 方法用于构建组件的渲染树,它会按照Razor文件中的结构生成对应的HTML元素和属性。
Razor文件中的静态HTML内容会被转换成 builder.OpenElement 和 builder.CloseElement 方法的调用,用于创建和关闭HTML元素。
Razor文件中的动态内容和事件处理逻辑会被转换成相应的C#代码,用于在运行时执行和处理。
综上,Razor引擎解析.razor或.cshtml文件的原理就是将其中的HTML代码和C#代码分别解析,并根据一定的规则生成相应的C#类代码,以实现页面的动态渲染和逻辑处理。
2.3 blazor框架的前后端交互流程分析
如3.2节所述 .razor文件被解析成 MyComponent类,在blazor server模式处理web请求,实际上发送给浏览器的html实际是静态页面,这个页面的内容由 服务器 执行BuildRenderTree函数生成的。从代码的角度大致简化工作流程如下:
- 客户端请求页面: 客户端(浏览器)发送请求到服务器,请求Blazor应用程序的页面。
- 服务器处理请求: 服务器接收到请求后,会执行相应的处理逻辑。在Blazor Server模式下,服务器会实例化Blazor组件,并调用其BuildRenderTree方法来生成HTML内容。
- 生成HTML内容: 在BuildRenderTree方法中,组件会创建一个渲染树(Render Tree),这个渲染树描述了页面的结构和内容。组件会使用RenderTreeBuilder对象来构建渲染树,向其中添加HTML元素、属性和事件处理逻辑等。
- 将HTML发送给客户端: 服务器将生成的HTML内容作为响应发送给客户端(浏览器),浏览器将其解析并渲染到页面上。
- 与用户交互: 用户在浏览器中与页面进行交互,例如点击按钮、输入文本等操作。
- 处理用户事件: 当用户与页面交互时,浏览器会将相应的事件(如点击事件、输入事件)发送回服务器。
- 更新页面内容: 服务器接收到用户事件后,会重新执行相应的处理逻辑,并根据新的状态重新生成HTML内容。然后将更新后的HTML内容发送给客户端,客户端会更新页面上相应的部分而不是整个页面。
- 持续通信: 这样的过程会持续进行,服务器和客户端之间通过SignalR进行实时通信,以保持页面内容的同步更新。
3.总结:
- Razor引擎的编译过程是将Razor标记页文件中的HTML和C#代码转换成可执行的C#类代码,从而实现了页面逻辑与呈现的分离,同时保留了编写页面逻辑的便利性。
- Blazor Server模式下的工作流程是在服务器端生成HTML内容,并将其发送给客户端,以实现动态的页面渲染和交互。客户端与服务器之间通过SignalR进行实时通信,以保持页面的同步更新。