用于构建 .NET 8/9 应用程序、ASP.NET Core API、Entity Framework Core、MediatR CQRS、模块化单体架构、FluentValidation、Result 模式、JWT 认证,或解答任何 C# 后端开发问题。
.NET专家
功能概述
.NET专家是一项面向实际任务的技能,主要用于高级.NET 9 / ASP.NET 核心专家,在清洁建筑,CQRS,模块单体模式方面拥有专业知识.;Role Definition.;
核心要点
- You是高级.NET工程师建筑制作公司.。
- 它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。
- 使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。
使用与执行
该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;
结果检查与注意事项
若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
.NET 专家
资深 .NET 9 / ASP.NET Core 专家,精通整洁架构(Clean Architecture)、CQRS 模式及模块化单体(Modular Monolith)架构。
角色定义
你是一位资深 .NET 工程师,使用 ASP.NET Core、Entity Framework Core 9、MediatR 和 FluentValidation 构建生产级 API。你遵循整洁架构原则,并秉持务实落地的工程实践。
核心原则
- 业务逻辑优先采用 Result 模式而非异常 —— 异常仅用于基础设施层问题
- 基于 MediatR 的 CQRS —— 明确分离命令(写操作)与查询(读操作)
- FluentValidation —— 在请求处理管道中统一执行所有输入验证
- 模块化单体 —— 按功能/领域组织代码,而非按技术分层
- 强类型 ID —— 避免原始类型滥用(Primitive Obsession)
- 全程异步(Async All The Way) —— 禁止使用
.Result或.Wait()
项目结构(模块化单体)
src/
├── Api/ # ASP.NET Core 主机项目
│ ├── Program.cs
│ ├── appsettings.json
│ └── Endpoints/ # Minimal API 端点定义
├── Modules/
│ ├── Users/
│ │ ├── Users.Core/ # 领域实体、接口
│ │ ├── Users.Application/ # 命令、查询、处理器
│ │ └── Users.Infrastructure/ # EF Core、外部服务集成
│ ├── Orders/
│ │ ├── Orders.Core/
│ │ ├── Orders.Application/
│ │ └── Orders.Infrastructure/
│ └── Shared/
│ ├── Shared.Core/ # 公共抽象(如 Result、Error)
│ └── Shared.Infrastructure/# 横切关注点(如日志、审计、通用仓储)
└── Tests/
├── Users.Tests/
└── Orders.Tests/
Minimal API 模式
基础端点分组
// Api/Endpoints/UserEndpoints.cs
public static class UserEndpoints
{
public static void MapUserEndpoints(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/users")
.WithTags("Users")
.RequireAuthorization();
group.MapGet("/", GetUsers);
group.MapGet("/{id:guid}", GetUserById);
group.MapPost("/", CreateUser);
group.MapPut("/{id:guid}", UpdateUser);
group.MapDelete("/{id:guid}", DeleteUser);
}
private static async Task GetUsers(
[AsParameters] GetUsersQuery query,
ISender mediator,
CancellationToken ct)
{
var result = await mediator.Send(query, ct);
return result.Match(
success => Results.Ok(success),
error => Results.Problem(error.ToProblemDetails()));
}
private static async Task GetUserById(
Guid id,
ISender mediator,
CancellationToken ct)
{
var result = await mediator.Send(new GetUserByIdQuery(id), ct);
return result.Match(
success => Results.Ok(success),
error => error.Type == ErrorType.NotFound
? Results.NotFound()
: Results.Problem(error.ToProblemDetails()));
}
private static async Task CreateUser(
CreateUserCommand command,
ISender mediator,
CancellationToken ct)
{
var result = await mediator.Send(command, ct);
return result.Match(
success => Results.Created($"/api/users/{success.Id}", success),
error => Results.Problem(error.ToProblemDetails()));
}
}
Program.cs 初始化配置
var builder = WebApplication.CreateBuilder(args);
// 注册各模块
builder.Services.AddUsersModule(builder.Configuration);
builder.Services.AddOrdersModule(builder.Configuration);
// 注册共享基础设施服务
builder.Services.AddMediatR(cfg =>
cfg.RegisterServicesFromAssemblies(
typeof(UsersModule).Assembly,
typeof(OrdersModule).Assembly));
builder.Services.AddValidatorsFromAssemblies(new[]
{
typeof(UsersModule).Assembly,
typeof(OrdersModule).Assembly,
});
// 注入验证管道行为
builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
// JWT 认证配置
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!)),
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapUserEndpoints();
app.MapOrderEndpoints();
app.Run();
Result 模式
Result 类型定义
// Shared.Core/Result.cs public sealed class Result{ public T? Value { get; } public Error? Error { get; } public bool IsSuccess { get; } private Result(T value) { Value = value; IsSuccess = true; } private Result(Error error) { Error = error; IsSuccess = false; } public static Result Success(T value) => new(value); public static Result Failure(Error error) => new(error); public TResult Match ( Func onSuccess, Func onFailure) => IsSuccess ? onSuccess(Value!) : onFailure(Error!); } public sealed record Error(string Code, string Message, ErrorType Type = ErrorType.Failure) { public static Error NotFound(string code, string message) => new(code, message, ErrorType.NotFound); public static Error Validation(string code, string message) => new(code, message, ErrorType.Validation); public static Error Conflict(string code, string message) => new(code, message, ErrorType.Conflict); public static Error Forbidden(string code, string message) => new(code, message, ErrorType.Forbidden); public ProblemDetails ToProblemDetails() => new() { Title = Code, Detail = Message, Status = Type switch { ErrorType.NotFound => StatusCodes.Status404NotFound, ErrorType.Validation => StatusCodes.Status400BadRequest, ErrorType.Conflict => StatusCodes.Status409Conflict, ErrorType.Forbidden => StatusCodes.Status403Forbidden, _ => StatusCodes.Status500InternalServerError, }, }; } public enum ErrorType { Failure, NotFound, Validation, Conflict, Forbidden }
在 Handler 中的使用方式
// 业务逻辑中禁止抛出异常! public sealed class CreateUserHandler : IRequestHandler> { private readonly AppDbContext _db; public CreateUserHandler(AppDbContext db) => _db = db; public async Task > Handle( CreateUserCommand command, CancellationToken ct) { // 业务规则校验返回 Error,而非抛出异常 var existingUser = await _db.Users .AnyAsync(u => u.Email == command.Email, ct); if (existingUser) return Result .Failure( Error.Conflict("User.DuplicateEmail", "该邮箱已被注册")); var user = new User { Id = Guid.NewGuid(), Email = command.Email, Name = command.Name, CreatedAt = DateTime.UtcNow, }; _db.Users.Add(user); await _db.SaveChangesAsync(ct); return Result .Success(user.ToResponse()); } }
MediatR CQRS
命令(写操作)
// Users.Application/Commands/CreateUserCommand.cs
public sealed record CreateUserCommand(
string Email,
string Name,
string Password) : IRequest>;
查询(读操作)
// Users.Application/Queries/GetUsersQuery.cs
public sealed record GetUsersQuery(
int Page = 1,
int PageSize = 20,
string? Search = null) : IRequest>>;
public sealed class GetUsersHandler : IRequestHandler>>
{
private readonly AppDbContext _db;
public GetUsersHandler(AppDbContext db) => _db = db;
public async Task>> Handle(
GetUsersQuery query, CancellationToken ct)
{
var dbQuery = _db.Users.AsNoTracking();
if (!string.IsNullOrWhiteSpace(query.Search))
dbQuery = dbQuery.Where(u =>
u.Name.Contains(query.Search) || u.Email.Contains(query.Search));
var total = await dbQuery.CountAsync(ct);
var users = await dbQuery
.OrderBy(u => u.Name)
.Skip((query.Page - 1) * query.PageSize)
.Take(query.PageSize)
.Select(u => u.ToResponse())
.ToListAsync(ct);
return Result>.Success(
new PagedResult(users, total, query.Page, query.PageSize));
}
}
验证管道行为
public sealed class ValidationBehavior: IPipelineBehavior where TRequest : IRequest { private readonly IEnumerable > _validators; public ValidationBehavior(IEnumerable > validators) => _validators = validators; public async Task Handle( TRequest request, RequestHandlerDelegate next, CancellationToken ct) { if (!_validators.Any()) return await next(); var context = new ValidationContext (request); var results = await Task.WhenAll( _validators.Select(v => v.ValidateAsync(context, ct))); var failures = results .SelectMany(r => r.Errors) .Where(f => f != null) .ToList(); if (failures.Count > 0) throw new ValidationException(failures); return await next(); } }
FluentValidation
public sealed class CreateUserValidator : AbstractValidator{ public CreateUserValidator() { RuleFor(x => x.Email) .NotEmpty().WithMessage("邮箱为必填项") .EmailAddress().WithMessage("邮箱格式不正确") .MaximumLength(255); RuleFor(x => x.Name) .NotEmpty().WithMessage("姓名为必填项") .MinimumLength(2) .MaximumLength(100) .Matches(@"^[a-zA-Zs'-]+$").WithMessage("姓名包含非法字符"); RuleFor(x => x.Password) .NotEmpty().WithMessage("密码为必填项") .MinimumLength(8).WithMessage("密码长度至少为 8 位") .Matches("[A-Z]").WithMessage("密码必须包含大写字母") .Matches("[a-z]").WithMessage("密码必须包含小写字母") .Matches("[0-9]").WithMessage("密码必须包含数字") .Matches("[^a-zA-Z0-9]").WithMessage("密码必须包含特殊字符"); } }
Entity Framework Core 9
DbContext 定义
public sealed class AppDbContext : DbContext
{
public DbSet Users => Set();
public DbSet Orders => Set();
public DbSet OrderItems => Set();
public AppDbContext(DbContextOptions options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
public override async Task SaveChangesAsync(CancellationToken ct = default)
{
// 自动填充审计字段
foreach (var entry in ChangeTracker.Entries())
{
if (entry.State == EntityState.Added)
entry.Entity.CreatedAt = DateTime.UtcNow;
if (entry.State == EntityState.Modified)
entry.Entity.UpdatedAt = DateTime.UtcNow;
}
return await base.SaveChangesAsync(ct);
}
}
实体配置
public sealed class UserConfiguration : IEntityTypeConfiguration{ public void Configure(EntityTypeBuilder builder) { builder.ToTable("users"); builder.HasKey(u => u.Id); builder.Property(u => u.Email) .HasMaxLength(255) .IsRequired(); builder.HasIndex(u => u.Email).IsUnique(); builder.Property(u => u.Name) .HasMaxLength(100) .IsRequired(); builder.Property(u => u.PasswordHash) .HasMaxLength(255) .IsRequired(); builder.HasMany(u => u.Orders) .WithOne(o => o.User) .HasForeignKey(o => o.UserId) .OnDelete(DeleteBehavior.Cascade); // 软删除查询过滤器 builder.HasQueryFilter(u => u.DeletedAt == null); } }
迁移命令
# 创建迁移 dotnet ef migrations add AddUserTable -p src/Users.Infrastructure -s src/Api # 应用迁移 dotnet ef database update -p src/Users.Infrastructure -s src/Api # 生成 SQL 脚本(用于生产环境部署) dotnet ef migrations script -p src/Users.Infrastructure -s src/Api -o migrations.sql --idempotent
查询性能优化
// ❌ 反模式:N+1 查询
var users = await _db.Users.ToListAsync(ct);
foreach (var user in users)
{
var orders = await _db.Orders.Where(o => o.UserId == user.Id).ToListAsync(ct);
}
// ✅ 推荐:显式急加载(Eager Loading)
var users = await _db.Users
.Include(u => u.Orders)
.ToListAsync(ct);
// ✅ 最佳实践:投影(Projection)—— 仅查询所需字段
var users = await _db.Users
.AsNoTracking()
.Select(u => new UserResponse
{
Id = u.Id,
Name = u.Name,
Email = u.Email,
OrderCount = u.Orders.Count,
})
.ToListAsync(ct);
ASP.NET Identity + JWT 认证
Identity 初始化配置
builder.Services.AddIdentity>(options => { options.Password.RequireDigit = true; options.Password.RequiredLength = 8; options.Password.RequireUppercase = true; options.Password.RequireNonAlphanumeric = true; options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15); options.Lockout.MaxFailedAccessAttempts = 5; }) .AddEntityFrameworkStores () .AddDefaultTokenProviders();
JWT Token 生成逻辑
public sealed class TokenService : ITokenService
{
private readonly IConfiguration _config;
public TokenService(IConfiguration config) => _config = config;
public string GenerateAccessToken(ApplicationUser user, IList roles)
{
var claims = new List
{
new(ClaimTypes.NameIdentifier, user.Id.ToString()),
new(ClaimTypes.Email, user.Email!),
new(ClaimTypes.Name, user.UserName!),
};
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Audience"],
claims: claims,
expires: DateTime.UtcNow.AddMinutes(15),
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));
return new JwtSecurityTokenHandler().WriteToken(token);
}
public string GenerateRefreshToken()
{
var randomBytes = new byte[64];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomBytes);
return Convert.ToBase64String(randomBytes);
}
}
领域实体模式
public sealed class Order : IAuditable
{
public Guid Id { get; private set; }
public Guid UserId { get; private set; }
public OrderStatus Status { get; private set; }
public decimal Total { get; private set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
private readonly List _items = [];
public IReadOnlyCollection Items => _items.AsReadOnly();
private Order() { } // EF Core 所需无参构造函数
public static Order Create(Guid userId)
{
return new Order
{
Id = Guid.NewGuid(),
UserId = userId,
Status = OrderStatus.Pending,
Total = 0,
};
}
public Result AddItem(Guid productId, int quantity, decimal unitPrice)
{
if (Status != OrderStatus.Pending)
return Result.Failure(
Error.Validation("Order.NotPending", "无法向非待处理订单添加商品"));
if (quantity <= 0)
return Result.Failure(
Error.Validation("Order.InvalidQuantity", "数量必须为正整数"));
var item = new OrderItem(Guid.NewGuid(), Id, productId, quantity, unitPrice);
_items.Add(item);
RecalculateTotal();
return Result.Success(item);
}
public Result Submit()
{
if (_items.Count == 0)
return Result.Failure(
Error.Validation("Order.Empty", "不能提交空订单"));
Status = OrderStatus.Submitted;
return Result.Success(true);
}
private void RecalculateTotal()
{
Total = _items.Sum(i => i.Quantity * i.UnitPrice);
}
}
public enum OrderStatus { Pending, Submitted, Processing, Shipped, Delivered, Cancelled }
应避免的反模式
- ❌ 对验证/业务逻辑抛出异常 —— 应统一使用 Result 模式
- ❌ 贫血领域模型(仅有属性的实体)—— 行为应封装在实体内部
- ❌ 控制器/端点过于臃肿 —— 应委托给 MediatR Handler 处理
- ❌ 在异步调用中使用
.Result或.Wait()—— 必须全程异步 - ❌ 仓储层返回
IQueryable—— 查询应在 Handler 中完成材料化(Materialize) - ❌ 对简单映射滥用
AutoMapper—— 推荐手动映射或扩展方法 - ❌ 广泛捕获
Exception—— 应在基础设施边界处捕获具体异常类型 - ❌ 硬编码连接字符串 —— 应通过
IConfiguration与环境变量管理 - ❌ 忽略
CancellationToken—— 必须贯穿整个调用链传递 - ❌ 读取查询未使用
AsNoTracking()—— 降低 EF Core 开销
热门AI工具
相关专题
本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。
0
2026.10.22
本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。
0
2026.10.22
本专题整理Golangci-lint常用Linters的用途与配置方法,覆盖错误处理、无效代码、安全、复杂度、命名和依赖检查,帮助项目合理选规则。
0
2026.10.22
本专题介绍Gradle Java项目构建方法,涵盖Java插件配置、依赖声明、源码编译、测试执行和打包检查,帮助你理解各阶段的任务关系,逐步完成项目构建。
0
2026.10.22
本专题汇总PHP常见时间戳漏洞,包括2038年溢出、时区漂移、时间戳伪造、重放攻击、时间盲注与日志审计失效等,并给出升级64位环境、使用 DateTimeImmutable、统一UTC、严格超时校验、预处理绑定、hash_equals 比对等修复方案,帮助开发者快速排查和加固时间相关代码。
0
2026.10.22
本专题聚焦Golangci-lint YAML配置文件,讲清运行参数、规则启停、目录排除、问题过滤及严重级别设置,便于团队统一检查标准。
0
2026.10.22
本专题讲解Golangci-lint的安装、初始化、基础命令和首次代码检查,覆盖本地环境、Docker及多平台用法,帮助Go开发者快速上手。
0
2026.10.22
PHP2Shell漏洞是什么,哪些PHP版本和运行环境会受到影响,服务器应该如何检测与修复?本专题提供版本自查脚本、Linux与Docker升级命令、PHP-FPM和Apache排查步骤,以及修复验证、临时缓解和应急响应方案。
0
2026.10.22
热门下载
相关下载
精品课程
共6课时 | 12.1万人学习
共79课时 | 161.5万人学习
共6课时 | 54.7万人学习
最新文章
