mcpField
A
aspnet

aspnet

github.com/youlaitechDevelopment6258 installsUpdated 5d ago
Repository

About aspnet

A set of conventions and examples for ASP.NET Core backend development, aimed at teams building REST APIs, using EF Core, and implementing authentication and authorization. It covers architecture, naming, response handling, and code-quality checks.

Key features

  1. 01Define a .NET 8+ and ASP.NET Core stack
  2. 02Specify layers, naming, and DTO suffixes
  3. 03Standardize RESTful CRUD routes and async methods
  4. 04Use a unified response format and handle business exceptions
  5. 05Describe JWT authentication and Policy-based authorization
  6. 06List code-quality checks and common anti-patterns

Use cases

  1. 01Set up project folders and layers for ASP.NET Core
  2. 02Design consistent REST API routes and responses
  3. 03Implement JWT authentication and permission policies
  4. 04Review backend conventions and exception handling

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/youlaitech/youlai-skills --skill aspnet

After installing, type/aspnetin Claude Code to confirm it loaded.

Details

From the project README

ASP.NET Core 后端开发规范

触发条件

  • Develop ASP.NET Core projects
  • Implement REST APIs
  • Use Entity Framework Core for data access
  • Implement JWT authentication
  • Implement permission control

Part 1: 技术栈

层选型说明
运行环境.NET 8+跨平台运行时
Web 框架ASP.NET Core内置依赖注入、中间件管道
ORMEntity Framework CoreLINQ 查询、Code First、迁移
数据库MySQL 8.xInnoDB 引擎
缓存Redis 7.x分布式缓存
认证JWT (Microsoft.AspNetCore.Authentication.JwtBearer)Token 认证
API 文档SwashbuckleOpenAPI 生成

Part 2: 目录结构

src/
├── Youlai.Api/                     # API 层(Controller + 中间件)
│   ├── Program.cs                  # 启动配置
│   ├── Controllers/                # 按模块分目录,复数命名
│   │   ├── Auth/{AuthController, WxMaAuthController}
│   │   ├── System/{UsersController, RolesController, MenusController, ...}
│   │   ├── Codegen/{CodegenController}
│   │   ├── File/{FilesController}
│   │   └── Message/{SseController}
│   ├── Filters/                    # LogActionFilter
│   ├── Middlewares/                # ExceptionHandlingMiddleware, RateLimitMiddleware
│   ├── Security/                   # CurrentUser, HasPermAttribute, JwtExtensions, PermissionAuthorizationHandler
│   └── Swagger/                    # FileUploadOperationFilter
│
├── Youlai.Application/            # 应用层(Service + DTO)
│   ├── DependencyInjection.cs
│   ├── Auth/                       # IAuthService, AuthService, WxMaAuthService + Models/
│   ├── Common/                     # ILoggingService, SseService
│   ├── Constants/                  # RedisKeyConstants
│   ├── Exceptions/                 # BusinessException
│   ├── Options/                    # SecurityOptions, RedisOptions, WxMaOptions
│   ├── Results/                    # Result, PageResult, ResultCode
│   ├── Security/                   # ICurrentUser, JwtTokenManager, DataPermissionService + Models/
│   └── System/                     # IUserService, UserService 等 + Models/{User,Role,Menu,Dept,...}/
│
├── Youlai.Domain/                  # 领域层(最薄,无依赖)
│   ├── Entities/                   # SysUser, SysRole, SysMenu 等
│   └── Enums/                      # ActionType, LogModule, MenuType
│
├── Youlai.Infrastructure/          # 基础设施层
│   ├── DependencyInjection.cs
│   ├── Persistence/AppDbContext.cs
│   ├── FileStorage/                # LocalFileStorage, MinioFileStorage
│   └── CodegenTemplates/           # Scriban 模板
│
└── tests/Youlai.Api.Tests/         # 集成测试

设计原则:

  • Youlai.Domain 是最薄层,不依赖任何层
  • Youlai.Application 依赖 Domain,不依赖 Api 和 Infrastructure
  • Youlai.Infrastructure 实现接口,依赖 Application
  • Youlai.Api 作为入口,组合所有层

Part 3: 命名规范

3.1 文件命名
类型规范示例
Controller{Entity}Controller.csUserController.cs
Service 接口I{Entity}Service.csIUserService.cs
Service 实现{Entity}Service.csUserService.cs
EntityPascalCaseSysUser.cs
DTO功能 + 类型后缀UserForm.cs, UserVO.cs
EnumsPascalCase + 无后缀ActionType.cs
3.2 类命名
类型规范示例
Controller{Entity}ControllerUserController
Service 接口I{Entity}ServiceIUserService
Service 实现{Entity}ServiceUserService
EntityPascalCaseSysUser
DTO功能 + 类型UserVO, UserForm, UserPageQuery

DTO 后缀规范:

