mcpField
A
aspnet

aspnet

github.com/youlaitech開発6258 回インストール5 日前に更新
リポジトリ

aspnet について

ASP.NET Core のバックエンド開発向け規約と例をまとめたスキルです。REST API、EF Core によるデータアクセス、認証・認可を扱う開発チーム向けに、構成や命名、応答処理、品質確認を示します。

主な機能

  1. 01.NET 8+ と ASP.NET Core の技術スタック規約
  2. 02レイヤー構成、命名、DTO 接尾辞の定義
  3. 03RESTful CRUD ルートと非同期メソッドの標準化
  4. 04統一応答形式と業務例外の処理
  5. 05JWT 認証と Policy ベース認可の説明
  6. 06品質チェック項目と一般的なアンチパターン

活用シーン

  1. 01ASP.NET Core プロジェクトのフォルダーとレイヤー構成
  2. 02一貫性のある REST API ルートと応答の設計
  3. 03JWT 認証と権限ポリシーの実装
  4. 04バックエンド規約と例外処理のレビュー

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/aspnetを入力して読み込まれたか確認します。

詳細

ASP.NET Core バックエンド開発規約

トリガー条件

  • ASP.NET Core プロジェクトを開発する
  • REST API を実装する
  • データアクセスに Entity Framework Core を使用する
  • JWT 認証を実装する
  • 権限制御を実装する

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
EnumPascalCase + 接尾辞なし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/optionsList<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()

コメント