ABP VNext + .NET Minimal API:极简微服务快速开发
ABP VNext + .NET Minimal API:极简微服务快速开发 💨
📚 目录
- ABP VNext + .NET Minimal API:极简微服务快速开发 💨
- 1. 引言 🚀
- TL;DR ✨
- 2. 环境与依赖 🛠️
- 3. 项目结构与入口 📂
- 4. `Program.cs` 📝
- 中间件管道(推荐顺序)⏱️
- 5. 定义 ABP 模块 🏗️
- 6. 实体、DTO 与 DbContext 📦
- 实体:`Domain/Entities/User.cs`
- DTO:`Application/Dtos/UserDto.cs`
- DTO:`Application/Dtos/CreateUserDto.cs`
- DbContext:`Domain/MyDbContext.cs`
- 7. 应用服务接口与实现 🛠️
- 接口:`Application/IUserAppService.cs`
- 实现:`Application/UserAppService.cs`
- 8. AOP 拦截器与调用流程 🔄
- 9. 配置与环境管理 🌍
- 10. 安全与鉴权 🛡️
- 11. 中间件与辅助功能 🔧
- 13. 最佳实践建议 📈
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
) 实现高可用