ABP VNext + .NET Minimal API:极简微服务快速开发 💨
📚 目录
1. 引言 🚀
TL;DR ✨
- 🔥 极简上手:用 .NET Minimal API + ABP VNext,仅需一个
Program.cs
即可启动轻量级微服务 - 🛡️ 保留核心能力:依然拥有 ABP 的依赖注入(DI)、AOP 拦截器、配置管理、审计日志等特性
- 🎉 即开即用:ProblemDetails 异常格式、Swagger/OpenAPI、多版本 API 文档、API 版本管理、健康检查、CORS、多语言本地化一键配置
- ⚡ 高性能、高可用:Serilog 日志 + Kestrel 原生优化 + Docker Compose,启动秒级响应
2. 环境与依赖 🛠️
.NET SDK:6 +
ABP VNext:6.x +
数据库:PostgreSQL(生产)、In-Memory(测试)
关键 NuGet 包:
dotnet add package Volo.Abp.AspNetCore.Builder dotnet add package Volo.Abp.Modularity dotnet add package Volo.Abp.EntityFrameworkCore.PostgreSql dotnet add package Volo.Abp.AutoMapper dotnet add package Volo.Abp.AspNetCore.Serilog # Serilog 丰富器 dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package Swashbuckle.AspNetCore dotnet add package Asp.Versioning.Http dotnet add package Asp.Versioning.Mvc.ApiExplorer # 版本化 ApiExplorer dotnet add package Hellang.Middleware.ProblemDetails # ProblemDetails 中间件 dotnet add package Serilog dotnet add package Serilog.Sinks.Console # Serilog 控制台 Sink dotnet add package StackExchange.Redis
3. 项目结构与入口 📂
MyMinimalService/
├─ Program.cs
├─ Modules/
│ └─ MyServiceModule.cs
├─ Application/
│ ├─ Dtos/
│ │ ├─ UserDto.cs
│ │ └─ CreateUserDto.cs
│ └─ IUserAppService.cs
├─ Domain/
│ ├─ Entities/
│ │ └─ User.cs
│ └─ MyDbContext.cs
└─ appsettings.json
4. Program.cs
📝
using System.Text.Json;
using System.Text.Json.Serialization;
using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Serilog;
using Volo.Abp;
using Volo.Abp.Autofac;
using Volo.Abp.AspNetCore.Builder; // 确保 AddApplication 扩展可用
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.EventBus; // 确保 AddAbpEventBus 扩展可用
using Volo.Abp.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// 1. Serilog 全局配置 🔥
builder.Host.UseSerilog((ctx, lc) =>
{
lc.ReadFrom.Configuration(ctx.Configuration)
.Enrich.FromLogContext()
.Enrich.WithProperty("Application", ctx.HostingEnvironment.ApplicationName)
.WriteTo.Console();
});
// 2. 使用 Autofac 容器,确保 ABP AOP 拦截器生效 🛡️
builder.Host.UseAutofac();
// 3. 注册 ABP 模块化支持(包含 ASP.NET Core 特性)📦
builder.Services.AddApplication<MyServiceModule>();
// 4. 本地化:资源文件路径 🌐
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
// 5. ProblemDetails 异常格式化 ⚠️
builder.Services.AddProblemDetails(opts =>
{
opts.MapToStatusCode<Exception>(StatusCodes.Status500InternalServerError);
});
// 6. 身份验证与授权 🔒
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.Authority = builder.Configuration["Auth:Issuer"];
options.Audience = builder.Configuration["Auth:Audience"];
});
builder.Services.AddAuthorization();
// 7. 启用 ABP 事件总线(自动注册 AOP 拦截器)🔄
builder.Services.AddAbpEventBus();
// 8. JSON 序列化优化 📲
builder.Services.Configure<JsonOptions>(opts =>
{
opts.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
opts.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
// 9. API 版本化 📑
builder.Services.AddApiVersioning(opts =>
{
opts.AssumeDefaultVersionWhenUnspecified = true;
opts.DefaultApiVersion = new ApiVersion(1, 0);
opts.ReportApiVersions = true;
opts.ApiVersionReader = new UrlSegmentApiVersionReader();
});
builder.Services.AddVersionedApiExplorer(opts =>
{
opts.GroupNameFormat = "'v'VVV";
opts.SubstituteApiVersionInUrl = true;
});
// 10. Swagger/OpenAPI 🛠️
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(opts =>
{
// 在此阶段 BuildServiceProvider 有轻微容器重复,但示例中可用
var provider = builder.Services.BuildServiceProvider()
.GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var desc in provider.ApiVersionDescriptions)
{
opts.SwaggerDoc(desc.GroupName, new OpenApiInfo {
Title = "MyMinimalService",
Version = desc.ApiVersion.ToString()
});
}
});
// 11. 健康检查 + Redis 缓存 ❤️
builder.Services.AddHealthChecks()
.AddDbContextCheck<MyDbContext>("db")
.AddRedis(builder.Configuration["Redis:ConnectionString"], name: "redis");
builder.Services.AddStackExchangeRedisCache(opts =>
{
opts.Configuration = builder.Configuration["Redis:ConnectionString"];
});
// 12. CORS 🌐
builder.Services.AddCors(opts =>
{
opts.AddDefaultPolicy(p =>
p.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
});
var app = builder.Build();
// 13. 初始化 ABP 应用 🔧
app.InitializeApplication();
中间件管道(推荐顺序)⏱️
app.UseProblemDetails(); // RFC7807 异常格式
app.UseAbpExceptionHandling(); // ABP 全局异常处理
app.UseAbpRequestLocalization(); // 本地化
app.UseCors(); // 跨域
app.UseSerilogRequestLogging(); // Serilog 请求日志
app.UseAuthentication(); // 验证
app.UseAuthorization(); // 授权
app.UseAbpSerilogEnrichers(); // ABP Serilog 丰富器
app.UseSwagger();
app.UseSwaggerUI(c =>
{
var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var desc in provider.ApiVersionDescriptions)
{
c.SwaggerEndpoint($"/swagger/{desc.GroupName}/swagger.json", desc.GroupName);
}
});
app.UseHealthChecks("/health");
// 极简路由定义 📍
app.MapGroup("/api/v{version:apiVersion}/users")
.MapGet("/{id}", (Guid id, IUserAppService svc) => svc.GetAsync(id))
.MapGet("/", (IUserAppService svc) => svc.GetListAsync())
.MapPost("/", (CreateUserDto dto, IUserAppService svc) => svc.CreateAsync(dto))
.RequireAuthorization();
app.Run();
5. 定义 ABP 模块 🏗️
using Volo.Abp;
using Volo.Abp.Autofac;
using Volo.Abp.AspNetCore.Builder;
using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
namespace MyMinimalService.Modules
{
[DependsOn(
typeof(AbpAspNetCoreModule), // ASP.NET Core 特性支持
typeof(AbpAutofacModule),
typeof(AbpEntityFrameworkCoreModule),
typeof(AbpAspNetCoreSerilogModule) // Serilog 丰富器模块
)]
public class MyServiceModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbContextOptions>(opts => opts.UseNpgsql());
context.Services.AddAbpDbContext<MyDbContext>(opts =>
{
opts.AddDefaultRepositories(true);
});
context.Services.AddAutoMapperObjectMapper<MyServiceModule>();
Configure<AbpAutoMapperOptions>(opt => opt.AddMaps<MyServiceModule>());
}
}
}
6. 实体、DTO 与 DbContext 📦
实体:Domain/Entities/User.cs
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace MyMinimalService.Domain.Entities
{
/// <summary>
/// 用户实体,继承了审计字段(CreationTime、CreatorId、LastModificationTime 等)
/// </summary>
public class User : AuditedAggregateRoot<Guid>
{
/// <summary>
/// 用户名
/// </summary>
public string Name { get; set; }
protected User() { }
public User(Guid id, string name)
: base(id)
{
Name = name;
}
}
}
DTO:Application/Dtos/UserDto.cs
using System;
namespace MyMinimalService.Application.Dtos
{
/// <summary>
/// 用户数据传输对象
/// </summary>
public class UserDto
{
public Guid Id { get; set; }
public string Name { get; set; }
}
}
DTO:Application/Dtos/CreateUserDto.cs
using System.ComponentModel.DataAnnotations;
namespace MyMinimalService.Application.Dtos
{
/// <summary>
/// 创建用户时的输入 DTO
/// </summary>
public class CreateUserDto
{
[Required]
[StringLength(128, MinimumLength = 1)]
public string Name { get; set; }
}
}
DbContext:Domain/MyDbContext.cs
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using MyMinimalService.Domain.Entities;
namespace MyMinimalService.Domain
{
/// <summary>
/// 应用的 EF Core 上下文,配置了 User 实体和默认仓储
/// </summary>
public class MyDbContext : AbpDbContext<MyDbContext>
{
public DbSet<User> Users { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<User>(b =>
{
b.ToTable("AppUsers"); // 自定义表名
b.HasKey(x => x.Id);
b.Property(x => x.Name)
.IsRequired()
.HasMaxLength(128);
});
}
}
}
7. 应用服务接口与实现 🛠️
接口:Application/IUserAppService.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using MyMinimalService.Application.Dtos;
namespace MyMinimalService.Application
{
/// <summary>
/// 定义用户相关的应用服务接口
/// </summary>
public interface IUserAppService : IApplicationService
{
/// <summary>
/// 获取指定 Id 的用户
/// </summary>
Task<UserDto> GetAsync(Guid id);
/// <summary>
/// 获取所有用户列表
/// </summary>
Task<List<UserDto>> GetListAsync();
/// <summary>
/// 创建一个新用户
/// </summary>
Task<UserDto> CreateAsync(CreateUserDto input);
}
}
实现:Application/UserAppService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using MyMinimalService.Application.Dtos;
using MyMinimalService.Domain.Entities;
namespace MyMinimalService.Application
{
/// <summary>
/// 用户应用服务实现,包含基本的增删改查
/// </summary>
public class UserAppService : ApplicationService, IUserAppService
{
private readonly IRepository<User, Guid> _repository;
public UserAppService(IRepository<User, Guid> repository)
{
_repository = repository;
}
/// <summary>
/// 根据 Id 获取一个用户,需认证
/// </summary>
[Authorize]
public async Task<UserDto> GetAsync(Guid id)
{
var entity = await _repository.GetAsync(id);
return ObjectMapper.Map<User, UserDto>(entity);
}
/// <summary>
/// 获取所有用户列表
/// </summary>
public async Task<List<UserDto>> GetListAsync()
{
var entities = await _repository.GetListAsync();
return entities
.Select(u => ObjectMapper.Map<User, UserDto>(u))
.ToList();
}
/// <summary>
/// 创建新用户
/// </summary>
public async Task<UserDto> CreateAsync(CreateUserDto input)
{
var user = new User(GuidGenerator.Create(), input.Name);
var created = await _repository.InsertAsync(user);
return ObjectMapper.Map<User, UserDto>(created);
}
}
}
8. AOP 拦截器与调用流程 🔄
9. 配置与环境管理 🌍
加载顺序:
appsettings.json
→appsettings.{环境}.json
→ 环境变量示例
appsettings.json
:{ "ConnectionStrings": { "Default": "Host=localhost;Database=mydb;Username=user;Password=pass" }, "Redis": { "ConnectionString": "localhost:6379" }, "Auth": { "Issuer": "https://auth.example.com", "Audience": "MyMinimalService" } }
支持 Kubernetes Secret、Vault 等插件扩展
10. 安全与鉴权 🛡️
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = cfg["Auth:Issuer"];
options.Audience = cfg["Auth:Audience"];
});
app.UseAuthentication();
app.UseAuthorization();
- 用
.RequireAuthorization()
或[Authorize]
保护端点 - 支持 ABP 的 Policy 与 PermissionChecker
11. 中间件与辅助功能 🔧
- ProblemDetails:统一异常格式
- AbpExceptionHandling:ABP 全局异常处理
- Localization:多语言支持
- Serilog:日志丰富器 + 请求日志
- Swagger/OpenAPI:多版本文档
- HealthChecks:健康探针
- CORS:跨域配置
13. 最佳实践建议 📈
DI 生命周期:
DbContext
保持默认Scoped
Kestrel 调优:
"Kestrel": { "Limits": { "MaxConcurrentConnections": 1000 } }
分布式缓存:Redis (
AddStackExchangeRedisCache
) 实现高可用