ASP.NET Core
Microsoftが開発したクロスプラットフォーム対応のモダンWebフレームワーク。高性能なKestrelサーバーを搭載し、マイクロサービスに最適。
GitHub概要
dotnet/aspnetcore
ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
ホームページ:https://asp.net
スター36,872
ウォッチ1,434
フォーク10,394
作成日:2014年3月11日
言語:C#
ライセンス:MIT License
トピックス
aspnetcoredotnethacktoberfesthelp-wanted
スター履歴
データ取得日時: 2025/7/17 10:32
フレームワーク
ASP.NET Core
概要
ASP.NET Coreは、Microsoftが開発したクロスプラットフォーム対応の高性能Webフレームワークです。
詳細
ASP.NET Core(エーエスピー・ドット・ネット・コア)は、Microsoftが開発したオープンソースのクロスプラットフォーム対応Webフレームワークです。2016年にリリースされ、従来のASP.NET Frameworkを完全に再設計・再構築したものです。Windows、macOS、Linuxで動作し、高いパフォーマンスと拡張性を提供します。モジュラー設計により必要な機能のみを組み込むことができ、軽量で高速なアプリケーション開発が可能です。MVC、Web API、Razor Pages、Blazorなど複数の開発モデルをサポートし、企業レベルのWebアプリケーション開発に最適化されています。組み込みの依存性注入、設定システム、ロギング、認証・認可機能により、堅牢で保守性の高いアプリケーションを構築できます。Docker対応、クラウドネイティブ設計により、現代的なマイクロサービスアーキテクチャにも適しています。
メリット・デメリット
メリット
- 高いパフォーマンス: 最適化されたランタイムで高速な処理を実現
- クロスプラットフォーム: Windows、macOS、Linuxで動作
- 統合開発環境: Visual Studioによる強力な開発サポート
- 企業レベル対応: 大規模アプリケーション開発に最適化
- 豊富な機能: 認証、承認、キャッシュ、ロギングなど標準搭載
- 強力な型システム: C#による型安全性とIntelliSense
- 活発なエコシステム: NuGetによる豊富なライブラリ群
デメリット
- 学習コスト: C#言語とフレームワーク概念の習得が必要
- Microsoftエコシステム: Microsoft技術スタックへの依存
- メモリ使用量: JVMやNode.jsと比較して多めのメモリ消費
- デプロイの複雑さ: .NETランタイムのインストールが必要
- ライセンス: 一部の開発ツールが有償
主要リンク
- ASP.NET Core公式サイト
- ASP.NET Core公式ドキュメント
- ASP.NET Core GitHub リポジトリ
- .NET公式サイト
- Visual Studio
- NuGet パッケージマネージャー
書き方の例
Hello World(基本的なWebアプリ)
// Program.cs - Minimal API
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapGet("/hello/{name}", (string name) => $"Hello {name}!");
app.Run();
// Program.cs - MVC
var builder = WebApplication.CreateBuilder(args);
// サービスの登録
builder.Services.AddControllersWithViews();
var app = builder.Build();
// ミドルウェアパイプライン
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
コントローラーとアクション
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewData["Message"] = "ASP.NET Coreアプリケーションです。";
return View();
}
[HttpPost]
public IActionResult Contact(ContactModel model)
{
if (ModelState.IsValid)
{
// フォーム処理ロジック
return RedirectToAction("ContactSuccess");
}
return View(model);
}
[HttpGet]
public JsonResult GetUser(int id)
{
var user = new { Id = id, Name = "太郎", Email = "[email protected]" };
return Json(user);
}
}
public class ContactModel
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
}
}
依存性注入
// サービスインターフェース
public interface IUserService
{
Task<User> GetUserAsync(int id);
Task<IEnumerable<User>> GetAllUsersAsync();
}
// サービス実装
public class UserService : IUserService
{
private readonly ILogger<UserService> _logger;
private readonly HttpClient _httpClient;
public UserService(ILogger<UserService> logger, HttpClient httpClient)
{
_logger = logger;
_httpClient = httpClient;
}
public async Task<User> GetUserAsync(int id)
{
_logger.LogInformation("ユーザー取得: {UserId}", id);
var response = await _httpClient.GetAsync($"/api/users/{id}");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<User>(json) ?? new User();
}
public async Task<IEnumerable<User>> GetAllUsersAsync()
{
var response = await _httpClient.GetAsync("/api/users");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<IEnumerable<User>>(json) ?? Enumerable.Empty<User>();
}
}
// Program.csでの登録
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddHttpClient<UserService>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
});
// コントローラーでの使用
public class UsersController : Controller
{
private readonly IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
public async Task<IActionResult> Index()
{
var users = await _userService.GetAllUsersAsync();
return View(users);
}
}
Entity Framework Core
// モデル定義
public class Blog
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
public List<Post> Posts { get; set; } = new();
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public int BlogId { get; set; }
public Blog Blog { get; set; } = null!;
}
// DbContext
using Microsoft.EntityFrameworkCore;
public class BlogContext : DbContext
{
public BlogContext(DbContextOptions<BlogContext> options) : base(options) { }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Title)
.IsRequired()
.HasMaxLength(200);
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogId);
}
}
// Program.csでの設定
builder.Services.AddDbContext<BlogContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// コントローラーでの使用
public class BlogsController : Controller
{
private readonly BlogContext _context;
public BlogsController(BlogContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
var blogs = await _context.Blogs
.Include(b => b.Posts)
.ToListAsync();
return View(blogs);
}
[HttpPost]
public async Task<IActionResult> Create(Blog blog)
{
if (ModelState.IsValid)
{
blog.CreatedAt = DateTime.Now;
_context.Blogs.Add(blog);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(blog);
}
}
ミドルウェア
// カスタムミドルウェア
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _logger;
public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
var startTime = DateTime.UtcNow;
_logger.LogInformation("リクエスト開始: {Method} {Path}",
context.Request.Method, context.Request.Path);
await _next(context);
var duration = DateTime.UtcNow - startTime;
_logger.LogInformation("リクエスト完了: {Method} {Path} - {StatusCode} ({Duration}ms)",
context.Request.Method, context.Request.Path, context.Response.StatusCode, duration.TotalMilliseconds);
}
}
// 拡張メソッド
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLoggingMiddleware>();
}
}
// Program.csでの使用
app.UseRequestLogging();
// エラーハンドリングミドルウェア
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ErrorHandlingMiddleware> _logger;
public ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "未処理の例外が発生しました");
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
var response = new { error = "内部サーバーエラーが発生しました" };
await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}
}
Web APIとJSON処理
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IProductService _productService;
private readonly ILogger<ProductsController> _logger;
public ProductsController(IProductService productService, ILogger<ProductsController> logger)
{
_productService = productService;
_logger = logger;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
{
try
{
var products = await _productService.GetAllProductsAsync();
return Ok(products);
}
catch (Exception ex)
{
_logger.LogError(ex, "商品一覧取得でエラーが発生");
return StatusCode(500, "内部サーバーエラー");
}
}
[HttpGet("{id}")]
public async Task<ActionResult<Product>> GetProduct(int id)
{
var product = await _productService.GetProductByIdAsync(id);
if (product == null)
{
return NotFound($"ID {id} の商品が見つかりません");
}
return Ok(product);
}
[HttpPost]
public async Task<ActionResult<Product>> CreateProduct([FromBody] CreateProductRequest request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var product = new Product
{
Name = request.Name,
Price = request.Price,
Description = request.Description,
CreatedAt = DateTime.UtcNow
};
var createdProduct = await _productService.CreateProductAsync(product);
return CreatedAtAction(
nameof(GetProduct),
new { id = createdProduct.Id },
createdProduct);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateProduct(int id, [FromBody] UpdateProductRequest request)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var existingProduct = await _productService.GetProductByIdAsync(id);
if (existingProduct == null)
{
return NotFound();
}
existingProduct.Name = request.Name;
existingProduct.Price = request.Price;
existingProduct.Description = request.Description;
existingProduct.UpdatedAt = DateTime.UtcNow;
await _productService.UpdateProductAsync(existingProduct);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
var product = await _productService.GetProductByIdAsync(id);
if (product == null)
{
return NotFound();
}
await _productService.DeleteProductAsync(id);
return NoContent();
}
}
// DTOクラス
public class CreateProductRequest
{
[Required(ErrorMessage = "商品名は必須です")]
[StringLength(100, ErrorMessage = "商品名は100文字以内で入力してください")]
public string Name { get; set; } = string.Empty;
[Range(0, double.MaxValue, ErrorMessage = "価格は0以上である必要があります")]
public decimal Price { get; set; }
[StringLength(500, ErrorMessage = "説明は500文字以内で入力してください")]
public string Description { get; set; } = string.Empty;
}
public class UpdateProductRequest
{
[Required]
[StringLength(100)]
public string Name { get; set; } = string.Empty;
[Range(0, double.MaxValue)]
public decimal Price { get; set; }
[StringLength(500)]
public string Description { get; set; } = string.Empty;
}