后缀用途示例
VO视图对象(返回前端)UserVO, RolePageVO
Form / RequestDto表单/请求对象UserForm, LoginRequestDto
Query查询参数UserQuery, RolePageQuery
Dto传输对象CurrentUserDto, ExcelResultDto
3.3 方法命名
动作前缀示例
查询单个GetGetByIdAsync()
查询列表ListListUsersAsync()
分页查询PagePageUsersAsync()
新增CreateCreateUserAsync()
更新UpdateUpdateUserAsync()
删除DeleteDeleteUserAsync()
下拉选项GetXxxOptionsGetUserOptionsAsync()
3.4 变量命名
类型规范示例
局部变量camelCaseuserList
常量PascalCaseMaxSize
私有字段_ 前缀 camelCase_userService
布尔值Is/Has/Can 前缀IsDeleted, HasPermission

⚠️ ASP.NET Core 约定私有字段用 _ 前缀(与 Spring Boot 不同),与官方文档和 EF Core 一致。


Part 4: RESTful API 规范

4.1 标准 CRUD 路径
操作方法路径说明
分页列表GET/api/v1/users/pageQuery 参数
详情GET/api/v1/users/{id}路径参数
表单数据GET/api/v1/users/{id}/form编辑回显
新增POST/api/v1/usersBody: UserForm
更新PUT/api/v1/usersBody: UserForm
删除DELETE/api/v1/users/{id}路径参数
批量删除DELETE/api/v1/users/batchBody: List<long>
下拉选项GET/api/v1/users/options返回 List<OptionType>
4.2 Controller 模板
[ApiController]
[Route("api/v1/users")]
[ApiExplorerSettings(GroupName = "用户管理")]
public class UserController : ControllerBase
{
    private readonly IUserService _userService;

    public UserController(IUserService userService) =>
        _userService = userService;

    [HttpGet("page")]
    [SwaggerOperation(Summary = "用户分页列表")]
    public async Task<Result<PageResult<UserVO>>> Page([FromQuery] UserPageQuery query) =>
        Result.Success(await _userService.PageUsersAsync(query));

    [HttpPost]
    [SwaggerOperation(Summary = "新增用户")]
    [Authorize(Policy = "sys:user:add")]
    public async Task<Result<long>> Create([FromBody] UserForm form) =>
        Result.Success(await _userService.CreateUserAsync(form));

    [HttpPut]
    [SwaggerOperation(Summary = "更新用户")]
    [Authorize(Policy = "sys:user:edit")]
    public async Task<Result> Update([FromBody] UserForm form)
    {
        await _userService.UpdateUserAsync(form);
        return Result.Success();
    }

    [HttpDelete("{id}")]
    [SwaggerOperation(Summary = "删除用户")]
    [Authorize(Policy = "sys:user:delete")]
    public async Task<Result> Delete(long id)
    {
        await _userService.DeleteUserAsync(id);
        return Result.Success();
    }

    [HttpGet("options")]
    [SwaggerOperation(Summary = "用户选项列表")]
    public async Task<Result<List<OptionType>>> Options() =>
        Result.Success(await _userService.GetUserOptionsAsync());
}

Part 5: 响应格式与异常处理

5.1 统一响应
public class Result<T>
{
    public int Code { get; set; }
    public string Msg { get; set; } = string.Empty;
    public T? Data { get; set; }

    public static Result<T> Success(T? data = default) => new() { Code = 200, Msg = "操作成功", Data = data };
    public static Result<T> Failed(int code, string msg) => new() { Code = code, Msg = msg };
}

public class PageResult<T>
{
    public List<T> List { get; set; } = [];
    public long Total { get; set; }

    public static PageResult<T> Of(List<T> list, long total) => new() { List = list, Total = total };
}
5.2 业务异常
public class BusinessException : Exception
{
    public BusinessException(string message) : base(message) { }
}
5.3 全局异常处理
public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;

    public ExceptionMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        try { await _next(context); }
        catch (BusinessException ex) { await WriteResult(context, 200, ex.Message); }
        catch (Exception ex) { await WriteResult(context, 500, "系统异常"); }
    }

    private static async Task WriteResult(HttpContext context, int code, string msg)
    {
        context.Response.StatusCode = 200;
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync(JsonSerializer.Serialize(new { Code = code, Msg = msg, Data = (object?)null }));
    }
}

Part 6: 实体规范

public abstract class BaseEntity
{
    [Key][Column("id")] public long Id { get; set; }
    [Column("create_time")] public DateTime CreateTime { get; set; } = DateTime.Now;
    [Column("update_time")] public DateTime UpdateTime { get; set; } = DateTime.Now;
    [Column("deleted")] public bool Deleted { get; set; } = false;
}

[Table("sys_user")]
public class SysUser : BaseEntity
{
    [Required][MaxLength(50)][Column("username")] public string Username { get; set; } = "";
    [Required][MaxLength(100)][Column("password")] public string Password { get; set; } = "";
    [Required][MaxLength(50)][Column("nickname")] public string Nickname { get; set; } = "";
    [MaxLength(20)][Column("mobile")] public string? Mobile { get; set; }
    [Column("status")] public int Status { get; set; } = 1;
    [Column("dept_id")] public long? DeptId { get; set; }
}

