mcpField
A
aspnet-core

aspnet-core

github.com/claude-dev-suite開発4642 回インストール4 日前に更新
リポジトリ

aspnet-core について

ASP.NET Core 開発者向けのクイックリファレンススキルで、一般的なアプリ設定や実装パターンを扱います。コントローラー、サービス、依存性注入、設定、例外処理の例とトラブルシューティングを含みます。

主な機能

  1. 01Program.cs のアプリ設定
  2. 02コントローラーとサービスのパターン
  3. 03依存性注入のライフタイム
  4. 04設定バインディングの例
  5. 05グローバル例外処理
  6. 06一般的な問題の診断

活用シーン

  1. 01ASP.NET Core アプリの構成
  2. 02コントローラーとサービスのコード整理
  3. 03依存性注入のライフタイム選択
  4. 04ルーティングや設定の問題診断

MCP 対応

包括的なドキュメントを参照するため、技術識別子 `aspnet-core` とともに `mcp__documentation__fetch_docs` を案内します。

インストール

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

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill aspnet-core

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

詳細

ASP.NET Core - クイックリファレンス

詳細な知識:包括的なドキュメントについては、technology: aspnet-core を指定して mcp__documentation__fetch_docs を使用してください。

Program.cs の設定

var builder = WebApplication.CreateBuilder(args);

// Services
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));

// Dependency injection
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IUserRepository, UserRepository>();

// Configuration
builder.Services.Configure<JwtOptions>(builder.Configuration.GetSection("Jwt"));

var app = builder.Build();

// Middleware pipeline (order matters!)
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

コントローラーパターン

[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class UsersController : ControllerBase
{
    private readonly IUserService _userService;

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

    [HttpGet]
    [ProducesResponseType<IEnumerable<UserResponse>>(StatusCodes.Status200OK)]
    public async Task<IActionResult> GetAll([FromQuery] int page = 1, [FromQuery] int size = 10)
    {
        var users = await _userService.GetAllAsync(page, size);
        return Ok(users);
    }

    [HttpGet("{id:int}")]
    [ProducesResponseType<UserResponse>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetById(int id)
    {
        var user = await _userService.GetByIdAsync(id);
        return user is null ? NotFound() : Ok(user);
    }

    [HttpPost]
    [ProducesResponseType<UserResponse>(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> Create([FromBody] CreateUserRequest request)
    {
        var user = await _userService.CreateAsync(request);
        return CreatedAtAction(nameof(GetById), new { id = user.Id }, user);
    }

    [HttpPut("{id:int}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> Update(int id, [FromBody] UpdateUserRequest request)
    {
        var result = await _userService.UpdateAsync(id, request);
        return result ? NoContent() : NotFound();
    }

    [HttpDelete("{id:int}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    public async Task<IActionResult> Delete(int id)
    {
        await _userService.DeleteAsync(id);
        return NoContent();
    }
}

サービスレイヤー

public interface IUserService
{
    Task<UserResponse?> GetByIdAsync(int id);
    Task<IEnumerable<UserResponse>> GetAllAsync(int page, int size);
    Task<UserResponse> CreateAsync(CreateUserRequest request);
    Task<bool> UpdateAsync(int id, UpdateUserRequest request);
    Task DeleteAsync(int id);
}

public class UserService : IUserService
{
    private readonly IUserRepository _repository;
    private readonly ILogger<UserService> _logger;

    public UserService(IUserRepository repository, ILogger<UserService> logger)
    {
        _repository = repository;
        _logger = logger;
    }

    public async Task<UserResponse?> GetByIdAsync(int id)
    {
        var user = await _repository.GetByIdAsync(id);
        return user is null ? null : MapToResponse(user);
    }

    public async Task<UserResponse> CreateAsync(CreateUserRequest request)
    {
        var user = new User { Name = request.Name, Email = request.Email };
        await _repository.AddAsync(user);
        _logger.LogInformation("User {UserId} created", user.Id);
        return MapToResponse(user);
    }

    private static UserResponse MapToResponse(User user)
        => new(user.Id, user.Name, user.Email, user.CreatedAt);
}

レコードを使用した DTO

public record CreateUserRequest(string Name, string Email);
public record UpdateUserRequest(string Name, string Email);
public record UserResponse(int Id, string Name, string Email, DateTime CreatedAt);

依存性注入のライフタイム

ライフタイム用途
AddTransient<T>軽量でステートレスなサービス
AddScoped<T>リクエストごとのサービス(リポジトリ、DbContext)
AddSingleton<T>共有状態、キャッシュ、設定

設定のバインド

// appsettings.json
// { "Jwt": { "Key": "...", "Issuer": "..." } }

public class JwtOptions
{
    public string Key { get; set; } = default!;
    public string Issuer { get; set; } = default!;
    public string Audience { get; set; } = default!;
    public int ExpiryMinutes { get; set; } = 60;
}

// Register
builder.Services.Configure<JwtOptions>(builder.Configuration.GetSection("Jwt"));

// Use
public class AuthService
{
    private readonly JwtOptions _options;
    public AuthService(IOptions<JwtOptions> options) => _options = options.Value;
}

グローバル例外処理

app.UseExceptionHandler(app => app.Run(async context =>
{
    var exception = context.Features.Get<IExceptionHandlerFeature>()?.Error;
    var response = exception switch
    {
        NotFoundException e => (StatusCodes.Status404NotFound, e.Message),
        ValidationException e => (StatusCodes.Status400BadRequest, e.Message),
        _ => (StatusCodes.Status500InternalServerError, "An unexpected error occurred"),
    };

    context.Response.StatusCode = response.Item1;
    await context.Response.WriteAsJsonAsync(new { error = response.Item2 });
}));

アンチパターン

アンチパターン問題点正しいアプローチ
コントローラーにビジネスロジックを記述するSRP に違反しますサービスレイヤーを使用します
依存関係の生成に new を使うテストできませんコンストラクター DI を使用します
DbContext をシングルトンにするスレッドセーフではありませんScoped ライフタイムを使用します
コントローラーですべての例外をキャッチする繰り返しが多く、一貫性がありませんグローバル例外ハンドラーを使用します
API からエンティティを返す内部情報を公開してしまいますDTO/レコードを使用します

クイックトラブルシューティング

問題考えられる原因解決策
DI の解決エラー登録が不足していますProgram.cs でサービスを登録します
エンドポイントが 404 を返すルートテンプレートが間違っています[Route] 属性を確認します
モデルバインディングが null になる[FromX] 属性が間違っていますJSON には [FromBody] を使用します
設定値が null になるセクションパスが間違っていますGetSection() のパスを確認します

コメント