🚀 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-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with: dotnet-version: '7.0.x'
- run: dotnet graphql sdl > schema.graphql
- uses: actions/upload-artifact@v3
with:
name: schema-graphql
path: schema.graphql
🗂 推荐项目结构
/GraphQL
/Queries
/Mutations
/Subscriptions
/Resolvers
/Types
/Inputs
❓ FAQ
问题 | 解答 |
---|---|
如何添加订阅支持? | 使用 HotChocolate.Subscriptions 或结合 SignalR 实现实时推送 |
如何自定义字段解析器? | 实现 Resolver 类并注册到 DI 容器,无需修改 AppService |
如何导出 SDL 文档? | 使用 dotnet graphql sdl 命令,或在 CI 中自动化生成并上传 artifact |
如何处理授权失败错误? | 在 ModifyRequestOptions 中关闭详细异常,并统一捕获返回 AuthorizationError |