前言
上一章节我们引入BootstrapBlazor UI组件完成了EasySQLite后台界面的基本架子的搭建,本章节的主要内容是Blazor班级管理页面编写和接口对接。
七天.NET 8 操作 SQLite 入门到实战详细教程
- 第一天 SQLite 简介
- 第二天 在 Windows 上配置 SQLite 环境
- 第三天 SQLite 快速入门
- 第四天 EasySQLite 前后端项目框架搭建
- 第五天引入 SQLite-net ORM 并封装常用方法
- 第六天后端班级管理相关接口完善和Swagger自定义配置
- 第七天BootstrapBlazor UI组件库引入(1)
EasySQLite 项目源码地址
Blazor简介和快速入门
不熟悉Blazor的同学可以先看这篇文章大概了解一下。
前端Table页面和接口对接代码
主要是常见Table的数据展示、数据添加、数据删除、数据修改等操作。
@page "/SchoolClass" @using Entity @using WebUI.Common @inject HttpClient _httpClient; <Table TItem="SchoolClass" AutoGenerateColumns="true" ShowToolbar="true" IsMultipleSelect="true" OnSaveAsync="@OnSaveAsync" OnQueryAsync="@OnQueryAsync" OnDeleteAsync="@OnDeleteAsync" IsStriped="true" IsBordered="true" ShowSearch="true" IsPagination="true" ShowSearchText="true"> <TableColumns> <TableColumn Sortable="true" Filterable="true" Searchable="true" @bind-Field="@context.ClassName" PlaceHolder="请输入班级名称" /> <TableColumn @bind-Field="@context.ClassID" IsVisibleWhenAdd="false" IsVisibleWhenEdit="false" /> <TableColumn @bind-Field="@context.CreateTime" IsVisibleWhenAdd="false" IsVisibleWhenEdit="false" /> </TableColumns> <SearchTemplate> <GroupBox Title="搜索条件"> <div class="row g-3 form-inline"> <div class="col-12 col-sm-6"> <BootstrapInput @bind-Value="@context.ClassName" PlaceHolder="请输入班级名称" maxlength="50" ShowLabel="true" DisplayText="姓名" /> </div> </div> </GroupBox> </SearchTemplate> </Table> @code { /// <summary> /// 数据查询 /// </summary> /// <param name="options">options</param> /// <returns></returns> private async Task<QueryData<SchoolClass>> OnQueryAsync(QueryPageOptions options) { var getClass = new List<SchoolClass>(); var getResults = await _httpClient.GetFromJsonAsync<ApiResponse<List<SchoolClass>>>("api/SchoolClass/GetClass").ConfigureAwait(false); if (getResults.Success) { // 数据模糊过滤筛选 if (!string.IsNullOrWhiteSpace(options.SearchText)) { getClass = getResults.Data.Where(x => x.ClassName.Contains(options.SearchText)).ToList(); } else { getClass = getResults.Data.ToList(); } } //假分页 return await Task.FromResult(new QueryData<SchoolClass>() { Items = getClass.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList(), TotalCount = getClass.Count() }); } /// <summary> /// 模拟数据增加和修改操作 /// </summary> /// <param name="studentInfo">studentInfo</param> /// <param name="changedType">changedType</param> /// <returns></returns> public async Task<bool> OnSaveAsync(SchoolClass studentInfo, ItemChangedType changedType) { if (changedType.ToString() == "Update") { var addResult = await _httpClient.PutAsJsonAsync($"api/SchoolClass/UpdateClass/{studentInfo.ClassID}", studentInfo).ConfigureAwait(false); if (UtilityBusiness.CheckResponse(addResult)) { return await Task.FromResult(true); } else { return await Task.FromResult(false); } } else if (changedType.ToString() == "Add") { var addResult = await _httpClient.PostAsJsonAsync("api/SchoolClass/CreateClass", studentInfo).ConfigureAwait(false); if (UtilityBusiness.CheckResponse(addResult)) { return await Task.FromResult(true); } else { return await Task.FromResult(false); } } return await Task.FromResult(true); } /// <summary> /// 数据删除 /// </summary> /// <param name="items">items</param> /// <returns></returns> private async Task<bool> OnDeleteAsync(IEnumerable<SchoolClass> items) { var deleteSuccessNum = 0; var schoolClassList = items.ToList(); foreach (var item in schoolClassList) { var delResult = await _httpClient.DeleteAsync($"api/SchoolClass/DeleteClass/{item.ClassID}").ConfigureAwait(false); if (UtilityBusiness.CheckResponse(delResult)) { deleteSuccessNum++; } } if (deleteSuccessNum > 0) { return await Task.FromResult(true); } else { return await Task.FromResult(false); } } }
后端API接口
using Entity; using Microsoft.AspNetCore.Mvc; using Utility; namespace WebApi.Controllers { /// <summary> /// 学校班级管理 /// </summary> [ApiController] [Route("api/[controller]/[action]")] public class SchoolClassController : ControllerBase { private readonly SQLiteAsyncHelper<SchoolClass> _schoolClassHelper; /// <summary> /// 依赖注入 /// </summary> /// <param name="schoolClassHelper">schoolClassHelper</param> public SchoolClassController(SQLiteAsyncHelper<SchoolClass> schoolClassHelper) { _schoolClassHelper = schoolClassHelper; } /// <summary> /// 班级创建 /// </summary> /// <param name="schoolClass">创建班级信息</param> /// <returns></returns> [HttpPost] public async Task<ApiResponse<int>> CreateClass([FromBody] SchoolClass schoolClass) { try { var querySchoolClass = await _schoolClassHelper.QuerySingleAsync(c => c.ClassName == schoolClass.ClassName).ConfigureAwait(false); if (querySchoolClass != null) { return new ApiResponse<int> { Success = false, Message = $"创建班级失败,班级{schoolClass.ClassName}已存在" }; } schoolClass.CreateTime = DateTime.Now; int insertNumbers = await _schoolClassHelper.InsertAsync(schoolClass); if (insertNumbers > 0) { return new ApiResponse<int> { Success = true, Message = "创建班级成功" }; } else { return new ApiResponse<int> { Success = false, Message = "创建班级失败" }; } } catch (Exception ex) { return new ApiResponse<int> { Success = false, Message = ex.Message }; } } /// <summary> /// 获取所有班级信息 /// </summary> [HttpGet] public async Task<ApiResponse<List<SchoolClass>>> GetClass() { try { var classes = await _schoolClassHelper.QueryAllAsync().ConfigureAwait(false); return new ApiResponse<List<SchoolClass>> { Success = true, Data = classes }; } catch (Exception ex) { return new ApiResponse<List<SchoolClass>> { Success = false, Message = ex.Message }; } } /// <summary> /// 根据班级ID获取班级信息 /// </summary> /// <param name="classId">班级ID</param> /// <returns></returns> [HttpGet("{classId}")] public async Task<ApiResponse<SchoolClass>> GetClass(int classId) { try { var schoolClass = await _schoolClassHelper.QuerySingleAsync(c => c.ClassID == classId).ConfigureAwait(false); if (schoolClass != null) { return new ApiResponse<SchoolClass> { Success = true, Data = schoolClass }; } else { return new ApiResponse<SchoolClass> { Success = false, Message = "班级不存在" }; } } catch (Exception ex) { return new ApiResponse<SchoolClass> { Success = false, Message = ex.Message }; } } /// <summary> /// 更新班级信息 /// </summary> /// <param name="classId">班级ID</param> /// <param name="updatedClass">更新的班级信息</param> /// <returns></returns> [HttpPut("{classId}")] public async Task<ApiResponse<int>> UpdateClass(int classId, [FromBody] SchoolClass updatedClass) { try { var existingClass = await _schoolClassHelper.QuerySingleAsync(c => c.ClassID == classId).ConfigureAwait(false); if (existingClass != null) { existingClass.ClassName = updatedClass.ClassName; var updateResult = await _schoolClassHelper.UpdateAsync(existingClass).ConfigureAwait(false); if (updateResult > 0) { return new ApiResponse<int> { Success = true, Message = "班级信息更新成功" }; } else { return new ApiResponse<int> { Success = false, Message = "班级信息更新失败" }; } } else { return new ApiResponse<int> { Success = false, Message = "班级不存在" }; } } catch (Exception ex) { return new ApiResponse<int> { Success = false, Message = ex.Message }; } } /// <summary> /// 班级删除 /// </summary> /// <param name="classId">班级ID</param> /// <returns></returns> [HttpDelete("{classId}")] public async Task<ApiResponse<int>> DeleteClass(int classId) { try { var deleteResult = await _schoolClassHelper.DeleteAsync(classId).ConfigureAwait(false); if (deleteResult > 0) { return new ApiResponse<int> { Success = true, Message = "班级删除成功" }; } else { return new ApiResponse<int> { Success = true, Message = "班级删除失败" }; } } catch (Exception ex) { return new ApiResponse<int> { Success = false, Message = ex.Message }; } } } }
接口对接所遇问题及其解决方案
跨源请求 (CORS)问题
在API服务端启用跨源请求 (CORS):
调用 UseCors 扩展方法并指定 PolicyCorsName CORS 策略。UseCors 添加 CORS 中间件。对 UseCors 的调用必须放在 UseRouting 之后,但在 UseAuthorization 之前。
Program.cs添加如下代码(注意中间件顺序)
var builder = WebApplication.CreateBuilder(args); var PolicyCorsName = "EasySQLitePolicy"; builder.Services.AddCors(option => { option.AddPolicy(PolicyCorsName, builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); var app = builder.Build(); app.UseCors(PolicyCorsName); app.UseAuthorization(); app.MapControllers(); app.Run();
System.Text.Json 反序列化时间异常问题
异常:
Microsoft.AspNetCore.Components.Web.ErrorBoundary[0] System.Text.Json.JsonException: The JSON value could not be converted to System.DateTime. Path: $.Data[0].CreateTime | LineNumber: 0 | BytePositionInLine: 113. ---> System.FormatException: The JSON value is not in a supported DateTime format. at System.Text.Json.ThrowHelper.ThrowFormatException(DataType dataType) at System.Text.Json.Utf8JsonReader.GetDateTime() at System.Text.Json.Serialization.Converters.DateTimeConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
异常原因:
System.Text.Json 时间是认标准的. yyyy-MM-ddTHH:mm:ss 中间得有个T
解决方案:
注释掉服务端对时间日期类型默认格式化处理!
参考文章
- 在 ASP.NET Core 中启用跨源请求 (CORS):https://learn.microsoft.com/zh-cn/aspnet/core/security/cors?view=aspnetcore-8.0