Web API C# (Furion版)

发布时间:2026/7/31 11:27:31
Web API C# (Furion版) 這是官網https://furion.net/docs/category/appendix主要做的是一個後端API接口程序給前端訪問。用C#ASP .net開發框架用了FurionFurion EFCore 脚手架安装下载Furiondotnet new install Furion.Template.Api::4.9.5.21不带版本号总是安装最新的版本根据需要来创建项目# 命令模板如下dotnet new 关键词 -n 项目名称 -f .NET版本# EFCore支持创建 .NET5-8 版本D:\Projects\VS\TestWebdotnet new furionapi -n EmployeeApi -f net7範本「Furion Api」已成功建立。範本套件 Furion.Template.Api4.9.5.21 有可用的更新。若要更新套件請使用:dotnet new install Furion.Template.Api4.9.9.45D:\Projects\VS\TestWeb运行demo创建完就能用vs打开了注意这边有很多项目都是一个解决方案。把EmployeeApi.Web.Entry设置成启动程序。就能运行项目了里面有一个demo项目结构Application 放业务逻辑就是servicedtoCore 放modelsDatabse.Migrations 数据库迁移 EF coreEntityFramework.core 放DbContextweb.core web组件Entry 程序入口Program.cs Controllers创建模型Employee.csusing Furion.DatabaseAccessor; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EmployeeApi.Core.Models { public class Employee : Entity { //Entity //无需定义 Id 属性 // 并自动添加 CreatedTimeUpdatedTime 属性 public string Name { get; set; } public int Age { get; set; } public string Dept { get; set; } } }数据库配置数据库上下文EmployeeDbContext.csusing EmployeeApi.Core.Models; using Furion.DatabaseAccessor; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EmployeeApi.EntityFramework.Core.DbContexts { [AppDbContext(MyDb, DbProvider.Sqlite)] public class EmployeeDbContext : AppDbContextEmployeeDbContext { public EmployeeDbContext(DbContextOptionsEmployeeDbContext options) : base(options) { } public DbSetEmployee employees { get; set; } } }配置数据库链接参考SqliteData Source./Furion.dbMySqlData Sourcelocalhost;DatabaseFurion;User IDroot;Password000000;poolingtrue;port3306;sslmodenone;CharSetutf8;SqlServerServerlocalhost;DatabaseFurion;Usersa;Password000000;MultipleActiveResultSetsTrue;OracleUser Idorcl;Passwordorcl;Data Source(DESCRIPTION(ADDRESS_LIST(ADDRESS(PROTOCOLTCP)(HOST127.0.0.1)(PORT1521)))(CONNECT_DATA(SERVICE_NAMEorcl)))PostgreSQLPORT5432;DATABASEpostgres;HOST127.0.0.1;PASSWORDpostgres;USER IDpostgres;appsettings.json{ $schema: https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json, Logging: { LogLevel: { Default: Information, Microsoft.AspNetCore: Warning, Microsoft.EntityFrameworkCore: Information } }, AllowedHosts: *, ConnectionStrings: { MyDb: Data SourceD:\\Projects\\VS\\TestWeb\\EmployeeApi\\app.db } }注册该数据库上下文Startup.csusing EmployeeApi.EntityFramework.Core.DbContexts; using Furion; using Microsoft.Extensions.DependencyInjection; namespace EmployeeApi.EntityFramework.Core; public class Startup : AppStartup { public void ConfigureServices(IServiceCollection services) { services.AddDatabaseAccessor(options { options.AddDbPoolDefaultDbContext(); options.AddDbPoolEmployeeDbContext(); //注册数据库上下文 }, EmployeeApi.Database.Migrations); } }模型生成数据库code first方法一用cmd或者powershell用命令安装在\EmployeeApi.Database.Migrations项目下面dotnet add package Microsoft.EntityFrameworkCore.Sqlitedotnet add package Microsoft.EntityFrameworkCore.Designdotnet tool install --global dotnet-ef注意因为这边没有用最新的.net所以你用vs 界面去找对应版本dotnet tool install --global dotnet-ef --version 7.* 也要是对应版本运行下面命令要在EmployeeApi.Web.Entry启动项目下面运行dotnet ef database update --context EmployeeDbContext --project ../EmployeeApi.Database.Migrationsdotnet ef database update --context EmployeeDbContext --project ../EmployeeApi.Database.Migrations成功后app.db就有了参考dotnet ef migrations add InitialCreate_MyProject \--context MyProjectDbContext \ # 为这个 DbContext 生成迁移--output-dir Migrations \ # 生成的迁移文件放在 Migrations 文件夹下--project ../MyProject.Database.Migrations # 把整个 Migrations 文件夹放到这个项目里方法二执行Add-Migration -Context EmployeeDbContext v1.0.0Update-Database -Context EmployeeDbContextController准备dtoserviceDTO这边就写一个也可以写多个比如添加员工写一个更新写一个。EmployeeDto.csusing System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EmployeeApi.Application.EmployeeManage.Dtos { public class EmployeeDto { public string Name { get; set; } public int Age { get; set; } public string Dept { get; set; } } }service以接口形式写方便以后拓展IEmployeeService.csusing EmployeeApi.Application.EmployeeManage.Dtos; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EmployeeApi.Application.EmployeeManage.Services { public interface IEmployeeService { TaskListEmployeeDto GetEmoloyeesAsync(); TaskEmployeeDto GetEmployeeByIdAsync(int id); Taskint CreateEmployeeAsync(EmployeeDto employeeDto); Taskbool UpdateEmployeeAsync(EmployeeDto employeeDto); Taskbool DeleteEmployeeAsync(int id); } }注意ITransient一定要有。三种注册的生命周期一般就用这个EmployeeService.csusing EmployeeApi.Application.EmployeeManage.Dtos; using EmployeeApi.EntityFramework.Core.DbContexts; using EmployeeApi.Core.Models; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EmployeeApi.Application.EmployeeManage.Services { public class EmployeeService : IEmployeeService, ITransient { private readonly EmployeeDbContext _employeeDbContext; public EmployeeService(EmployeeDbContext employeeDbContext) { _employeeDbContext employeeDbContext; } public async Taskint CreateEmployeeAsync(EmployeeDto employeeDto) { var employee new Employee { Name employeeDto.Name, Age employeeDto.Age, Dept employeeDto.Dept }; await _employeeDbContext.employees.AddAsync(employee); await _employeeDbContext.SaveChangesAsync(); return employee.Id; } public async Taskbool DeleteEmployeeAsync(int id) { var employee await _employeeDbContext.employees.FindAsync(id); if (employee null) { return false; } _employeeDbContext.employees.Remove(employee); await _employeeDbContext.SaveChangesAsync(); return true; } public async TaskListEmployeeDto GetEmoloyeesAsync() { return await _employeeDbContext.employees .Select(e new EmployeeDto { Name e.Name, Age e.Age, Dept e.Dept }) .ToListAsync(); } public async TaskEmployeeDto GetEmployeeByIdAsync(int id) { var employee await _employeeDbContext.employees.FindAsync(id); if (employee null) { return null; } var employeeDto new EmployeeDto { Name employee.Name, Age employee.Age, Dept employee.Dept }; return employeeDto; } public async Taskbool UpdateEmployeeAsync(UpdateEmployeeRequest request) { var employee await _employeeDbContext.employees.FindAsync(request.Id); if (employee null) { return false; } employee.Name request.Name; employee.Age request.Age; employee.Dept request.Dept; await _employeeDbContext.SaveChangesAsync(); return true; } } }controllerEmployeeController.csusing EmployeeApi.Application.EmployeeManage.Dtos; using EmployeeApi.Application.EmployeeManage.Services; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EmployeeApi.Application.EmployeeManage { public class EmployeeController : IDynamicApiController { private readonly IEmployeeService _employeeService; public EmployeeController(IEmployeeService employeeService) { _employeeService employeeService; } [HttpPost] public async Taskint PostCreateEmployee(EmployeeDto employeeDto) { return await _employeeService.CreateEmployeeAsync(employeeDto); } [HttpGet] public async TaskListEmployeeDto GetAllEmployees() { return await _employeeService.GetEmoloyeesAsync(); } [HttpGet] public async TaskEmployeeDto GetEmployeeById(int id) { return await _employeeService.GetEmployeeByIdAsync(id); } [HttpPost] public async Taskbool UpdateEmployee(UpdateEmployeeRequest request) { return await _employeeService.UpdateEmployeeAsync(request); } [HttpPost] public async Taskbool DeleteEmployee(int id) { return await _employeeService.DeleteEmployeeAsync(id); } } }到这边就完成了运行项目就能测试了。进阶Mapster在过去我们需要将一个对象的值转换到另一个对象中我们需要这样做如var entity repository.Find(1); var dto new Dto(); dto.Id entity.Id; dto.Name entity.Name; dto.Age entity.Age; dto.Address entity.Address; dto.FullName entity.FirstName entity.LastName; dto.IdCard entity.IdCard.Replace(1234, ****);上面的例子似乎没有任何问题但是如果很多地方需要这样的赋值操作、或者相同的赋值操作在多个地方使用又或者一个类中含有非常多的属性或自定义赋值操作。那么这样的操作效率极低容易出错且代码非常臃肿和冗余。所以实现自动映射赋值和支持特殊配置的需求就有了。目前C#平台有两个优秀的对象映射工具Mapster和AutoMapper。在Furion框架中推荐使用MapsterMapster是一款极易使用且超高性能的对象映射框架。var dto employee.AdaptEmployeeDto();employee转EmployeeDto示例Employee → EmployeeDto字段完全一致如果两个类的字段名称完全一样不需要任何配置直接用 .Adapt() 就行。var dto employee.AdaptEmployeeDto(); // ✅ 字段名相同自动映射示例Employee → EmployeeDto字段名不同如果字段名不完全一致需要在 Mapper 中配置public class Employee { public int Id { get; set; } public string FullName { get; set; } // Model 里叫 FullName public int Age { get; set; } public string Department { get; set; } // Model 里叫 Department } public class EmployeeDto { public int Id { get; set; } public string Name { get; set; } // DTO 里叫 Name public int Age { get; set; } public string Dept { get; set; } // DTO 里叫 Dept }using Mapster; using EmployeeApi.Core.Models; using EmployeeApi.Application.EmployeeManage.Dtos; namespace EmployeeApi.Application; public class Mapper : IRegister { public void Register(TypeAdapterConfig config) { // 配置 Employee → EmployeeDto 的映射关系 config.NewConfigEmployee, EmployeeDto() .Map(dest dest.Name, src src.FullName) // FullName → Name .Map(dest dest.Dept, src src.Department); // Department → Dept // 配置 EmployeeDto → Employee反向映射用于创建/更新 config.NewConfigEmployeeDto, Employee() .Map(dest dest.FullName, src src.Name) .Map(dest dest.Department, src src.Dept); } }情况是否需要配置怎么做Model 字段比 DTO 多❌ 不需要直接.Adapt()多余的自动忽略Model 字段比 DTO 少❌ 不需要多余的 DTO 字段为null或默认值字段名相同❌ 不需要自动映射字段名不同✅ 需要在Mapper.cs中用.Map()配置需要忽略某个字段✅ 需要用.Ignore()明确忽略ProjectToTypeProjectToType 是 Mapster 提供的专门用于 EF Core 查询 的映射方法它的核心作用是在数据库层面执行映射只查询 DTO 需要的字段。参考例子using EmployeeApi.Application.EmployeeManage.Dtos; using EmployeeApi.EntityFramework.Core.DbContexts; using EmployeeApi.Core.Models; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EmployeeApi.Application.EmployeeManage.Services { public class EmployeeService : IEmployeeService, ITransient { private readonly EmployeeDbContext _employeeDbContext; public EmployeeService(EmployeeDbContext employeeDbContext) { _employeeDbContext employeeDbContext; } public async Taskint CreateEmployeeAsync(EmployeeDto employeeDto) { //var employee new Employee //{ // Name employeeDto.Name, // Age employeeDto.Age, // Dept employeeDto.Dept //}; var employee employeeDto.AdaptEmployee(); await _employeeDbContext.employees.AddAsync(employee); await _employeeDbContext.SaveChangesAsync(); return employee.Id; } public async Taskbool DeleteEmployeeAsync(int id) { var employee await _employeeDbContext.employees.FindAsync(id); if (employee null) { return false; } _employeeDbContext.employees.Remove(employee); await _employeeDbContext.SaveChangesAsync(); return true; } public async TaskListEmployeeDto GetEmoloyeesAsync() { //return await _employeeDbContext.employees // .Select(e new EmployeeDto // { // Name e.Name, // Age e.Age, // Dept e.Dept // }) // .ToListAsync(); return await _employeeDbContext.employees .ProjectToTypeEmployeeDto() .ToListAsync(); } public async TaskEmployeeDto GetEmployeeByIdAsync(int id) { var employee await _employeeDbContext.employees.FindAsync(id); if (employee null) { return null; } //var employeeDto new EmployeeDto //{ // Name employee.Name, // Age employee.Age, // Dept employee.Dept //}; var employeeDto employee.AdaptEmployeeDto(); return employeeDto; } public async Taskbool UpdateEmployeeAsync(UpdateEmployeeRequest request) { var employee await _employeeDbContext.employees.FindAsync(request.Id); if (employee null) { return false; } //employee.Name request.Name; //employee.Age request.Age; //employee.Dept request.Dept; request.AdaptEmployee(); await _employeeDbContext.SaveChangesAsync(); return true; } } }