解决方案里的项目结构
| 项目 | 说明 | 所需三方库 | 
|---|---|---|
| APIs | 作为访问数据库的服务和提供 WebApi的项目,其实可以再拆分,把访问数据库的服务拆出来。 | Microsoft.EntityFrameworkCore.DesignMicrosoft.EntityFrameworkCore.ToolsPomelo.EntityFrameworkCore.MySqlNewtonsoft.JsonMicrosoft.Extensions.Configuration.AbstractionsSystem.Linq.Dynamic.Core | 
| Client | 前端 | |
| Shared | 前端 (其实 Client和Shared可以合并为一个,因为是模板自动生成,暂且这样) | BootstrapBlazor | 
| Server | 后端 | Microsoft.EntityFrameworkCore.DesignMicrosoft.EntityFrameworkCore.ToolsPomelo.EntityFrameworkCore.MySqlNewtonsoft.JsonSwashbuckle.AspNetCoreSystem.Linq.Dynamic.Core | 
| Entities | 前后端共用的一些结构体 | Microsoft.Extensions.Configuration.Abstractions | 
| Util | 前后端共用的类封装。 | 根据实际需要 | 
项目引用关系:
- Client:引用 Shared、Entities、Util
- Shared:引用 Entities、Util
- Server:引用 APIs、Entities、Util
人员分工:
如果全程是一个人开发,全部项目添加到同一个解决方案里即可,如果是前后端不同人员开发,则按照下面方式:
- 前端开发负责:Client、Shared、Entities、Util
- 后端开发负责:Server、APIs、Entities、Util
- 公共部分:Entities、Util,除此之外的项目应该按照权限隔离开来。
调试运行:
- 迁移数据库时:设置 Server项目为启动项目,打开PM控制台并切换到APIs,然后执行迁移命令;
- 联调运行时:配置启动项目 - 通用属性 - 启动项目 - 多个启动项目,勾选:Client和Server,然后调试运行即可。这个时候会同时运行服务端和前端,两个项目可以同时调试,比较方便。
接口编写步骤
- 先写 - Model,模型设计及数据库迁移可以参考:C# blazor Web开发之数据库汇总 — 朱皮特的烂笔头
- 配置数据源:创建好数据库,然后配置 - appsettings.json;
- 添加并注册 - DbContext派生类;
- 如果模型及数据有变更,需要执行一次数据迁移; 
- 编写写服务端的 - service(使用- DbContext)并注册,一般是三个文件:一个接口、一个实现、一个扩展服务(可选);
- 编写服务端的 - controller;
- 使用 - swagger测试- 添加三方库: - Swashbuckle.AspNetCore
- 添加初始化代码: - if(env.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } builder.Services.AddSwaggerGen();
- 服务运行后访问:https://localhost:7155/swagger/index.html 测试接口及服务编写的正确性。 
 
- 编写客户端的 - service(使用http发送请求)并注册,一般是两个文件:一个接口、一个实现。
服务请求方法
PostAsync
public async Task<ServiceResponse<bool>> Create(Module obj) {
    ServiceResponse<bool> ret = new();
    if (obj.Memo?.Length > Settings.MemoMaxSize) {
        obj.Memo = obj.Memo.Substring(0, Settings.MemoMaxSize);
    }
    var postContent = System.Text.Json.JsonSerializer.Serialize(obj, _jsonSerializerOptions);
    var bodyContent = new StringContent(postContent, Encoding.UTF8, "application/json");
    var response = await _client.PostAsync("api/module/create", bodyContent);
    if (response.IsSuccessStatusCode) {
        ret = await response.Content.ReadFromJsonAsync<ServiceResponse<bool>>(_jsonSerializerOptions) ?? ret;
    } else {
        ret.Success = false;
        var content = await response.Content.ReadAsStringAsync();
        ret.Message = $"Create failed with status code: {response.StatusCode}\nResponse content: {content}";
        throw new ApplicationException(content);
    }
    return ret;
}
PostAsJsonAsync
public async Task<ServiceResponse<PagedList<Module>>> GetAll(ModuleFilterParam param) {
    HttpResponseMessage response = await _client.PostAsJsonAsync($"api/module", param);
    response.EnsureSuccessStatusCode(); // 确保响应成功
    var content = await response.Content.ReadFromJsonAsync<ServiceResponse<PagedList<Module>>>(_jsonSerializerOptions);
    return content ?? new();
}
DeleteAsync
public async Task Delete(long id) {
    var postResult = await _client.DeleteAsync("api/module/delete/" + id);
    var postContent = await postResult.Content.ReadAsStringAsync();
    if (!postResult.IsSuccessStatusCode) {
        throw new ApplicationException(postContent);
    }
}
PutAsync
public async Task<ServiceResponse<bool>> Update(Module obj) {
    ServiceResponse<bool> ret = new();
    try {
        var postContent = System.Text.Json.JsonSerializer.Serialize(obj, _jsonSerializerOptions);
        var bodyContent = new StringContent(postContent, Encoding.UTF8, "application/json");
        var response = await _client.PutAsync("api/module/update", bodyContent);
        if (response.IsSuccessStatusCode) {
            ret = await response.Content.ReadFromJsonAsync<ServiceResponse<bool>>(_jsonSerializerOptions) ?? ret;
        } else {
            var content = await response.Content.ReadAsStringAsync();
            ret.Success = false;
            ret.Message = $"Update failed with status code: {response.StatusCode}\nResponse content: {content}";
            throw new ApplicationException(content);
        }
    } catch (Exception e) {
        ret.Success = false;
        ret.Message = $"Exception occured in Update: {e.Message}";
        if (e.InnerException != null) {
            ret.Message += $"\nInner exception: {e.InnerException.Message}";
        }
        ret.Message += $"\bStack trace: {e.StackTrace}";
        throw;
    }
    return ret;
}
DeleteFromJsonAsync
GetFromJsonAsync
var res = await _client.GetFromJsonAsync<ServiceResponse<xxx>>(Url + "/api/chat/message");
res.Data
PatchAsJsonAsync
PostAsJsonAsync
PutAsJsonAsync
文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/program/blazor-client-server-api.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)