ABP 框架集成 EasyAbp.Abp.GraphQL 构建高性能 GraphQL API
🚀 ABP 框架集成 EasyAbp.Abp.GraphQL 构建高性能 GraphQL API
📚 目录
- 🚀 ABP 框架集成 EasyAbp.Abp.GraphQL 构建高性能 GraphQL API
- 🧭 背景与目标
- 🛠 安装与依赖
- 📦 模块注册与启动
- MyProjectHttpApiHostModule.cs
- Program.cs 最小化示例
- 🔐 安全性增强
- ✍ 构建服务与示例
- UserAppService.cs
- Query.cs
- 🧪 Mutation 与校验
- Mutation.cs
- CreateUserInputValidator.cs
- 🚦 性能优化
- DataLoader 与缓存流程图
- 📑 Schema 文档化 & CI 自动化
- 🗂 推荐项目结构
- ❓ FAQ
🧭 背景与目标
REST API 在前端个性化查询、数据聚合场景下常显局限,GraphQL 可以让前端精确声明字段并聚合多个资源,减少冗余通信。本文基于 ABP vNext + EasyAbp.Abp.GraphQL,构建具备权限控制、分页、缓存优化、输入校验和限流能力的生产级 GraphQL 服务。
🛠 安装与依赖
dotnet add package EasyAbp.Abp.GraphQL
dotnet add package GraphQL.Server.Transports.AspNetCore
dotnet add package FluentValidation.AspNetCore
dotnet add package AspNetCoreRateLimit
📦 模块注册与启动
MyProjectHttpApiHostModule.cs
using Volo.Abp.AspNetCore.GraphQL;
using Volo.Abp.Modularity;[DependsOn(typeof(AbpAspNetCoreGraphQLModule),typeof(MyProjectApplicationModule)
)]
public class MyProjectHttpApiHostModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){Configure<AbpGraphQLOptions>(options =>{options.UseGraphiQL = true;options.SchemaName = null; // 简化为 /graphql});context.Services.AddFluentValidationAutoValidation();context.Services.AddValidatorsFromAssemblyContaining<UserDtoValidator>();}public override void OnApplicationInitialization(ApplicationInitializationContext context){var app = context.GetApplicationBuilder();app.UseRouting();app.UseAuthentication();app.UseAuthorization();app.UseEndpoints(endpoints =>{endpoints.MapGraphQL("/graphql");endpoints.MapGraphQLPlayground("/graphql/playground");});}
}
Program.cs 最小化示例
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddApplication<MyProjectHttpApiHostModule>();// GraphQL 注册
builder.Services.AddGraphQLServer().AddQueryType<Query>().AddMutationType<Mutation>().AddType<UserType>().AddDataLoader<UserDataLoader>().ModifyRequestOptions(opt =>{opt.EnableMetrics = false;opt.EnableExceptionDetails = false;opt.EnableIntrospection = false;}).ModifyExecutionOptions(opt => opt.MaxExecutionDepth = 10);// 限流配置
builder.Services.AddOptions();
builder.Services.Configure<IpRateLimitOptions>(builder.Configuration.GetSection("IpRateLimiting")
);
builder.Services.AddInMemoryRateLimiting();
builder.Services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
builder.Services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();var app = builder.Build();
app.InitializeApplication();
app.Run();
🔐 安全性增强
-
禁用 Introspection
.ModifyRequestOptions(opt => opt.EnableIntrospection = false)
-
关闭详细异常
.ModifyRequestOptions(opt => opt.EnableExceptionDetails = false)
-
限流示例 (appsettings.json)
"IpRateLimiting": {"EnableEndpointRateLimiting": true,"GeneralRules": [ { "Endpoint": "*", "Period": "1s", "Limit": 5 } ] }
✍ 构建服务与示例
UserAppService.cs
[Authorize(UserPermissions.Default)]
public class UserAppService : ReadOnlyAppService<User, UserDto, Guid>, IUserAppService
{public UserAppService(IReadOnlyRepository<User, Guid> repository): base(repository) { }
}
Query.cs
public class Query
{public Task<PagedResultDto<UserDto>> GetUsers(int skipCount, int maxResultCount,[Service] IUserAppService appService,CancellationToken cancellationToken){return appService.GetListAsync(new PagedAndSortedResultRequestDto{ SkipCount = skipCount, MaxResultCount = maxResultCount },cancellationToken: cancellationToken);}
}
🧪 Mutation 与校验
Mutation.cs
public class Mutation
{public Task<UserDto> CreateUser(CreateUserInput input,[Service] IUserAppService appService){return appService.CreateAsync(input);}
}
CreateUserInputValidator.cs
public class CreateUserInputValidator : AbstractValidator<CreateUserInput>
{public CreateUserInputValidator(){RuleFor(x => x.UserName).NotEmpty().MaximumLength(32);RuleFor(x => x.Email).NotEmpty().EmailAddress();}
}
🚦 性能优化
DataLoader 与缓存流程图
- BatchDataLoader 批量聚合请求,避免 N+1。
- Redis 缓存:自定义中间层,结合 DataLoader 缓存常用查询。
- CancellationToken:在 DataLoader 和 AppService 中传递,支持中断。
📑 Schema 文档化 & CI 自动化
name: Generate GraphQL SDL
on: [push]
jobs:sdl:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- uses: actions/setup-dotnet@v3with: dotnet-version: '7.0.x'- run: dotnet graphql sdl > schema.graphql- uses: actions/upload-artifact@v3with:name: schema-graphqlpath: schema.graphql
🗂 推荐项目结构
/GraphQL/Queries/Mutations/Subscriptions/Resolvers/Types/Inputs
❓ FAQ
问题 | 解答 |
---|---|
如何添加订阅支持? | 使用 HotChocolate.Subscriptions 或结合 SignalR 实现实时推送 |
如何自定义字段解析器? | 实现 Resolver 类并注册到 DI 容器,无需修改 AppService |
如何导出 SDL 文档? | 使用 dotnet graphql sdl 命令,或在 CI 中自动化生成并上传 artifact |
如何处理授权失败错误? | 在 ModifyRequestOptions 中关闭详细异常,并统一捕获返回 AuthorizationError |