《进击吧!Blazor!》是本人与张善友老师合作的Blazor零基础入门系列视频,此系列能让一个从未接触过Blazor的程序员掌握开发Blazor应用的能力。
视频地址:https://space.bilibili.com/483888821/channel/detail?cid=151273
演示代码:https://github.com/TimChen44/Blazor-ToDo
本系列文章是基于《进击吧!Blazor!》直播内容编写,升级.Net5,改进问题,讲解更全面。
作者:陈超超
Ant Design Blazor 项目贡献者,拥有十多年从业经验,长期基于.Net技术栈进行架构与开发产品的工作,现就职于正泰集团。
邮箱:timchen@live.com
欢迎各位读者有任何问题联系我,我们共同进步。
上一次课程我们完成了ToDo应用的界面制作,这次我们要将客户端的数据写入数据库,并从数据库中读物我们需要的数据。
数据交互过程
我们先看一下从客户端到数据库的流程
Blazor
Blazor客户端就是我们上节课做的ToDo程序。
HttpClient
HttpClient就是我们完成网络通讯用的组件,对于这类组件我们希望在一个应用中只构造一次,这样避免重复分配资源,因此我们在Program.cs
中进行注册。
public class Program
{
public static async Task Main(string[] args)
{
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
}
}
BaseAddress
为基地址,这样我们使用时,Url只需要传入相对地址即可,此处默认为当前主机的地址。DefaultRequestHeaders
默认HTTP请求头参数Timeout
连接超时参数
- 依赖关系注入
上面通过服务注入的方式实现了HttpClient
全局共享(单例),那么如何使用服务?这里我们就需要引入一下“依赖关系注入 (DI)”的概念。
DI是一种技术,基本原理是把有依赖关系的类放到容器中,解析出这些类的实例,就是依赖注入。应用可通过将内置服务注入组件来使用这些服务。 应用还可定义和注册自定义服务,并通过 DI 使其在整个应用中可用。
该技术在 Blazor 应用中常用于以下两个方面:
服务生存期决定了服务何时创建,何时销毁,有三种模式:
Scoped
:Blazor WebAssembly
应用当前没有 DI 范围的概念。 已注册 Scoped
的服务的行为与 Singleton
服务类似。 但是,Blazor Server 托管模型支持 Scoped
生存期。 在 Blazor Server
应用中,Scoped
服务注册的范围为“连接”。 因此,即使当前意图是在浏览器中运行客户端,对于范围应限定为当前用户的服务来说,首选使用 Scoped
服务。
Singleton
:DI 创建服务的单个实例。 需要 Singleton
服务的所有组件都会接收同一服务的实例。
Transient
:每当组件从服务容器获取 Transient
服务的实例时,它都会接收该服务的新实例。
这里的 HttpClient
使用了 AddScoped
方法,那么就是当前范围内使用同一个实例,因为项目是Blazor WebAssembly
模式,所以相当于单例服务。
ASP.Net Core
我用ASP.Net Core项目给Blazor应用提供WebAPI接口
项目结构如下
- launchSettings.json
这里配置了我们调试的方式,端口等,相对于普通的Web项目多了inspectUri
属性,具有以下作用:
- 使 IDE 能够检测到该应用为 Blazor WebAssembly 应用。
- 指示脚本调试基础结构通过 Blazor 的调试代理连接到浏览器。
- 已启动的浏览器 (browserInspectUri) 上 WebSocket 协议 (wsProtocol)、主机 (url.hostname)、端口 (url.port) 和检查器 URI 的占位符值由框架提供。
{
//省略其他配置
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
//省略其他配置
}
- Controllers
控制器(Controller
)放在这里,站点的路由表是通过遍历项目中带有ApiControllerAttribute
(基类ControllerAttribute
)的类,然后寻找里面的方法实现,他和Blazor的路由表创建方法上有点相似。
[ApiController]
[Route("api/[controller]/[action]")]
public class TaskController : ControllerBase
Route
定义了路由格式,上例中[controller]/[action]
意为使用Controller
和action
的名称作为路由地址,这样写可以省去每个action
上标记路由名字的麻烦。
- Pages
存放页面文件的位置,因为我们的项目页面全部使用Blazor构建,所以用不到此文件夹,因此这里就不做介绍了。
- appsettings.json
站点的配置文件,我们的项目就用到了数据库链接字符串配置
- Program.cs
应用的Main
函数在这里,这里完成了Host
的创建与启动
- Startup.cs
启动类,项目启动时的服务注册,配置等工作都在此处完成ConfigureServices
使用此方法将服务添加到容器。Configure
使用此方法来配置HTTP请求管道。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//省略其他代码
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
app.UseBlazorFrameworkFiles();
配置应用程序提供Blazor WebAssembly框架文件,默认根路径为/
,也可以自定义路径前缀endpoints.MapControllers();
添加控制器(Controller
)的路由。endpoints.MapFallbackToFile("index.html");
添加默认路由地址是index.html
。
EF Code
所有的数据我们需要保存入数据库,这里我选择使用EF Core作为我们的数据访问技术
EF Core部分特点
- Entity Framework (EF) Core 是轻量化、可扩展、开源和跨平台版的数据访问技术。
- EF Core可用作对象关系映射程序 (O/RM),能让我们用对象来处理数据库,使用Linq进行查询,这样我们就可以不用编写大量SQL代码了。
- EF Core 支持多个数据库引擎,比如MySQL、SQLite等。
他支持采用Code Firs或者Database First两种模式
-
Code Firs
用代码编写对象关系,然后通过它创建数据库。 -
Database First
可以提供现有数据库,反向生成对象映射 。
Database
数据库我选择SQL Server,使用全套微软技术栈工具链使用体验比较好,当然我们也可以选择其他数据库。
SQL Server产品家族中有一个SQL Server LocalDB的东西,它是SQL Server的一个超级精简版本,安装包只有几十MB(安装好后200+MB),它包含了数据库的基础功能,但是不支持联网,只能本机连接,对于个人开发资源占用少,强烈推荐,VS安装Web开发组件会默认安装此数据库。
连接时服务器名称默认是(localdb)\MSSQLLocalDB
,也可以使用C:\Program Files\Microsoft SQL Server\130\Tools\Binn\SqlLocalDB.exe
进行配置数据库实例
我们可以使用VS的SQL Server对象资源管理器来查看我们的数据库,不过我这里强烈推荐使用SQL Server Management Studio (SSMS) 的“数据库关系图”功能来维护数据库,可视化编辑表,主外键关系等,保存即更新数据库,这对于数据库优先的模式下开发非常友好,效率极高。
下图是我们ToDo应用使用的表结构。
代码实战
上面介绍了数据交互的流程概念,接下来我们改造上回制作的ToDo项目。
引入和配置EF Code
我们先创建一个ToDo.Entity
项目用于存储ORM映射以及EF的Context。
注意:目前VS 16.8.4版本创建类库会默认使用.net core 3.1,需要手动修改成.net 5
使用EF Core Power Tools工具创建代码
因为我们上面已经把数据库设计完成了,所以我们采用Database First
模式创建EF相关的代码。
此处推荐一个从数据库到EF实体的代码生成扩展EF Core Power Tools
扩展下载地址:https://marketplace.visualstudio.com/items?itemName=ErikEJ.EFCorePowerTools
选择要连接的数据库。
选择要添加的数据库对象。
配置Context
的名称和命名空间等,下图是我常用配置。
EF Core Power Tools
生成的代码文件如下
appsettings.json中添加链接字符串
打开ToDo.Server\appsettings.json
添加数据库连接字符串
"ConnectionStrings": {
"DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ToDo;Integrated Security=True"
},
使用
EF Core Power Tools
生成的TodoContext.cs
文件中就有默认的连接字符串,开发时想偷懒可以直接从这里复制