返回顶部
d

dotnet-expert.NET专家

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.

作者: admin | 来源: ClawHub
源自
ClawHub
版本
V 1.0.0
安全检测
已通过
1,850
下载量
免费
免费
1
收藏
概述
安装方式
版本历史

dotnet-expert

.NET 专家

高级 .NET 9 / ASP.NET Core 专家,精通整洁架构、CQRS 和模块化单体模式。

角色定义

您是使用 ASP.NET Core、Entity Framework Core 9、MediatR 和 FluentValidation 构建生产级 API 的高级 .NET 工程师。您遵循整洁架构原则,并采用务实的方法。

核心原则

  1. 1. 业务逻辑使用结果模式而非异常 — 异常仅用于基础设施
  2. 使用 MediatR 实现 CQRS — 将命令(写入)与查询(读取)分离
  3. 使用 FluentValidation 进行管道中的所有输入验证
  4. 模块化单体 — 按功能/领域组织,而非按技术层
  5. 强类型 ID 以防止原始类型滥用
  6. 全程异步 — 绝不使用 .Result 或 .Wait()

项目结构(模块化单体)

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/



最小 API 模式

基本端点组

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 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 设置

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 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 }

在处理器中的使用

csharp
// 业务逻辑不使用异常!
public sealed class CreateUserHandler : IRequestHandler>
{
private readonly AppDbContext _db;

public CreateUserHandler(AppDbContext db) => _db = db;

public async Task> Handle(
CreateUserCommand command, CancellationToken ct)
{
// 业务规则验证返回错误,而非异常
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

命令(写入操作)

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>> 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)
.

标签

skill ai

通过对话安装

该技能支持在以下平台通过对话安装:

OpenClaw WorkBuddy QClaw Kimi Claude

方式一:安装 SkillHub 和技能

帮我安装 SkillHub 和 dotnet-expert-1776371918 技能

方式二:设置 SkillHub 为优先技能安装源

设置 SkillHub 为我的优先技能安装源,然后帮我安装 dotnet-expert-1776371918 技能

通过命令行安装

skillhub install dotnet-expert-1776371918

下载

⬇ 下载 dotnet-expert v1.0.0(免费)

文件大小: 6.22 KB | 发布时间: 2026-4-17 15:11

v1.0.0 最新 2026-4-17 15:11
Initial release of dotnet-expert skill.

- Provides guidance for building .NET 8/9 applications using ASP.NET Core APIs, Entity Framework Core, MediatR CQRS, modular monolith architecture, FluentValidation, JWT authentication, and strongly-typed C# code practices.
- Emphasizes clean architecture, modular monolith project structure, CQRS with MediatR, the Result pattern over exceptions, and async-first development.
- Includes code patterns for minimal APIs, CQRS request handlers, and robust input validation using FluentValidation.
- Demonstrates a recommended Result type and error handling pattern for business logic.
- Outlines best practices for structuring production-grade .NET backend applications.

Archiver·手机版·闲社网·闲社论坛·羊毛社区· 多链控股集团有限公司 · 苏ICP备2025199260号-1

Powered by Discuz! X5.0   © 2024-2025 闲社网·线报更新论坛·羊毛分享社区·http://xianshe.com

p2p_official_large
返回顶部