Blazor的两种方式
1。基于WebAssembly
WebAssembly(简称Wasm)是一个虚拟指令集体系架构(virtual ISA),旨在提供一种高效、 安全和可移植的代码执行方式,特别是在Web平台上。
2。 运行在Server上
特点:
以上两种方式无需插件,基于Web标准。例如flash这种就需要装插件。
可以与Javascript进行交互。
可以利用.Net的优势,例如性能、安全性、现有的程序库等
Blazor的历史:
Blazor的两种宿主模型
。客户端
。服务器端
至其它的方式,如果桌面、移动平台等,在2020年微软承诺会提供。
但是截止勇哥写此文的时间是2024.6月,微软的承诺实现情况如下:
(1)Blazor Hybrid
利用 .NET MAUI 中的 BlazorWebView 控件,实现桌面开发的承诺。
微软的官方解释是:
.NET 多平台应用 UI (.NET MAUI) BlazorWebView 是一个控件, 可用于在 .NET MAUI 应用中托管 Blazor Web 应用。 这些应用称为 Blazor 混合应用,使 Blazor Web 应用能够与平台功能和 UI 控件集成。 B lazorWebView 控件可以添加到 .NET MAUI 应用的任何页面, 并指向 Blazor 应用的根目录。 Razor 组件在 .NET 进程中本机运行, 并将 Web UI 呈现到嵌入式 Web 视图控件。 在 .NET MAUI 中,Blazor 混合应用可以在 .NET MAUI 支持的所有平台上运行。
勇哥的理解就相当于在winform程序里加了一个web浏览器控件,可以把winform+web界面混在一起。
(2)Blazor Native
在微软未来的计划中,Blazor Native 将支持让 Blazor 代码编译成目标平台原生的渲染方式
这其实就是一种自定义渲染器:
将 Blazor 的概念应用于原生应用,可能需要编写自定义的渲染器来将 Blazor 组件映射到原生 UI 控件。
这将是一个复杂的任务,需要深入了解 Blazor 和目标平台的 UI 系统。
这又是微软画的下一个大饼,我们就等着微软来折腾,至少目前是没有听到任何进展的消息。
(3)其它的开发Blazor桌面应用的方式
blazor的桌面开发微软只是提供了Blazor Hybrid方式,见上面的解释。它是利用了MAUI。
利用第三方工具也可以实现Blazor的桌面开发:
它就是 Electron.NET
Electron.NET 是一个允许你使用 .NET 和 Blazor 来构建跨平台桌面应用的框架。
它基于 Electron(一个使用 Web 技术构建跨平台桌面应用的开源库)但用 .NET 替代了 JavaScript。
用 Electron.NET,你可以创建类似于传统桌面应用的应用,
它们包含独立的窗口、本地菜单、文件对话框等,但使用 Blazor 编写前端代码。
安装和配置 Electron.NET 后,你可以使用 Blazor 组件来构建应用的 UI,
并使用 C# 来处理后端逻辑。
Electron的说明见:
https://www.electronjs.org/zh/docs/latest/
Electron.NET 见:
https://github.com/ElectronNET/electron.net-api-demos
客户端的Blazor
客户端的Blazor的优点:
。可以运行在所有现代浏览器上面,包括ipad手机平板等
。服务器端不需要.NET
。SPA的体验,即单页应用的体验
缺点:
。老一点浏览器不支持
。首次下载的应用比较大
。调试方便性差些
服务端的Blazor
服务器端的Blazor的优点:
。需要下载的东西很小
。可以使用所有服务器端的api
。完整的debug体验
。可以在不支持WebAssembly的浏览器中运行
缺点:
。不支持离线运行
。网络延迟影响较大
。可扩展性是个问题
服务器端的Blazor不是它的未来,未来最光明的还是Blazor WebAssembly。
下面来一段示例程序
需求:弄两个页面,一个是员工信息列表,一个是点击Detail后进入的详细页。
程序效果如下图示:
存储数据一般的方式:
1。后端,例如web api
2。 前端:例如Local Storage
这个例子中,勇哥把数据写死到代码里。
下面员工信息页的blazor组件代码。(创建时要选择blazor组件)
其中:
@page 是写的本页的路由地址
@inherits 写的是本html页绑定的处理类是 ListDatadisplayBase
这种写法就相当于把页面和C#处理程序的类分离开来书写了。
@page "/ListDataDisplayView" @inherits ListDataDisplayBase <h1>Employee Overview</h1> <table class="table table-hover table-striped"> <thead class="thead-dark"> <tr> <th>ID</th> <th>部门</th> <th>姓名</th> <th>出生日期</th> <th>性别</th> <th>操作</th> </tr> </thead> <tbody> @foreach (var m in Employess) { <tr> <td>@m.Id</td> <td>@m.DepartmentId</td> <td>@m.Name</td> <td>@m.BirthDate</td> <td>@m.Gender</td> <td> <a href="@($"UserDetail/{m.Id}")" class="btn btn-primary btn-sm">Detail</a> </td> </tr> } </tbody> </table>
下面员工信息页的C#代码。(创建时要选择类)
注意几点:
1。 这个类必须继承ComponentBase
2。 写死的数据,放在这个类的生命周期方法中
using Microsoft.AspNetCore.Components; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace BlazorApp1.Pages { public class ListDataDisplayBase: ComponentBase { public IEnumerable<EmployeeDto> Employess { get; set; } /// <summary> /// blazor的生命周期方法,异步 /// </summary> /// <returns></returns> protected override Task OnInitializedAsync() { Employess = new List<EmployeeDto>() { new EmployeeDto { Id = 1,DepartmentId = 1,No="A01", Name="刘备",PictureUrl="", BirthDate=new DateTime(1980, 1, 1), Gender=Gender.Female }, new EmployeeDto { Id = 2,DepartmentId = 2,No="A02", Name="张辽",PictureUrl="", BirthDate=new DateTime(1972, 3, 12), Gender=Gender.Female }, new EmployeeDto { Id = 3,DepartmentId = 3,No="A03", Name="貂蝉",PictureUrl="", BirthDate=new DateTime(1971, 5, 21), Gender=Gender.Male }, new EmployeeDto { Id = 4,DepartmentId = 4,No="A04", Name="吕布",PictureUrl="", BirthDate=new DateTime(1982, 3, 22), Gender=Gender.Female }, new EmployeeDto { Id = 5,DepartmentId = 5,No="A05", Name="小桥",PictureUrl="", BirthDate=new DateTime(1972, 1, 22), Gender=Gender.Male }, new EmployeeDto { Id = 6,DepartmentId =6,No="A06", Name="赵云",PictureUrl="", BirthDate=new DateTime(1970, 5, 31), Gender=Gender.Female } }; return base.OnInitializedAsync(); } } public class Department { public int Id { get; set; } [Display(Name="部门")] [Required(ErrorMessage ="{0}是必填项")] [MaxLength(50,ErrorMessage ="{0}的长度不能超过{1}")] public string Name { get; set; } } public class Employee { public int Id { get; set; } public int DepartmentID { get; set; } [Display(Name = "工号")] [Required(ErrorMessage = "{0}是必填项")] [StringLength(3,MinimumLength =3, ErrorMessage = "{0}的长度不能超过{1}")] public string No { get; set; } [Display(Name = "姓名")] [Required(ErrorMessage = "{0}是必填项")] [MaxLength(50, ErrorMessage = "{0}的长度不能超过{1}")] public string Name { get; set; } [Display(Name = "照片地址")] [MaxLength(500, ErrorMessage = "{0}的长度不能超过{1}")] public string PictureUrl { get; set; } [Display(Name = "日期")] public DateTime BirthDate { get; set; } [Display(Name = "性别")] public Gender Gender { get; set; } } public enum Gender { NotSpecified, Female, Male } public class EmployeeDto { public int Id { get; set; } public int DepartmentId { get; set; } [Display(Name = "工号")] public string No { get; set; } [Display(Name = "姓名")] public string Name { get; set; } [Display(Name = "照片地址")] public string PictureUrl { get; set; } [Display(Name = "日期")] public DateTime BirthDate { get; set; } [Display(Name = "性别")] public Gender Gender { get; set; } } }
下面是详细页的组件代码
注意路由参数/UserDetail/{EmployeeId}的写法。
@page "/UserDetail/{EmployeeId}" @inherits UserDetailBase <h1>UserDetail for @Employee.Name</h1> <idv> <div>@Employee.Id</div> <div>@Employee.DepartmentId</div> <div>@Employee.Name</div> <div>@Employee.BirthDate</div> <div>@Employee.Gender</div> </idv>
下面是详细页的C#处理类代码:
几点说明:
1。 由于是写死的数据,所以这里还得重复写一次这些数据
2。 属性EmployeeId由是会做为组件页的路由参数,所以它得加上特性【Parameter】
using Microsoft.AspNetCore.Components; namespace BlazorApp1.Pages { public class UserDetailBase: ComponentBase { [Parameter] public string EmployeeId { get; set; } public EmployeeDto Employee { get; set; } = new EmployeeDto(); public IEnumerable<EmployeeDto> Employees { get; set; } protected override Task OnInitializedAsync() { Employees = new List<EmployeeDto> { new EmployeeDto { Id = 1,DepartmentId = 1,No="A01", Name="刘备",PictureUrl="", BirthDate=new DateTime(1980, 1, 1), Gender=Gender.Female }, new EmployeeDto { Id = 2,DepartmentId = 2,No="A02", Name="张辽",PictureUrl="", BirthDate=new DateTime(1972, 3, 12), Gender=Gender.Female }, new EmployeeDto { Id = 3,DepartmentId = 3,No="A03", Name="貂蝉",PictureUrl="", BirthDate=new DateTime(1971, 5, 21), Gender=Gender.Male }, new EmployeeDto { Id = 4,DepartmentId = 4,No="A04", Name="吕布",PictureUrl="", BirthDate=new DateTime(1982, 3, 22), Gender=Gender.Female }, new EmployeeDto { Id = 5,DepartmentId = 5,No="A05", Name="小桥",PictureUrl="", BirthDate=new DateTime(1972, 1, 22), Gender=Gender.Male }, new EmployeeDto { Id = 6,DepartmentId =6,No="A06", Name="赵云",PictureUrl="", BirthDate=new DateTime(1970, 5, 31), Gender=Gender.Female } }; Employee = Employees.SingleOrDefault(s => s.Id == int.Parse(EmployeeId)); return base.OnInitializedAsync(); } } }
本文演示代码下载:
链接:https://pan.baidu.com/s/1CqVZervQmS_msCGlAzFPoQ
提取码:9296
--来自百度网盘超级会员V6的分享

