リリース・改善中
ASP.NET Core ガイド · 3/6
この章は現在、英語でのみ提供しています。
ASP.NET Core is built from a few ideas that fit together: a host that runs the app, a middleware pipeline that every request passes through, a dependency injection container, endpoints written as minimal APIs or controllers, and configuration and logging shared by all of them.
WebApplication.CreateBuilder creates a host with Kestrel, configuration, logging and DI. After Build(), each Use... call adds a middleware component. A request flows through them in the order they were added; each can act before and after calling the next one, or end the request early.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler(); // first: catches errors from everything after it
app.UseHttpsRedirection();
app.Use(async (context, next) =>
{
var watch = System.Diagnostics.Stopwatch.StartNew();
await next(context); // run the rest of the pipeline
app.Logger.LogInformation("{Path} took {Ms} ms", context.Request.Path, watch.ElapsedMilliseconds);
});
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", () => "Hello");
app.Run();Order matters: the exception handler comes first so it wraps everything, and authentication must run before authorization. Endpoints (Map...) run at the end of the pipeline.
Services are registered on builder.Services with one of three lifetimes:
| Lifetime | One instance per | Typical use |
|---|---|---|
AddSingleton | application | caches, clocks, stateless helpers |
AddScoped | HTTP request | DbContext, unit-of-work services |
AddTransient | resolution | lightweight stateless services |
builder.Services.AddSingleton(TimeProvider.System);
builder.Services.AddScoped<TodoService>();The framework injects services wherever it creates objects: minimal API handler parameters, controller constructors and other services. Do not inject a scoped service into a singleton; in Development the container detects this and throws.
Both styles share routing, DI and middleware. Minimal APIs map lambdas or methods directly. TypedResults and Results<...> make every possible response visible in the signature and in OpenAPI:
using Microsoft.AspNetCore.Http.HttpResults;
var todos = app.MapGroup("/todos");
todos.MapGet("/{id:int}", Results<Ok<Todo>, NotFound> (int id, TodoService service) =>
service.Find(id) is { } todo ? TypedResults.Ok(todo) : TypedResults.NotFound());
todos.MapPost("/", (Todo todo, TodoService service) =>
{
service.Add(todo);
return TypedResults.Created($"/todos/{todo.Id}", todo);
});Controllers group actions in classes and describe routes with attributes:
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class TodosController(TodoService service) : ControllerBase
{
[HttpGet("{id:int}")]
public ActionResult<Todo> Get(int id)
{
var todo = service.Find(id);
if (todo is null) return NotFound();
return todo;
}
}
// Program.cs: builder.Services.AddControllers(); ... app.MapControllers();Minimal APIs are the default for new APIs: less ceremony and very good performance. Controllers suit teams that like MVC conventions, filters and attribute-based model binding, and they are the basis of MVC apps with views.
Route templates hold parameters and constraints such as {id:int}, {slug} and {page?}. Handler parameters are bound automatically: simple types from route values and the query string, complex types from the JSON body, registered services from DI, and special types such as HttpContext, HttpRequest and CancellationToken. Attributes like [FromQuery], [FromHeader] and [FromServices] (namespace Microsoft.AspNetCore.Mvc) make the source explicit.
// GET /posts/hello-world?page=2
app.MapGet("/posts/{slug}", (string slug, int? page, HttpRequest request) =>
$"{slug}, page {page ?? 1}, agent {request.Headers.UserAgent}");Bind a configuration section to a class and inject it with the options pattern:
using Microsoft.Extensions.Options;
builder.Services.Configure<TodoOptions>(builder.Configuration.GetSection("Todo"));
app.MapGet("/settings", (IOptions<TodoOptions> options) => options.Value.PageSize);
public class TodoOptions
{
public int PageSize { get; set; } = 20;
}IOptionsSnapshot<T> re-reads values per request and IOptionsMonitor<T> reports changes. AddOptions<T>().BindConfiguration("Todo").ValidateDataAnnotations().ValidateOnStart() fails fast at startup when settings are invalid.
public class TodoService(ILogger<TodoService> logger)
{
public void Add(Todo todo)
{
logger.LogInformation("Added todo {TodoId}", todo.Id);
}
}ILogger<T> is available everywhere through DI. Use message templates with named placeholders instead of string interpolation so providers can store TodoId as a structured field. Minimum levels per category come from the Logging:LogLevel configuration section.
ILogger<T> gives structured logs.
コメント 0件
ログイン · ログインするとコメントできます。
最初のコメントを書いてみましょう。