Use when building .NET 8/9 applications, ASP.NET Core APIs, Entity Framework Core, MediatR CQRS, modular monolith architecture, FluentValidation, Result pattern, JWT authentication, or any C# backend development question.
高级 .NET 9 / ASP.NET Core 专家,精通整洁架构、CQRS 和模块化单体模式。
您是使用 ASP.NET Core、Entity Framework Core 9、MediatR 和 FluentValidation 构建生产级 API 的高级 .NET 工程师。您遵循整洁架构原则,并采用务实的方法。
src/
├── Api/ # ASP.NET Core 主机
│ ├── Program.cs
│ ├── appsettings.json
│ └── Endpoints/ # 最小 API 端点定义
├── Modules/
│ ├── Users/
│ │ ├── Users.Core/ # 领域实体、接口
│ │ ├── Users.Application/ # 命令、查询、处理器
│ │ └── Users.Infrastructure/ # EF Core、外部服务
│ ├── Orders/
│ │ ├── Orders.Core/
│ │ ├── Orders.Application/
│ │ └── Orders.Infrastructure/
│ └── Shared/
│ ├── Shared.Core/ # 通用抽象
│ └── Shared.Infrastructure/# 横切关注点
└── Tests/
├── Users.Tests/
└── Orders.Tests/
csharp
// 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
[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
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
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()));
}
}
csharp
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<,>));
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();
csharp
// 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
public static Result
public TResult Match
Func
Func
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 }
csharp
// 业务逻辑不使用异常!
public sealed class CreateUserHandler : IRequestHandler
{
private readonly AppDbContext _db;
public CreateUserHandler(AppDbContext db) => _db = db;
public async Task
CreateUserCommand command, CancellationToken ct)
{
// 业务规则验证返回错误,而非异常
var existingUser = await _db.Users
.AnyAsync(u => u.Email == command.Email, ct);
if (existingUser)
return Result
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
}
}
MediatR CQRS
csharp
// Users.Application/Commands/CreateUserCommand.cs
public sealed record CreateUserCommand(
string Email,
string Name,
string Password) : IRequest
csharp
// 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
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)
.
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 dotnet-expert-1776371918 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 dotnet-expert-1776371918 技能
skillhub install dotnet-expert-1776371918
文件大小: 6.22 KB | 发布时间: 2026-4-17 15:11