Part 7: Service 规范

public interface IUserService
{
    Task<PageResult<UserVO>> PageUsersAsync(UserPageQuery query);
    Task<UserVO> GetUserByIdAsync(long id);
    Task<UserForm> GetUserFormDataAsync(long id);
    Task<long> CreateUserAsync(UserForm form);
    Task UpdateUserAsync(UserForm form);
    Task DeleteUserAsync(long id);
}

public class UserService : IUserService
{
    private readonly AppDbContext _context;

    public UserService(AppDbContext context) => _context = context;

    public async Task<PageResult<UserVO>> PageUsersAsync(UserPageQuery query)
    {
        var q = _context.Users.Where(u => !u.Deleted);
        if (!string.IsNullOrEmpty(query.Keywords))
            q = q.Where(u => u.Username.Contains(query.Keywords));
        if (query.Status.HasValue)
            q = q.Where(u => u.Status == query.Status.Value);

        var total = await q.CountAsync();
        var list = await q.OrderByDescending(u => u.CreateTime)
            .Skip((query.PageNum - 1) * query.PageSize).Take(query.PageSize)
            .Select(u => new UserVO { Id = u.Id, Username = u.Username, Status = u.Status, CreateTime = u.CreateTime })
            .ToListAsync();
        return PageResult<UserVO>.Of(list, total);
    }

    public async Task<long> CreateUserAsync(UserForm form)
    {
        if (await _context.Users.AnyAsync(u => u.Username == form.Username && !u.Deleted))
            throw new BusinessException("用户名已存在");
        var user = new SysUser { Username = form.Username, Password = BCrypt.HashPassword(form.Password), Status = form.Status };
        _context.Users.Add(user);
        await _context.SaveChangesAsync();
        return user.Id;
    }
}

Part 8: 认证规范

8.1 JWT 配置
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters {
            ValidateIssuer = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"]!))
        };
    });

builder.Services.AddAuthorization(options => {
    options.AddPolicy("sys:user:add", p => p.RequireClaim("permission", "sys:user:add"));
    options.AddPolicy("sys:user:edit", p => p.RequireClaim("permission", "sys:user:edit"));
});
8.2 权限校验
// Controller 中使用 Policy 进行权限校验
[Authorize(Policy = "sys:user:add")]

// 权限标识命名:模块:实体:操作
// sys:user:create / sys:user:edit / sys:user:delete / sys:role:list / sys:menu:assign
8.3 当前用户
public interface ICurrentUser
{
    long UserId { get; }
    string Username { get; }
    List<string> Permissions { get; }
}

public class CurrentUser : ICurrentUser
{
    public long UserId => long.Parse(HttpContext.User.FindFirst(JwtRegisteredClaimNames.Sub)?.Value ?? "0");
    public string Username => HttpContext.User.FindFirst(JwtRegisteredClaimNames.UniqueName)?.Value ?? "";
    public List<string> Permissions => HttpContext.User.FindFirst("permission")?.Value?.Split(',').ToList() ?? [];
}

Part 9: 注释规范

  • 公共方法用 /// <summary> XML 注释(IDE 智能提示可识别)
  • Swagger 使用 [SwaggerOperation(Summary = "...")]
  • 代码修改时注释必须同步更新
/// <summary>
/// 用户管理控制器。
/// </summary>
[ApiExplorerSettings(GroupName = "用户管理")]
public class UserController : ControllerBase
{
    /// <summary>
    /// 创建新用户。
    /// </summary>
    /// <param name="form">用户表单(username 必填且唯一)</param>
    /// <returns>新用户 ID</returns>
    /// <exception cref="BusinessException">用户名已存在</exception>
    [HttpPost]
    [SwaggerOperation(Summary = "新增用户")]
    public async Task<Result<long>> Create([FromBody] UserForm form) { ... }
}

Part 10: 代码质量检查清单

  • 遵循 RESTful API 路径规范
  • 使用统一响应格式
  • 实现全局异常处理中间件
  • 权限校验使用 Authorize(Policy = "...")
  • 分页接口使用 PageResult
  • 实体继承 BaseEntity
  • 使用 EF Core 逻辑删除
  • API 添加 [SwaggerOperation] 注解
  • 分层:Controller → Service → Repository
  • 异步方法以 Async 结尾
  • 公共方法有 /// <summary> XML 注释
常见反模式
反模式正确做法
throw new Exception("用户不存在")throw new BusinessException("用户不存在")
catch { } 空捕获捕获并记录日志或抛出业务异常
public async Task<T> Xxx() 无 Async 后缀加 Async 后缀:XxxAsync()
Controller 中写业务逻辑委托 Service 层处理
同步方法调 SaveChangesAsync().Result使用 await SaveChangesAsync()

Comments

Markdown supported