如何在Fast Endpoints中复用处理器,减少.NET 9 WebAPI重复代码?
复用Fast Endpoints CRUD端点逻辑的解决方案
针对你遇到的重复代码问题,最直接高效的方式是封装泛型基类,将通用的CRUD逻辑抽离出来,具体端点只需继承基类并指定必要的类型和配置参数即可。以下是具体实现步骤:
1. 创建泛型基类(以Get单条数据为例)
这个基类将包含通用的路由配置、数据查询、结果映射和响应逻辑:
public abstract class GetEntityEndpoint<TEntity, TDto>( PostgresD db, IMapper mapper, ILogger logger) : EndpointWithoutRequest<TDto> where TEntity : class { // 由子类提供路由模板(例如"/contact/{id:Guid}") protected abstract string RouteTemplate { get; } public override void Configure() { Get(RouteTemplate); // 可在这里添加通用的权限验证、请求验证等配置 } public override async Task HandleAsync(CancellationToken ct) { var id = Route<Guid>("id"); var entity = await db.FindAsync<TEntity>(id, ct); if (entity is null) { await SendNotFoundAsync(ct); return; } Response = mapper.Map<TDto>(entity); logger.LogInformation("获取实体 {EntityType}(ID: {Id})成功", typeof(TEntity).Name, id); } }
2. 简化具体端点实现
原来的GetContact端点只需继承基类,提供路由模板即可:
public class GetContact(PostgresD db, IMapper mapper, ILogger<GetContact> logger) : GetEntityEndpoint<Contact, ContactDto>(db, mapper, logger) { protected override string RouteTemplate => "/contact/{id:Guid}"; }
3. 扩展到其他CRUD操作
用同样的思路可以封装其他CRUD的泛型基类,比如获取列表、创建、更新、删除:
示例:获取列表的泛型基类
public abstract class GetEntityListEndpoint<TEntity, TDto>( PostgresD db, IMapper mapper, ILogger logger) : EndpointWithoutRequest<List<TDto>> where TEntity : class { protected abstract string RouteTemplate { get; } public override void Configure() { Get(RouteTemplate); } public override async Task HandleAsync(CancellationToken ct) { var entities = await db.Set<TEntity>().ToListAsync(ct); Response = mapper.Map<List<TDto>>(entities); logger.LogInformation("获取 {EntityType} 列表成功,共 {Count} 条", typeof(TEntity).Name, entities.Count); } }
示例:创建实体的泛型基类
public abstract class CreateEntityEndpoint<TEntity, TRequest, TDto>( PostgresD db, IMapper mapper, ILogger logger) : Endpoint<TRequest, TDto> where TEntity : class { protected abstract string RouteTemplate { get; } public override void Configure() { Post(RouteTemplate); AllowAnonymous(); // 根据实际需求调整权限 } public override async Task HandleAsync(TRequest req, CancellationToken ct) { var entity = mapper.Map<TEntity>(req); db.Add(entity); await db.SaveChangesAsync(ct); Response = mapper.Map<TDto>(entity); logger.LogInformation("创建 {EntityType} 成功,ID: {Id}", typeof(TEntity).Name, typeof(TEntity).GetProperty("Id")?.GetValue(entity)); } }
关键优势
- 彻底消除重复代码,所有通用逻辑集中维护
- 子类只需关注自身特有的配置(路由、权限等)
- 统一CRUD操作的日志、异常处理(可在基类中扩展)
- 避免了路由构建器方案中访问内部受保护字段的问题,通过抽象属性传递配置参数
内容的提问来源于stack exchange,提问作者Zac Andersen
相关产品推荐
相关产品推荐

