共计 16579 个字符,预计需要花费 42 分钟才能阅读完成。
《进击吧!Blazor!》是自己与张善友老师单干的 Blazor 零根底入门系列视频,此系列能让一个从未接触过 Blazor 的程序员把握开发 Blazor 利用的能力。
视频地址:https://space.bilibili.com/48…
演示代码:https://github.com/TimChen44/…
本系列文章是基于《进击吧!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 接口
官网文档:https://docs.microsoft.com/zh…
我的项目构造如下
- 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 作为咱们的数据拜访技术
官网文档:https://docs.microsoft.com/zh…
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.visualstu…
抉择要连贯的数据库。
抉择要增加的数据库对象。
配置 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
文件中就有默认的连贯字符串,开发时想偷懒能够间接从这里复制????。
ConfigureServices 中增加服务注册
关上 ToDo.Server\Startup.cs
,把TodoContext
注册到 DbContext
中为,并设置连贯字符串
services.AddDbContext<TodoContext>(options =>
{options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
有时候咱们须要在输入 EF 执行的 SQL 语句,这便于咱们调试以及优化数据库,上面的配置就把 EF 日志输入到控制台
/// <summary>
/// 输入日志
/// </summary>
public static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
public void ConfigureServices(IServiceCollection services)
{
// 省略其余代码
services.AddDbContext<TodoContext>(options =>
{options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")).UseLoggerFactory(loggerFactory);
});
}
性能实现
首先创立 ToDo.Server\Controllers\TaskController.cs
文件用于编写 WebAPI 接口,代码如下:
namespace ToDo.Server.Controllers
{[ApiController]
[Route("api/[controller]/[action]")]
public class TaskController : ControllerBase
{
TodoContext Context;
public TaskController(TodoContext context)
{Context = context;}
}
}
通过依赖注入将 TodoContext
注入到以后类中。
1. 列出当天的所有代办工作
ToDo.Server
TaskController.cs
中增加 GetToDayTask
办法用于返回以后待办数据。
[HttpGet]
public List<TaskDto> GetToDayTask()
{var result = Context.Task.Where(x => x.PlanTime == DateTime.Now.Date);
return QueryToDto(result).ToList();}
[NonAction]
private IQueryable<TaskDto> QueryToDto(IQueryable<Entity.Task> query)
{return query.Select(x => new TaskDto()
{
TaskId = x.TaskId,
Title = x.Title,
Description = x.Description,
PlanTime = x.PlanTime,
Deadline = x.Deadline,
IsImportant = x.IsImportant,
IsFinish = x.IsFinish,
});
}
ToDo.Client
增加 Pages\ToDay.razor.cs
类文件,VS 会主动将 ToDay.razor
与ToDay.razor.cs
折叠到一起。
在类定义中减少 partial
关键字,申明类为部分类,你能够了解成 ToDay.razor
与ToDay.razor.cs
中的代码都属于同一个类,只是放在不同文件中,编译器编译时会将他们合并到一起后进行编译。
public partial class ToDay
接着做一下代码迁徙
- 将
Pages\ToDay.razor
文件@code{}
中的代码剪切到ToDay.razor.cs
- 将
Pages\ToDay.razor
文件@inject
代码采纳[Inject] public MessageService MsgSrv {get; set;}
这样的格局等价的迁徙到ToDay.razor.cs
这样做咱们能够实现界面代码与业务代码离开在不同的文件中,不便整顿代码,进步代码可读性。
后续其余页面我默认实现了创立部分类的操作,不再赘述。
ToDay.razor.cs
中增加 HttpClient
的依赖注入,用于向服务端发动 Http 申请
[Inject] public HttpClient Http {get; set;}
我的项目中其余类如果应用到
HttpClient
,我默认实现了依赖注入,不再赘述。???? 广告工夫????
Blazor
和Ant Design Blazor
中有很多服务,咱们常常在不同的中央须要注入,为了编码不便,咱们提供了一个 VS 扩大疾速插入罕用服务代码段,装置地址:https://marketplace.visualstu…
批改 OnInitializedAsync
办法的代码
private List<TaskDto> taskDtos = new List<TaskDto>();
bool isLoading = true;
protected async override Task OnInitializedAsync()
{
isLoading = true;
taskDtos = await Http.GetFromJsonAsync<List<TaskDto>>("api/Task/GetToDayTask");
isLoading = false;
await base.OnInitializedAsync();}
Http.GetFromJsonAsync<List<TaskDto>>
应用 HttpGet
模式申请数据,这里应用 await
进行异步期待,充分利用 await
能够极大的简化代码量。isLoading
是载入状态,网络通讯必然有提早,防止白屏,咱们在载入前后别离扭转载入状态,同时批改 ToDay.razor
代码增加 Spin
组件用于显示载入成果。
<PageHeader Title="@(" 我的一天 ")" Subtitle="@DateTime.Now.ToString("yyyy 年 MM 月 dd 日 ")"></PageHeader>
<Spin Spinning="isLoading"><!-- 插入代码 -->
@foreach (var item in taskDtos)
<!-- 省略其余代码 -->
<Input @bind-Value="@newTask.Title" OnkeyUp="OnInsert" />
</div>
</Spin><!-- 插入代码 -->
2. 增加代办
ToDo.ServerTaskController.cs
中增加 SaveTask
办法用于保留新的待办内容
[HttpPost]
public Guid SaveTask(TaskDto dto)
{
Entity.Task entity;
if (dto.TaskId == Guid.Empty)
{entity = new Entity.Task();
entity.TaskId = Guid.NewGuid();
Context.Add(entity);
}
else
{entity = Context.Task.FirstOrDefault(x => x.TaskId == dto.TaskId);
}
entity.Title = dto.Title;
entity.Description = dto.Description;
entity.PlanTime = dto.PlanTime;
entity.Deadline = dto.Deadline;
entity.IsImportant = dto.IsImportant;
entity.IsFinish = dto.IsFinish;
Context.SaveChanges();
return entity.TaskId;
}
我通过判断 dto.TaskId
的值,间接将新增与更新写在一个接口中,这样能够复用代码。
此处能够应用
AutoMapper
库来简化赋值过程,这将在未来的章节中具体介绍
ToDo.ClientToDay.razor.cs
文件批改 OnInsert
办法相干的代码
TaskDto newTask = new TaskDto() { PlanTime = DateTime.Now.Date};
[Inject] public MessageService MsgSrv {get; set;}
bool isNewLoading = false;
async void OnInsert(KeyboardEventArgs e)
{if (e.Code == "Enter")
{if (string.IsNullOrWhiteSpace(newTask.Title))
{MsgSrv.Error($"题目必须填写");
return;
}
isNewLoading = true;
var result = await Http.PostAsJsonAsync<TaskDto>($"api/Task/SaveTask", newTask);
if (result.IsSuccessStatusCode)
{newTask.TaskId = await result.Content.ReadFromJsonAsync<Guid>();
taskDtos.Add(newTask);
newTask = new TaskDto() { PlanTime = DateTime.Now.Date};
}
else
{MsgSrv.Error($"申请产生谬误 {result.StatusCode}");
}
isNewLoading = false;
StateHasChanged();}
}
ToDay.razor
文件减少保留时期待组件
<Spin Spinning="isNewLoading"><!-- 插入代码 -->
<div class="task-input">
<DatePicker Picker="@DatePickerType.Date" @bind-Value="@newTask.PlanTime" />
<Input @bind-Value="@newTask.Title" OnkeyUp="OnInsert" />
</div>
</Spin><!-- 插入代码 -->
通过 Http.PostAsJsonAsync
调用 api/Task/SaveTask
将newTask
内容提交到后端并保留,返回的 HttpResponseMessage
蕴含了状态编码等,如果胜利就在界面上显示新的待办,失败就提醒谬误
MessageService
全局展现操作反馈信息。
组件文档地址:https://ant-design-blazor.git…
3. 编辑待办
ToDo.ServerTaskController.cs
中增加 GetTaskDto
办法用于获取待办信息
public TaskDto GetTaskDto(Guid taskId)
{var result = Context.Task.Where(x => x.TaskId == taskId);
return QueryToDto(result).FirstOrDefault();}
ToDo.ClientTaskInfo.razor
文件中减少 Spin
与@if
代码
<Spin Spinning="isLoading">
@if (taskDto != null)<!-- 页面关上时 taskDto 并没有值,所以间接绑定到 Form 会产生异样,所以这里须要做一个不为空判断 -->
{
<Form OnFinish="OnSave" Model="taskDto" LabelColSpan="8"><!-- 当用户点击 submit 按钮时会触发 OnFinish 事件,所以通常会在这里进行保留操作 -->
<!-- 省略其余代码 -->
<div>
<Button HtmlType="submit"> 保留 </Button>
<Button OnClick="OnCancel"> 勾销 </Button>
</div>
</Form>
}
</Spin>
TaskInfo.razor.cs
增加上面代码
public partial class TaskInfo : DrawerTemplate<TaskDto, TaskDto>
{[Inject]
public HttpClient Http {get; set;}
[Inject]
public MessageService MsgSvr {get; set;}
TaskDto taskDto;
bool isLoading = false;
protected override async Task OnInitializedAsync()
{
// 通过 api/Task/GetTaskDto 接口取得待办内容
taskDto = await Http.GetFromJsonAsync<TaskDto>($"api/Task/GetTaskDto?taskId={base.Options.TaskId}");
await base.OnInitializedAsync();}
async void OnSave()
{var result = await Http.PostAsJsonAsync<TaskDto>($"api/Task/SaveTask", taskDto);
if (result.StatusCode == System.Net.HttpStatusCode.OK)
{await base.CloseAsync(taskDto);// 敞开抽屉,并返回以后待办数据
}
else
{MsgSvr.Error($"申请产生谬误 {result.StatusCode}");
}
}
async void OnCancel()
{await base.CloseAsync(null);// 如果点击了勾销,那么将 null 返回进来
}
}
ToDay.razor.cs
中的 OnCardClick
办法更新
[Inject] public DrawerService DrawerSrv {get; set;}
async void OnCardClick(TaskDto task)
{var result = await DrawerSrv.CreateDialogAsync<TaskInfo, TaskDto, TaskDto>(task, title: task.Title, width: 450);
if (result == null) return;
var index = taskDtos.FindIndex(x => x.TaskId == result.TaskId);
taskDtos[index] = result;
await InvokeAsync(StateHasChanged);
}
DrawerSrv.CreateDialogAsync
绝对于 DrawerSrv.CreateAsync
简化了调用办法,默认将抽屉的 CloseAsync
参数返回,这就简化了每次应用抽屉时须要注册 CloseAsync
事件的麻烦,也让代码更加清晰。title: task.Title, width: 450
应用可选参数简化对抽屉的参数配置。
DrawerService 组件帮忙文档:https://ant-design-blazor.git…
4. 批改重要水平
ToDo.ServerTaskController.cs
中增加 SetImportant
办法用于批改 IsImportant
字段的值
[HttpPost]
public void SetImportant(SetImportantReq req)
{var entity = Context.Task.FirstOrDefault(x => x.TaskId == req.TaskId);
entity.IsImportant = req.IsImportant;
Context.SaveChanges();}
ToDo.Shared
增加 SetImportantReq
类用于 SetImportant
接口申请参数
public class SetImportantReq
{public Guid TaskId { get; set;}
public bool IsImportant {get; set;}
}
ToDo.ClientToDay.razor.cs
中的 OnStar
办法更新
private async void OnStar(TaskDto task)
{var req = new SetImportantReq()//ToDo.Shared 我的项目中的类能够前后端专用,这就是 Blazor 劣势之一。{
TaskId = task.TaskId,
IsImportant = !task.IsImportant,
};
var result = await Http.PostAsJsonAsync<SetImportantReq>("api/Task/SetImportant", req);
if (result.IsSuccessStatusCode)
{
task.IsImportant = req.IsImportant;// 申请胜利后须要批改本地重要状态
StateHasChanged();// 状态扭转,刷新页面的显示}
}
5. 批改实现状态
ToDo.ServerTaskController.cs
中增加 SetFinish
办法用于批改 IsFinish
字段的值
[HttpPost]
public void SetFinish(SetFinishReq req)
{var entity = Context.Task.FirstOrDefault(x => x.TaskId == req.TaskId);
entity.IsFinish = req.IsFinish;
Context.SaveChanges();}
ToDo.Shared
增加 SetFinishReq
类用于 SetFinish
接口申请参数
public class SetFinishReq
{public Guid TaskId { get; set;}
public bool IsFinish {get; set;}
}
ToDo.ClientToDay.razor.cs
中的 OnFinish
办法更新
private async void OnFinish(TaskDto task)
{var req = new SetFinishReq()
{
TaskId = task.TaskId,
IsFinish = !task.IsFinish,
};
var result = await Http.PostAsJsonAsync<SetFinishReq>("api/Task/SetFinish", req);
if (result.IsSuccessStatusCode)
{
task.IsFinish = req.IsFinish;
StateHasChanged();}
}
6. 删除代办
ToDo.ServerTaskController.cs
中增加 DelTask
办法用于删除待办。
[HttpDelete]
public void DelTask(Guid taskId)
{Context.Task.Remove(Context.Task.Find(taskId));
Context.SaveChanges();}
ToDo.ClientToDay.razor.cs
中的 OnFinish
办法更新
[Inject] public ConfirmService ConfirmSrv {get; set;}
public async Task OnDel(TaskDto task)
{if (await ConfirmSrv.Show($"是否删除工作 {task.Title}", "删除", ConfirmButtons.YesNo, ConfirmIcon.Info) == ConfirmResult.Yes)
{taskDtos.Remove(task);
}
}
ConfirmService
能够快捷地弹出一个内置的确认框,相似于 Windows MessageBox。
ConfirmService 组件帮忙文档:https://ant-design-blazor.git…
7. 查问代办
ToDo.ServerTaskController.cs
中增加 GetSearch
办法用于批改 SetFinish
字段的值
[HttpPost]
public GetSearchRsp GetSearch(GetSearchReq req)
{if (req.PageIndex == 0) req.PageIndex = 1;
var query = Context.Task.Where(x => x.Title.Contains(req.QueryTitle ?? ""));
foreach (var sort in req.Sorts)
{if (sort.SortOrder == "descend")
query = query.OrderBy(sort.SortField + "DESC");
else
query = query.OrderBy(sort.SortField);
}
var result = new GetSearchRsp()
{Data = QueryToDto(query.Skip(--req.PageIndex * req.PageSize).Take(req.PageSize)).ToList(),
Total = query.Count(),};
return result;
}
if (req.PageIndex == 0) req.PageIndex = 1
???? 吐槽开始:简直所有的 UI 框架页码都是从 0 开始,然而 AntDesign 标准的页码是从 1 开始的,然而没有载入数据时又是返回 0????,所以要特地留神。
OrderBy
应用了System.Linq.Dynamic.Core
扩大包,它提供了一些动静的 Linq 反对,比方此处排序我传入的参数不是一个表达式,而是一个字符串,这样能够让代码灵活性大增。
ToDo.Shared
public class GetSearchReq
{public string QueryTitle { get; set;}
public int PageIndex {get; set;}
public int PageSize {get; set;}
public List<SortFieldName> Sorts {get; set;}
}
public class SortFieldName
{
/// <summary>
/// 排序字段
/// </summary>
public string SortField {get; set;}
/// <summary>
/// 排序方向
/// </summary>
public string SortOrder {get; set;}
}
public class GetSearchRsp
{public List<TaskDto> Data { get; set;}
public int Total {get; set;}
}
ToDo.ClientTaskSearch.razor
文件的代码
@page "/search"
<PageHeader Title="@(" 全副待办事项 ")" Subtitle="@($" 数量:{total}")"></PageHeader>
<Search @bind-Value="queryTitle" OnSearch="OnSearch"></Search>
<Table Loading="@isLoading" DataSource="@datas" PageSize="10" Total="@total" OnChange="OnChange" TItem="TaskDto">
<AntDesign.Column @bind-Field="@context.Title" Sortable>
@context.Title
@if (context.IsImportant)
{<Tag Color="orange"> 重要 </Tag>}
</AntDesign.Column>
<AntDesign.Column @bind-Field="@context.Description" />
<AntDesign.Column @bind-Field="@context.PlanTime" Sortable />
<AntDesign.Column @bind-Field="@context.Deadline" />
<AntDesign.Column @bind-Field="@context.IsFinish">
@if (context.IsFinish)
{<Icon Type="check" Theme="outline" />}
</AntDesign.Column>
</Table>
TaskSearch.razor.cs
文件的代码
[Inject] public HttpClient Http {get; set;}
private bool isLoading = false;
List<TaskDto> datas = new List<TaskDto>();
private string queryTitle;
private int total = 0;
// 点击查问按钮时检索数据
private async Task OnSearch()
{await OnQuery(1, 10, new List<SortFieldName>());
}
// 以后页码,排序产生扭转时调用查询方法检索数据
private async Task OnChange(AntDesign.TableModels.QueryModel<TaskDto> queryModel)
{
await OnQuery(
queryModel.PageIndex,
queryModel.PageSize,
queryModel.SortModel.Where(x => string.IsNullOrEmpty(x.SortType.Name) == false).OrderBy(x => x.Priority)
.Select(x => new SortFieldName() {SortField = x.FieldName, SortOrder = x.SortType.Name}).ToList());
}
// 检索数据
private async Task OnQuery(int pageIndex, int pageSize, List<SortFieldName> sort)
{
isLoading = true;
var req = new GetSearchReq()
{
QueryTitle = queryTitle,
PageIndex = pageIndex,
PageSize = pageSize,
Sorts = sort,
};
var httpRsp = await Http.PostAsJsonAsync<GetSearchReq>($"api/Task/GetSearch", req);
var result = await httpRsp.Content.ReadFromJsonAsync<GetSearchRsp>();
datas = result.Data;
total = result.Total;
isLoading = false;
}
Search
带有查问按钮的文本框框
Search 组件文档地址:https://ant-design-blazor.git…
查看具体服务
在 我的一天
与全副
页面上均存在关上待办详情的性能需要,这时咱们就能够本人做一个服务将两边的性能合并到一起。
增加 TaskDetailServices.cs
文件,退出以下代码
namespace ToDo.Client
{
public class TaskDetailServices
{public DrawerService DrawerSvr { get; set;}
public TaskDetailServices(DrawerService drawerSvr)
{DrawerSvr = drawerSvr;}
public async Task EditTask(TaskDto taskDto, List<TaskDto> datas)
{var taskItem = await DrawerSvr.CreateDialogAsync<TaskInfo, TaskDto, TaskDto>(taskDto, title: taskDto.Title, width: 450);
if (taskItem == null) return;
var index = datas.FindIndex(x => x.TaskId == taskItem.TaskId);
datas[index] = taskItem;
}
}
}
TaskDetailServices(DrawerService drawerSvr)
只有 razor
文件能够应用 [Inject]
标记属性进行注入服务,一般得类须要在构造函数中定义能力注入服务。
Program.cs
文件中注册TaskDetailServices
builder.Services.AddScoped<TaskDetailServices>();
TaskSearch.razor
文件中增加详情按钮
<AntDesign.Column TData="object">
<Button OnClick="x=>OnDetail(context)"> 详情 </Button>
</AntDesign.Column>
TaskSearch.razor.cs
插入以下代码,咱们注入自定义的服务,应用服务中的办法关上编辑界面。
[Inject] public TaskDetailServices TaskSrv {get; set;}
private async Task OnDetail(TaskDto taskDto)
{await TaskSrv.EditTask(taskDto, datas);
}
次回预报
下一次咱们要介绍 Blazor 的精华,也是我集体认为 Blazor 框架体系中最优良的个性——组件。咱们通过几个小实例展现 Blazor 的组件开发方法,敬请期待
学习材料:
https://aka.ms/LearnBlazor