温故知新,.Net Core遇见Blazor(FluentUI),属于未来的SPA框架
TaylorShi dotNET跨平台 今天什么是BlazorBlazor是一个使用.NET生成交互式客户端WebUI的框架:使用C#代替JavaScript来创建信息丰富的交互式UI。共享使用.NET编写的服务器端和客户端应用逻辑。将UI呈现为HTML和CSS,以支持众多浏览器,其中包括移动浏览器。与新式托管平台(如Docker)集成。
基于.Net Core提供客户端Web开发的优势使用.NET进行客户端Web开发可提供以下优势:使用C#代替JavaScript来编写代码。利用现有的.NET库生态系统。在服务器和客户端之间共享应用逻辑。受益于.NET的性能、可靠性和安全性。在Windows、Linux和macOS上使用VisualStudio保持高效工作。以一组稳定、功能丰富且易用的通用语言、框架和工具为基础来进行生成。Blazor组件Blazor应用基于组件。Blazor中的组件是指UI元素,例如页面、对话框或数据输入窗体。组件是内置到.NET程序集的.NET C#类,它们用于:定义灵活的UI呈现逻辑。处理用户事件。可以嵌套和重用。可作为Razor类库或NuGet包共享和分发。组件类通常以Razor标记页(文件扩展名为.razor)的形式编写。Blazor中的组件有时被称为Razor组件。Razor是一种语法,用于将HTML标记与专为提高开发人员工作效率而设计的C#代码结合在一起。借助Razor,可使用Visual Studio中的IntelliSense编程支持在同一文件中的HTML标记与C#之间切换。Razor Pages和MVC也使用Razor。与基于请求/响应模型生成的Razor Pages和MVC不同,组件专门用于处理客户端UI逻辑和构成。Blazor使用UI构成的自然HTML标记。下面的Razor标记演示了一个组件(Dialog.razor),它显示一个对话框,并处理在用户选择按钮时发生的事件:<div class="card" style="width:22rem"><div class="card-body"><h3 class="card-title">@Title</h3><p class="card-text">@ChildContent</p><button @onclick="OnYes">Yes!</button></div></div>@code {[Parameter]public RenderFragment ChildContent { get; set; }[Parameter]public string Title { get; set; }private void OnYes(){Console.WriteLine("Write to the console in C#! 'Yes' button selected.");}}在上述示例中,OnYes是由按钮的onclick事件触发的C#方法。对话框的文本(ChildContent)和标题(Title)由在其UI中使用此组件的下述组件提供。使用HTML标记将Dialog组件嵌入到另一个组件中。在以下示例中,Index组件(Pages/Index.razor)使用前面的Dialog组件。标记的Title属性向Dialog组件的Title属性传递标题的值。Dialog组件的文本(ChildContent)由<Dialog>元素的内容设置。向Index组件添加Dialog组件后,Visual Studio中的IntelliSense可加快使用语法和参数补全进行开发的速度。@page "/"<h1>Hello, world!</h1><p>Welcome to your new app.</p><Dialog Title="Learn More">Do you want to <i>learn more</i> about Blazor?</Dialog>在浏览器中访问父级Index组件时,将呈现该对话框。当用户选择此按钮时,浏览器的开发人员工具控制台会显示由OnYes方法编写的消息:
组件呈现为浏览器文档对象模型(DOM)的内存中表现形式,它被称为“呈现树”,用于以灵活高效的方式更新UI。文档对象模型 (DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。一个web页面是一个文档。这个文档可以在浏览器窗口或作为HTML源码显示出来。但上述两个情况中都是同一份文档。文档对象模型(DOM)提供了对同一份文档的另一种表现,存储和操作的方式。DOM是web页面的完全的面向对象表述,它能够使用如 JavaScript等脚本语言进行修改。Blazor Web AssemblyBlazor Web Assembly是单页应用(SPA)框架,用于使用.NET生成交互式客户端Web应用。Blazor Web Assembly使用无插件或将代码重新编译为其他语言的开放式Web标准。Blazor Web Assembly适用于所有新式Web浏览器,包括移动浏览器。通过WebAssembly(缩写为wasm),可在Web浏览器内运行.NET代码。Web Assembly是针对快速下载和最大执行速度优化的压缩字节码格式。Web Assembly是开放的Web标准,支持用于无插件的Web浏览器。Web Assembly代码可通过JavaScript(称为JavaScript互操作性,通常简称为JavaScript互操作或JS互操作)访问浏览器的完整功能。通过浏览器中的Web Assembly执行的.NET代码在浏览器的JavaScript沙盒中运行,沙盒提供的保护可防御客户端计算机上的恶意操作。
当Blazor Web Assembly应用生成并在浏览器中运行时:C#代码文件和Razor文件将被编译为.NET程序集。该程序集和.NET运行时将被下载到浏览器。BlazorWebAssembly启动.NET运行时,并配置运行时,以为应用加载程序集。BlazorWebAssembly运行时使用JavaScript互操作来处理DOM操作和浏览器API调用。已发布应用的大小(其有效负载大小)是应用可用性的关键性能因素。大型应用需要相对较长的时间才能下载到浏览器,这会损害用户体验。Blazor Web Assembly优化有效负载大小,以缩短下载时间:在中间语言(IL)裁边器发布应用时,会从应用删除未使用的代码。压缩HTTP响应。.NET运行时和程序集缓存在浏览器中。Blazor托管模型主要的Blazor托管模型在Web Assembly上的浏览器中运行客户端。将Blazor应用、其依赖项以及.NET运行时下载到浏览器。应用将在浏览器线程中直接执行。UI更新和事件处理在同一进程中进行。应用资产作为静态文件部署到可为客户端提供静态内容的Web服务器或服务中。
如果创建了Blazor Web Assembly应用进行部署,但没有后端ASP.NET Core应用来为其文件提供服务,那么该应用被称为独立Blazor Web Assembly应用。如果创建了应用进行部署,但没有后端应用来为其文件提供服务,那么该应用被称为托管的Blazor Web Assembly应用。托管的Blazor Web Assembly Client应用通常使用WebAPI调用或SignalR(结合使用ASP.NET Core SignalR和Blazor)通过网络与后端Server应用交互。blazor.webassembly.js脚本由框架和句柄提供:下载.NET运行时、应用和应用依赖项。初始化运行应用的运行时。Blazor Web Assembly托管模型具有以下优点:没有.NET服务器端依赖项。应用下载到客户端后即可正常运行。可充分利用客户端资源和功能。工作可从服务器转移到客户端。无需ASP.NETCoreWeb服务器即可托管应用。无服务器部署方案可行,例如通过内容分发网络(CDN)为应用提供服务的方案。Blazor Web Assembly托管模型具有以下局限性:应用仅可使用浏览器功能。需要可用的客户端硬件和软件(例如WebAssembly支持)。下载项大小较大,应用加载耗时较长。.NET运行时和工具支持不够完善。例如,.NETStandard支持和调试方面存在限制。在传统Web应用和单页应用(SPA)之间选择Atwood 定律:任何能够用JavaScript编写的应用程序,最终必将用JavaScript编写。- Jeff Atwood目前可通过两种通用方法来构建Web应用程序:在服务器上执行大部分应用程序逻辑的传统Web应用程序,以及在Web浏览器中执行大部分用户界面逻辑的单页应用程序(SPA),后者主要使用WebAPI与Web服务器通信。也可以将两种方法混合使用,最简单的方法是在更大型的传统Web应用程序中托管一个或多个丰富SPA类子应用程序。何时使用传统Web应用程序:应用程序的客户端要求简单,甚至要求只读。应用程序需在不支持JavaScript的浏览器中工作。团队不熟悉JavaScript或TypeScript开发技术。何时使用SPA:应用程序必须公开具有许多功能的丰富用户界面。团队熟悉JavaScript、TypeScript或Blazor Web Assembly开发。应用程序已为其他(内部或公共)客户端公开API。此外,SPA框架还需要更强的体系结构和安全专业知识。相较于传统Web应用程序,SPA框架需要进行频繁的更新和使用新框架,因此改动更大。相较于传统Web应用,SPA应用程序在配置自动化生成和部署过程以及利用部署选项(如容器)方面的难度更大。使用SPA方法改进用户体验时必须权衡这些注意事项。传统Web应用程序、SPA或Blazor应用之间进行选择时要考虑的一些基本因素因素传统 Web 应用单页面应用程序Blazor 应用需要团队熟悉 JavaScript/TypeScript最低必需最低支持不带脚本的浏览器支持不支持支持客户端应用程序行为极少适合不必要可行丰富而复杂的用户界面要求受限适合适合何时选择传统Web应用应用程序的客户端要求简单,可能要求只读对许多Web应用程序而言,其大部分用户的主要使用方式是只读。只读(或以读取为主)应用程序往往比那些维护和操作大量状态的应用程序简单得多。例如,搜索引擎可能由一个带有文本框的入口点和用于显示搜索结果的第二页组成。匿名用户可以轻松提出请求,并且很少需要使用客户端逻辑。同样,一般而言,博客或内容管理系统中面向公众的应用程序主要包含的内容与客户端行为关系不大。此类应用程序容易构建为基于服务器的传统Web应用程序,在Web服务器上执行逻辑,并呈现要在浏览器中显示的HTML。事实上,网站的每个独特页面都有自己的URL,搜索引擎可以将其存为书签和编入索引(默认设置,无需将此功能添加为应用程序的单独功能),这也是此类情况的一个明显优势。应用程序需在不支持JavaScript的浏览器中工作如需在有限或不支持JavaScript的浏览器中工作的Web应用程序,则应使用传统的Web应用工作流编写(或至少可以回退到此类行为)。SPA需要客户端JavaScript才能正常工作;如果没有客户端JavaScript,SPA不是好的选择。团队不熟悉JavaScript或TypeScript开发技术如果团队不熟悉JavaScript或TypeScript,但熟悉服务器端Web应用程序开发,那相较于SPA,他们交付传统Web应用的速度可能更快。除非以学习SPA编程为目的,或需要SPA提供用户体验,否则对已经熟悉构建传统Web应用的团队而言,选择传统Web应用的工作效率更高。何时选择SPA应用程序必须公开具有许多功能的丰富用户界面SPA可支持丰富客户端功能,当用户执行操作或在应用的各区域间导航时无需重新加载页面。SPA很少需要重新加载整个页面,因此加载速度更快,可在后台提取数据,并且对单个用户操作的响应更快。SPA支持增量更新,可保存尚未完成的窗体或文档,而无需用户单击按钮提交窗体。SPA支持丰富的客户端行为,例如拖放,比传统应用程序更容易操作。可以将SPA设计为在断开连接的模式下运行,对客户端模型进行更新,并在重新建立连接后将更新最终同步回服务器。如果应用要求包括丰富的功能,且超出了典型HTML窗体提供的功能,则选择SPA样式应用程序。通常,SPA需要实现内置于传统Web应用中的功能,例如在反映当前操作的地址栏中显示有意义的URL(并允许用户将此URL存为书签或对其进行深层链接以便返回此URL)。SPA还应允许用户使用浏览器的后退和前进按钮寻找用户意料之中的结果。团队熟悉JavaScript和/或TypeScript开发编写SPA需要熟悉JavaScript或TypeScript以及客户端编程技术和库。团队应有能力像使用Angular一样使用SPA框架编写新式JavaScript。参考-SPA框架Angular:https://angular.ioReact:https://reactjs.org/Vue.js:https://vuejs.org/应用程序已为其他(内部或公共)客户端公开API如果已提供一个Web API供其他客户端使用,则相较于在服务器端窗体中复制逻辑,创建一个利用这些API的SPA实现更加容易。用户与应用程序交互时,SPA广泛使用Web API来查询和更新数据。何时选择Blazor应用程序必须公开丰富用户界面与基于JavaScript的SPA一样,Blazor应用程序可以支持丰富的客户端行为,而无需重载页面。这些应用程序对用户的响应更快,仅获取响应给定用户交互所需的数据(或HTML)。如果设计得当,可以将服务器端Blazor应用配置为以客户端Blazor应用的形式运行,只需在此功能受支持后对它进行稍加更改即可。与使用JavaScript或TypeScript开发相比,团队更喜欢使用.NET开发与使用JavaScript或TypeScript等客户端语言相比,许多使用.NET和Razor的开发人员的工作效率更高。由于已经使用.NET开发了应用程序的服务器端,因此,使用Blazor可以确保团队中的每名.NET开发人员都可以理解,并可能会生成应用程序前端的行为。Blazor ServerBlazor将组件呈现逻辑从UI更新的应用方式中分离出来。Blazor Server在ASP.NET Core应用中支持在服务器上托管Razor组件。可通过SignalR连接处理UI更新。
运行时停留在服务器上并处理:执行应用的C#代码。将UI事件从浏览器发送到服务器。将UI更新应用于服务器发送回的已呈现的组件。Blazor Server用于与浏览器通信的连接还用于处理JavaScript互操作调用。
JavaScript互操作对于需要第三方JavaScript库和访问浏览器API的应用,组件与JavaScript进行互操作。组件能够使用JavaScript能够使用的任何库或API。C#代码可调用到JavaScript代码,而JavaScript代码可调用到C#代码。在ASP.NET Core Blazor中从.NET方法调用JavaScript函数https://docs.microsoft.com/zh-cn/aspnet/core/blazor/call-javascript-from-dotnet?view=aspnetcore-5.0从ASP.NET Core Blazor中的JavaScript函数调用.NET方法https://docs.microsoft.com/zh-cn/aspnet/core/blazor/call-dotnet-from-javascript?view=aspnetcore-5.0Blazor支持的平台浏览者VersionApple Safari,包括 iOS当前†Google Chrome,包括 Android当前†Microsoft Edge当前†Mozilla Firefox当前††最新指的是浏览器的最新版本。Blazor模板选项Blazor WebAssembly项目模板:blazorwasmBlazor Server项目模板:blazorserver创建我的第一个Blazor应用1. 先准备".NET SDK (Software Development Kit)"环境。如果之前没有安装的先安装这个SDK:dotnet-sdk-5.0.202-win-x64.exe如果已经安装过了,检查下当前版本:dotnet --version
2. 根据Blazor项目模板创建应用1) 命令行方式创建dotnet new blazorserver -o BlazorApp --no-https这里通过DOTNET-CLI执行新建项目的命令,使用的是blazorserver这个项目模板,输出项目文件夹为BlazorApp,给该项目设置为不需要HTTPS模式--no-https。如果要创建Blazor WebAssembly项目,这里将blazorserver改成blazorwasm即可。dotnet new blazorwasm -o BlazorApp --no-https2) Visual Studio方式创建打开Visual Studio 2019最新版本,创建新项目,找到Blazor相关的项目模板。Blazor Server应用Blazor WebAssembly应用
点击下一步,输入BlazorApp的项目名称,点击下一步进行创建。
目标框架,可以选.NET Core 3.1(长期支持),也可以选择.NET 5.0(当前),去掉勾选复选框配置HTTPS,点击创建即可。
创建成功之后,会自动打开项目解决方案。
3. 运行应用1) 命令行方式创建如果通过命令行方式创建,运行应用只需要执行:dotnet watch run通过DOTNET-CLI的Run命令可以运行程序,这里添加watch参数的好处就是,等下如果改动了文件,会热重载,这样调试起来就很方便。
运行起来之后,会看到浏览器弹出应用首页。
如果要退出运行,只需要执行如下命令即可:Ctrl + C
2) Visual Studio方式创建在Visual Studio里面运行就很简单了,直接点运行BlazorApp或者Ctrl + F5即可。
默认会打开一个终端控制台界面,用来显示Console日志。
运行起来之后,会看到浏览器弹出应用首页。4. 项目结构Program.cs 启用这个应用服务的入口节点。Startup.cs 配置应用服务和中间件的地方。App.razor 应用组件的根组件,也就是组件的入口位置。BlazorApp/Pages 包含一些示例页面,也是页面目录。BlazorApp.csproj 描述应用项目及其依赖关系。5. 认识首页及组件我们看到Pages/Index.razor这个主页。@page "/"<h1>Hello, world!</h1>Welcome to your new app.<SurveyPrompt Title="How is Blazor working for you?" />这里已经有了SurveyPrompt这样一个组件,同时它有一个入参Title可以定制。6. 查看子组件计数器打开Pages/Counter.razor,这是一个计数器的组件。@page "/counter"<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(){currentCount++;}}我们可以从代码看到,顶部@page "/counter"实际上这个页面组件的目录,当我们切换到它时,路径也会变化。
每次点击Click me按钮的时候,就会从onclick事件去找到IncrementCount这个函数,在这个函数中,我们把currentCount做了加1,这时候,Current count的值会跟着刷新,可以看出只要绑定好了数据,它就会帮我们自动去更新界面显示了,还是很方便。
7. 在首页添加子组件计数器打开Pages/Index.razor,我们在末尾追加Counter即可。@page "/"<h1>Hello, world!</h1>Welcome to your new app.<SurveyPrompt Title="How is Blazor working for you?" /><Counter />这时候,我们查看页面就已经可以看到它了。
8. 修改组件添加属性并使用接下来,我们打开Pages/Counter.razor,我们给这个组件添加一个参数属性IncrementAmount,默认值是1, 这样我们可以从外部传递值进来修改它,并且我们让currentCount不再是继续加1了,而是改成加IncrementAmount的值,这样我们就可以控制每次累加的幅度。@page "/counter"<h1>Counter</h1><p>Current count: @currentCount</p><button class="btn btn-primary" @onclick="IncrementCount">Click me</button>@code {private int currentCount = 0;[Parameter]public int IncrementAmount { get; set; } = 1;private void IncrementCount(){currentCount += IncrementAmount;}}然后,我们回到Pages/Index.razor,在Counter组件上给他传递IncrementAmount的值进来。@page "/"<h1>Hello, world!</h1>Welcome to your new app.<SurveyPrompt Title="How is Blazor working for you?" /><Counter IncrementAmount="10" />这时候,界面会自动重载,这时候,我们每次点击Click me,这个计时器组件就会加10了,哈哈,是不是很简单。
生成Blazor待办事项列表应用1. 先准备".NET SDK (Software Development Kit)"环境。如果之前没有安装的先安装这个SDK:dotnet-sdk-5.0.202-win-x64.exe如果已经安装过了,检查下当前版本:dotnet --version
2. 创建待办事项列表Blazor应用dotnet new blazorserver -o TodoList --no-https通过DOTNET-CLI脚本的New命令,新建一个blazorserver项目模板,输出目录命名为TodoList,同时不需要HTTPS的支持。
3. 添加名为“Todo”的Blazor组件cd TodoList
先切换到TodoList项目文件夹中。dotnet new razorcomponent -n Todo -o Pages然后,通过DOTNET-CLI脚本的New命令,输出目录为Pages,新建名为Todo的razorcomponent组件。其中-n全称为--name,用来指定创建的名称,-o全称为--output,用来指定在这个目录进行创建。Razor组件文件名要求首字母大写。打开Pages文件夹,确认Todo组件文件名以大写字母T开头。文件名应为Todo.razor。
将在项目文件夹的Pages目录中,新建得到一个Todo.razor文件。
接下来,我们需要在Todo.razor文件顶部添加针对该文件组件的路由位置。@page "/todo"
4. 将“Todo”的Blazor组件添加到左侧导航位于Shared文件夹的NavMenu.razor组件是控制左侧导航的,我们需要将“Todo”的Blazor组件添加到左侧导航中。在NavMenu.razor组件中,找到ul元素下的li节点,参考前面的例子,新建属于Todo组件的导航位置。<div class="@NavMenuCssClass" @onclick="ToggleNavMenu"><ul class="nav flex-column">...<li class="nav-item px-3"><NavLink class="nav-link" href="todo"><span class="oi oi-list-rich" aria-hidden="true"></span> ToDoList</NavLink></li></ul></div>
这里我们需要注意的几个关键点是,NavLink的href需要填写组件的路由位置,其中span元素是菜单图标,紧跟着它的就是菜单名称,这里我们用ToDoList来作为菜单名称。保存之后,我们通过执行run命令来运行,查看导航效果。dotnet watch run
5. 添加“TodoItem”来存储待办事项数据。这里一个小插曲就是为了更好的写出TodoItem.cs这个模型类,我遇到了两个不错的VSC插件,这里就顺带记录一下。名为C# Extensions的VSC插件,可以帮助我们支持在VSC中右键快速新建模型类和接口,有点类似VS中那种创建,至少帮你完成了当前命名空间的添加的活,所以值得推荐。
名为C# XML Documentation Comments的VSC插件,平时我们在VS中写代码,习惯性的如果要添加函数或者属性的注释的话,上来就是///然后等待自动完成得到一串添加注释的注释体,这个插件就是来干这个事情的,效果还不错。
这两个插件,搜索C#这个关键词就可以看到了,基本上排在前面。有了它们,我们创建TodoItem模型类就如虎添翼了。在项目的Data文件夹中,我们右键,选择New C# Class,输入TodoItem,然后回车即可。
然后我们就自动完成,得到了一个基础的空的TodoItem.cs模型类,它的namespace都是已经处理好了,我觉得比手写强吧。
接下里,我们往TodoItem.cs模型类中添加两个属性(最好是走prop命令来新建),一个是Title来存储待办事项的标题,一个是IsDone来标记是否已完成该事项。
接下来,为了将来更好的阅读这个模型,我们养成一个好习惯,给对应的模型和字段都添加好注释,这时候C# XML Documentation Comments这个VSC插件就要派上用场了,通过在所需要注释代码的开头位置,输入///然后回车即可。namespace TodoList.Data{/// <summary>/// 待办事项/// </summary>public class TodoItem{/// <summary>/// 事项名称/// </summary>/// <value></value>public string Title { get; set; }/// <summary>/// 事项是否已完成/// </summary>/// <value></value>public bool IsDone { get; set; }}}
参考ASP.NET Core Blazor 简介BlazorFluentUIBlazor Webassembly DemoDOM概述在传统 Web 应用和单页应用 (SPA) 之间选择WebAssembly (abbreviated Wasm)从 ASP.NET Core Blazor 中的 JavaScript 函数调用 .NET 方法在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数ASP.NET Core Blazor 托管模型用于 ASP.NET Core Blazor 的工具Blazor Tutorial - Build your first Blazor app生成 Blazor 待办事项列表应用C# Extensions - VS MarketPlaceC# XML Documentation Comments - VS MarketPlace阅读原文阅读 1833赞6在看5写下你的留言精选留言
Ricky感觉像vue,而且看起来比较舒服。
okwh能不能用于 建立类似atom、electron那样的东西?(就是基于web ui的桌面应用)
dotNET跨平台(作者)可以,已经有了