はじめに
ASP.NET Coreは、Microsoftが提供する最新のWebアプリケーション開発フレームワークです。クロスプラットフォーム対応、高いパフォーマンス、そして豊富な機能を備えており、モダンなWeb開発に最適なツールとして注目を集めています。本記事では、ASP.NET Coreの基礎から実践的な開発手法まで、現役エンジニアの視点で詳しく解説していきます。
この記事を読んだらわかること:
- ASP.NET Coreの基本概念と従来の.NET Frameworkとの違い
- MVCパターンを用いた実践的なWebアプリケーション開発の方法
- パフォーマンス最適化とメモリ使用量の改善テクニック
- セキュリティ対策の実装方法と具体的な防御手段
- Entity Framework Coreを使用したデータベース連携の実践手法
- DockerとCI/CDを活用したモダンなデプロイメント手法
ASP.NET Coreとは何か – モダンWeb開発の新標準
ASP.NET Coreは、Microsoftが開発した最新のWebアプリケーションフレームワークです。従来の.NET Frameworkを基盤とするASP.NETとは異なり、オープンソースでクロスプラットフォーム対応の新しいフレームワークとして設計されています。
従来の.NET Frameworkとの決定的な違い
ASP.NET CoreとASP.NET Frameworkの主要な違いは以下の点にあります:
特徴 | ASP.NET Core | ASP.NET Framework |
---|---|---|
プラットフォーム | クロスプラットフォーム(Windows, Linux, macOS) | Windowsのみ |
依存性 | 完全モジュール化(必要な機能のみ導入可能) | モノリシック(全機能が統合) |
パフォーマンス | 高速(軽量設計) | 比較的重い |
開発方式 | オープンソース | プロプライエタリ |
デプロイ | 柔軟(自己完結型展開可能) | IIS依存 |
特筆すべき点として、ASP.NET Coreでは必要な機能のみを選択してインストールできる「Pay-for-what-you-use」モデルを採用しています。これにより、アプリケーションの起動時間が短縮され、メモリ使用量も最適化されます。
クロスプラットフォーム対応による新たな可能性
ASP.NET Coreの最大の特徴は、真のクロスプラットフォーム対応です。以下のような開発シナリオが可能になりました:
- 開発環境の自由な選択
- Visual Studio Code(Windows/Mac/Linux)
- Visual Studio(Windows/Mac)
- JetBrains Rider(全プラットフォーム)
- デプロイ先の柔軟な選択
- Linux系サーバー
- Windows Server
- Dockerコンテナ
- クラウドプラットフォーム(Azure, AWS, GCP)
実際の開発では、以下のようなプロジェクト作成コマンドで、どのプラットフォームでも同じように開発を始めることができます:
# 新規Webアプリケーションプロジェクトの作成 dotnet new webapp -n MyFirstAspNetCoreApp # APIプロジェクトの作成 dotnet new webapi -n MyFirstWebApi
高速で軽量な実行環境の実現方法
ASP.NET Coreは、以下の技術的特徴により高いパフォーマンスを実現しています:
Kestrelサーバー
- ネイティブで高性能なWebサーバー
- 非同期I/O処理による高スループット
- メモリ効率の高い実装
最適化されたミドルウェアパイプライン
public void Configure(IApplicationBuilder app) { // 必要最小限のミドルウェアのみを使用 app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }
JITコンパイル最適化
- プラットフォーム特有の最適化
- Tiered Compilationによる実行時最適化
- ReadyToRun形式による起動時間の短縮
効率的なメモリ管理
// Spanを使用した効率的なメモリ操作の例 public void ProcessLargeData(ReadOnlySpan<byte> data) { // スタックアロケーションを最小限に抑える Span<byte> buffer = stackalloc byte[1024]; // データ処理... }
これらの特徴により、ASP.NET Coreは以下のようなパフォーマンス指標を達成しています:
リクエスト処理速度: 従来の約2倍
メモリ使用量: 最大50%削減
アプリケーション起動時間: 約30%短縮
ASP.NET Coreは、これらの革新的な特徴により、モダンなWeb開発の新標準として急速に普及しています。特に、マイクロサービスアーキテクチャやコンテナ化された環境での開発において、その真価を発揮します。
ASP.NET Coreで作る最新のWebアプリケーション
ASP.NET Coreを使用した最新のWebアプリケーション開発では、モダンな開発手法とベストプラクティスを活用することで、保守性が高く拡張しやすいアプリケーションを構築できます。
新規プロジェクトのセットアップと基本設定
新規プロジェクトの作成から基本設定まで、以下の手順で効率的に開発環境を整えることができます:
プロジェクトの作成
# MVCプロジェクトの作成 dotnet new mvc -n ModernWebApp cd ModernWebApp # 必要なパッケージの追加 dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
アプリケーション設定の構成
var builder = WebApplication.CreateBuilder(args); // サービスの追加 builder.Services.AddControllersWithViews(); builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // アプリケーションの構築 var app = builder.Build(); // ミドルウェアの設定 if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
Model-View-Controllerパターンの実装方法
MVCパターンの効果的な実装例を見ていきましょう:
モデルの定義
public class Product { public int Id { get; set; } [Required] [StringLength(100)] public string Name { get; set; } [Range(0, 1000000)] public decimal Price { get; set; } public string Description { get; set; } [DataType(DataType.Date)] public DateTime CreatedDate { get; set; } }
コントローラーの実装
public class ProductController : Controller { private readonly IProductService _productService; private readonly ILogger<ProductController> _logger; public ProductController(IProductService productService, ILogger<ProductController> logger) { _productService = productService; _logger = logger; } public async Task<IActionResult> Index() { try { var products = await _productService.GetAllProductsAsync(); return View(products); } catch (Exception ex) { _logger.LogError(ex, "製品一覧の取得中にエラーが発生しました"); return StatusCode(500); } } }
ビューの作成
@model IEnumerable<ModernWebApp.Models.Product> <div class="container"> <h2>製品一覧</h2> <div class="row"> @foreach (var product in Model) { <div class="col-md-4 mb-4"> <div class="card"> <div class="card-body"> <h5 class="card-title">@product.Name</h5> <p class="card-text">@product.Description</p> <p class="card-text"> <strong>価格:</strong> @product.Price.ToString("C") </p> </div> </div> </div> } </div> </div>
依存性注入を活用した疎結合な設計手法
ASP.NET Coreの依存性注入(DI)を活用した実装例:
サービスインターフェースの定義
public interface IProductService { Task<IEnumerable<Product>> GetAllProductsAsync(); Task<Product> GetProductByIdAsync(int id); Task<Product> CreateProductAsync(Product product); }
サービス実装
public class ProductService : IProductService { private readonly ApplicationDbContext _context; private readonly IMapper _mapper; public ProductService(ApplicationDbContext context, IMapper mapper) { _context = context; _mapper = mapper; } public async Task<IEnumerable<Product>> GetAllProductsAsync() { return await _context.Products .AsNoTracking() .OrderByDescending(p => p.CreatedDate) .ToListAsync(); } // 他のメソッド実装... }
DIコンテナへの登録
builder.Services.AddScoped<IProductService, ProductService>(); builder.Services.AddAutoMapper(typeof(Program).Assembly); builder.Services.AddScoped<IEmailService, EmailService>(); // カスタム設定の注入 builder.Services.Configure<EmailSettings>( builder.Configuration.GetSection("EmailSettings"));
このような実装により、以下のメリットが得られます:
テスト容易性の向上
コンポーネントの再利用性
保守性の向上
実装の柔軟性
ASP.NET Coreのこれらの機能を活用することで、スケーラブルで保守性の高いWebアプリケーションを効率的に開発することができます。
パフォーマンスを最大化するASP.NET Coreの機能
ASP.NET Coreは、高いパフォーマンスを実現するための多様な機能を提供しています。適切な実装方法を理解し、これらの機能を効果的に活用することで、アプリケーションの応答性と処理能力を大幅に向上させることができます。
非同期処理による応答性の向上テクニック
非同期プログラミングを効果的に実装することで、アプリケーションのスケーラビリティと応答性を向上させることができます:
非同期コントローラーアクションの実装
public class ProductController : Controller { private readonly IProductService _productService; public ProductController(IProductService productService) { _productService = productService; } // 非同期アクションメソッド public async Task<IActionResult> Index() { // ConfigureAwait(false)を使用して不要な同期コンテキストの切り替えを防ぐ var products = await _productService.GetProductsAsync().ConfigureAwait(false); return View(products); } // 並列処理を活用した非同期処理 public async Task<IActionResult> Dashboard() { var tasks = new[] { _productService.GetTotalSalesAsync(), _productService.GetTopProductsAsync(), _productService.GetRecentOrdersAsync() }; // 複数の非同期処理を並列実行 await Task.WhenAll(tasks); var viewModel = new DashboardViewModel { TotalSales = tasks[0].Result, TopProducts = tasks[1].Result, RecentOrders = tasks[2].Result }; return View(viewModel); } }
非同期ストリーム処理の活用
public async IAsyncEnumerable<Product> GetProductStreamAsync() { await using var context = new ProductContext(); var products = context.Products.AsAsyncEnumerable(); await foreach (var product in products) { // 大量データを少しずつ処理 yield return product; } }
キャッシュ機能の効果的な活用方法
ASP.NET Coreは、複数のレベルでキャッシュを実装できます:
メモリキャッシュの実装
public class CacheProductService : IProductService { private readonly IMemoryCache _cache; private readonly IProductRepository _repository; public async Task<Product> GetProductByIdAsync(int id) { string cacheKey = $"product_{id}"; return await _cache.GetOrCreateAsync(cacheKey, async entry => { entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(10)); entry.SetSlidingExpiration(TimeSpan.FromMinutes(2)); return await _repository.GetProductByIdAsync(id); }); } }
分散キャッシュの設定(Redis使用)
public void ConfigureServices(IServiceCollection services) { services.AddStackExchangeRedisCache(options => { options.Configuration = Configuration.GetConnectionString("Redis"); options.InstanceName = "ProductCache_"; }); }
レスポンスキャッシュの実装
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any)] public async Task<IActionResult> ProductList() { var products = await _productService.GetProductsAsync(); return View(products); }
メモリ使用量の最適化戦略
メモリ使用量を最適化するための主要な戦略:
オブジェクトプーリングの実装
public class ApiController : Controller { private readonly ObjectPool<StringBuilder> _stringBuilderPool; public ApiController(ObjectPoolProvider poolProvider) { _stringBuilderPool = poolProvider.CreateStringBuilderPool(); } public IActionResult ProcessData(string data) { var sb = _stringBuilderPool.Get(); try { // StringBuilder を使用した処理 sb.Append("処理結果: ").Append(data); return Ok(sb.ToString()); } finally { _stringBuilderPool.Return(sb); } } }
効率的なメモリ管理
public class DataProcessor { // 大きな配列の効率的な処理 public async Task ProcessLargeDataAsync(Stream stream) { const int bufferSize = 4096; using var memoryStream = new MemoryStream(); Memory<byte> buffer = new byte[bufferSize]; int bytesRead; while ((bytesRead = await stream.ReadAsync(buffer)) > 0) { await memoryStream.WriteAsync(buffer[..bytesRead]); } } }
これらの最適化技術を適切に組み合わせることで、ASP.NET Coreアプリケーションの性能を最大限に引き出すことができます。
アプリケーションの重要な指標を監視
メモリ使用量
レスポンス時間
スループット
GCの頻度
ボトルネックの特定と対策
プロファイリングツールの活用
パフォーマンステストの実施
継続的なモニタリング
セキュリティ対策の実装ガイド
ASP.NET Coreには、堅牢なセキュリティ機能が組み込まれています。適切な実装により、アプリケーションを様々な脅威から保護することができます。
認証・認可の実装ベストプラクティス
Identity機能の実装
public void ConfigureServices(IServiceCollection services) { services.AddIdentity<ApplicationUser, IdentityRole>(options => { // パスワードポリシーの設定 options.Password.RequireDigit = true; options.Password.RequireLowercase = true; options.Password.RequireUppercase = true; options.Password.RequireNonAlphanumeric = true; options.Password.MinLength = 12; // ロックアウトポリシー options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15); options.Lockout.MaxFailedAccessAttempts = 5; }) .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); }
JWT認証の実装
public class AuthenticationService : IAuthenticationService { private readonly IConfiguration _configuration; private readonly UserManager<ApplicationUser> _userManager; public async Task<string> GenerateJwtToken(ApplicationUser user) { var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, user.Id), new Claim(ClaimTypes.Email, user.Email), new Claim(ClaimTypes.Role, "User") }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes( _configuration["JWT:SecretKey"])); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _configuration["JWT:Issuer"], audience: _configuration["JWT:Audience"], claims: claims, expires: DateTime.Now.AddHours(1), signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token); } }
クロスサイトスクリプティング対策の実践
XSS防御の実装
public void ConfigureServices(IServiceCollection services) { services.AddAntiforgery(options => { options.Cookie.Name = "X-CSRF-TOKEN"; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; }); services.Configure<HtmlEncoderOptions>(options => { options.HtmlAttributeEncode = true; }); }
CSPヘッダーの設定
public void Configure(IApplicationBuilder app) { app.Use(async (context, next) => { context.Response.Headers.Add( "Content-Security-Policy", "default-src 'self'; " + "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " + "style-src 'self' 'unsafe-inline';" ); await next(); }); }
セキュアな設定とデータ保護の方法
データ保護APIの実装
public class SecureDataService { private readonly IDataProtector _protector; public SecureDataService(IDataProtectionProvider provider) { _protector = provider.CreateProtector("SecureData.v1"); } public string ProtectData(string data) { return _protector.Protect(data); } public string UnprotectData(string protectedData) { return _protector.Unprotect(protectedData); } }
セキュアな設定管理
public class Startup { public void ConfigureServices(IServiceCollection services) { // セキュアな設定の管理 services.AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"path\to\keys")) .SetDefaultKeyLifetime(TimeSpan.FromDays(90)); // HTTPSリダイレクションの強制 services.AddHttpsRedirection(options => { options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect; options.HttpsPort = 443; }); // セッション設定 services.AddSession(options => { options.Cookie.Name = ".MyApp.Session"; options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.IdleTimeout = TimeSpan.FromMinutes(20); }); } }
これらのセキュリティ対策を適切に実装することで、アプリケーションを様々な脅威から保護し、ユーザーデータの安全性を確保することができます。
- 基本的なセキュリティ対策
- HTTPSの強制
- セキュアクッキーの使用
- 適切な認証・認可の実装
- XSS対策の実装
- CSRF対策の実装
- データ保護
- 機密データの暗号化
- セキュアなストレージの使用
- キーの定期的なローテーション
- バックアップの暗号化
- 監視とログ記録
- セキュリティイベントのログ記録
- 異常検知の実装
- 監査ログの保護
実践的なデータベース連携
ASP.NET Coreでのデータベース連携は、主にEntity Framework Core(EF Core)を使用して実装します。効率的なデータアクセスと保守性の高いコードを実現するための実践的な手法を見ていきましょう。
Entity Frameworkを使用したCRUD操作の実装
DbContextの設定
public class ApplicationDbContext : DbContext { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } public DbSet<Product> Products { get; set; } public DbSet<Category> Categories { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { // リレーションシップの設定 modelBuilder.Entity<Product>() .HasOne(p => p.Category) .WithMany(c => c.Products) .HasForeignKey(p => p.CategoryId); // インデックスの設定 modelBuilder.Entity<Product>() .HasIndex(p => p.Name); // 複合キーの設定 modelBuilder.Entity<OrderItem>() .HasKey(oi => new { oi.OrderId, oi.ProductId }); } }
リポジトリパターンの実装
public class ProductRepository : IProductRepository { private readonly ApplicationDbContext _context; public ProductRepository(ApplicationDbContext context) { _context = context; } // 非同期でのCRUD操作 public async Task<Product> CreateAsync(Product product) { await _context.Products.AddAsync(product); await _context.SaveChangesAsync(); return product; } public async Task<Product> UpdateAsync(Product product) { _context.Entry(product).State = EntityState.Modified; await _context.SaveChangesAsync(); return product; } public async Task<bool> DeleteAsync(int id) { var product = await _context.Products.FindAsync(id); if (product == null) return false; _context.Products.Remove(product); await _context.SaveChangesAsync(); return true; } public async Task<IEnumerable<Product>> GetAllAsync() { return await _context.Products .Include(p => p.Category) .AsNoTracking() .ToListAsync(); } }
マイグレーションによるデータベース管理
マイグレーションの作成と適用
# マイグレーションの作成 dotnet ef migrations add InitialCreate # マイグレーションの適用 dotnet ef database update
マイグレーションコードの例
public partial class AddProductInventory : Migration { protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AddColumn<int>( name: "StockQuantity", table: "Products", type: "int", nullable: false, defaultValue: 0); migrationBuilder.CreateIndex( name: "IX_Products_StockQuantity", table: "Products", column: "StockQuantity"); } protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropColumn( name: "StockQuantity", table: "Products"); } }
パフォーマンスを考慮したクエリ最適化
効率的なクエリの実装
public class OptimizedProductRepository : IProductRepository { private readonly ApplicationDbContext _context; // クエリの最適化例 public async Task<IEnumerable<ProductSummary>> GetProductSummariesAsync() { return await _context.Products .AsNoTracking() // 読み取り専用クエリの最適化 .Select(p => new ProductSummary // 必要なプロパティのみ選択 { Id = p.Id, Name = p.Name, Price = p.Price, CategoryName = p.Category.Name }) .ToListAsync(); } // ページング処理の実装 public async Task<(List<Product> Items, int TotalCount)> GetPagedAsync( int pageNumber, int pageSize) { var query = _context.Products .Include(p => p.Category) .AsNoTracking(); var totalCount = await query.CountAsync(); var items = await query .OrderBy(p => p.Name) .Skip((pageNumber - 1) * pageSize) .Take(pageSize) .ToListAsync(); return (items, totalCount); } // 複雑な検索条件の実装 public async Task<IEnumerable<Product>> SearchAsync(ProductSearchCriteria criteria) { var query = _context.Products.AsQueryable(); if (!string.IsNullOrEmpty(criteria.Name)) query = query.Where(p => p.Name.Contains(criteria.Name)); if (criteria.MinPrice.HasValue) query = query.Where(p => p.Price >= criteria.MinPrice.Value); if (criteria.MaxPrice.HasValue) query = query.Where(p => p.Price <= criteria.MaxPrice.Value); return await query .AsNoTracking() .ToListAsync(); } }
インデックスの適切な設定
必要なデータのみの取得
N+1問題の回避
クエリの結果キャッシング
トランザクション管理
public async Task<bool> ProcessOrderAsync(Order order) { using var transaction = await _context.Database.BeginTransactionAsync(); try { // 注文の登録 await _context.Orders.AddAsync(order); // 在庫の更新 foreach (var item in order.Items) { var product = await _context.Products.FindAsync(item.ProductId); product.StockQuantity -= item.Quantity; } await _context.SaveChangesAsync(); await transaction.CommitAsync(); return true; } catch { await transaction.RollbackAsync(); throw; } }
これらの実装方法を適切に組み合わせることで、効率的で保守性の高いデータベース連携を実現できます。
デプロイメントとCI/CDパイプライン
ASP.NET Coreアプリケーションの効率的なデプロイメントと継続的な開発・デリバリーを実現するための実践的な方法を解説します。
Dockerコンテナを使用した展開方法
Dockerfileの作成
# ビルドステージ FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /src # プロジェクトファイルのコピーと依存関係の復元 COPY ["MyApp.csproj", "./"] RUN dotnet restore # ソースコードのコピーとビルド COPY . . RUN dotnet build -c Release -o /app/build RUN dotnet publish -c Release -o /app/publish # 実行ステージ FROM mcr.microsoft.com/dotnet/aspnet:7.0 WORKDIR /app COPY --from=build /app/publish . EXPOSE 80 ENTRYPOINT ["dotnet", "MyApp.dll"]
docker-compose.ymlの設定
version: '3.8' services: webapp: build: context: . dockerfile: Dockerfile ports: - "8080:80" environment: - ASPNETCORE_ENVIRONMENT=Production - ConnectionStrings__DefaultConnection=Server=db;Database=MyApp;User=sa;Password=YourPassword; depends_on: - db db: image: mcr.microsoft.com/mssql/server:2019-latest environment: - ACCEPT_EULA=Y - SA_PASSWORD=YourPassword ports: - "1433:1433" volumes: - dbdata:/var/opt/mssql volumes: dbdata:
クラウドプラットフォームへのデプロイ手順
Azure App Serviceへのデプロイ設定
# azure-pipeline.yml trigger: - main variables: azureSubscription: 'Azure Production' webAppName: 'myapp-production' vmImageName: 'ubuntu-latest' stages: - stage: Build displayName: Build stage jobs: - job: Build displayName: Build pool: vmImage: $(vmImageName) steps: - task: DotNetCoreCLI@2 inputs: command: 'build' projects: '**/*.csproj' arguments: '--configuration Release' - task: DotNetCoreCLI@2 inputs: command: 'publish' publishWebProjects: true arguments: '--configuration Release --output $(Build.ArtifactStagingDirectory)' - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.ArtifactStagingDirectory)' artifactName: 'webapp'
環境別の設定管理
{ "Production": { "ConnectionStrings": { "DefaultConnection": "Server=prod-db;Database=MyApp;..." }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning" } }, "ApplicationInsights": { "ConnectionString": "your-connection-string" } } }
自動テストと継続的デプロイの構築
自動テストの実装
public class ProductControllerTests { private readonly IProductService _mockProductService; private readonly ProductController _controller; public ProductControllerTests() { _mockProductService = Substitute.For<IProductService>(); _controller = new ProductController(_mockProductService); } [Fact] public async Task Index_ReturnsViewResult_WithListOfProducts() { // Arrange var expectedProducts = new List<Product> { new Product { Id = 1, Name = "Test Product" } }; _mockProductService.GetProductsAsync() .Returns(expectedProducts); // Act var result = await _controller.Index(); // Assert var viewResult = Assert.IsType<ViewResult>(result); var model = Assert.IsAssignableFrom<IEnumerable<Product>>( viewResult.Model); Assert.Equal(expectedProducts.Count, model.Count()); } }
CI/CDパイプラインの構築(GitHub Actions)
name: .NET Core CI/CD on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: dotnet-version: '7.0.x' - name: Restore dependencies run: dotnet restore - name: Build run: dotnet build --configuration Release --no-restore - name: Test run: dotnet test --no-restore --verbosity normal - name: Publish run: dotnet publish -c Release -o publish - name: Deploy to Azure Web Apps uses: azure/webapps-deploy@v2 with: app-name: 'myapp-production' publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} package: ./publish
環境別の設定ファイル
シークレット管理
環境変数の活用
モニタリングとログの実装
Application Insightsの詳細設定
public void ConfigureServices(IServiceCollection services) { // Application Insightsの高度な設定 services.AddApplicationInsightsTelemetry(options => { options.EnableAdaptiveSampling = true; options.EnableQuickPulseMetricStream = true; options.EnableDebugLogger = false; options.EnableHeartbeat = true; }); // カスタムテレメトリの設定 services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>(); } public class CustomTelemetryInitializer : ITelemetryInitializer { public void Initialize(ITelemetry telemetry) { telemetry.Context.Cloud.RoleName = "MyWebApp"; telemetry.Context.Component.Version = "1.0.0"; if (telemetry is RequestTelemetry request) { request.Properties["CustomProperty"] = "CustomValue"; } } }
構造化ログの実装
public class LoggingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<LoggingMiddleware> _logger; public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { try { var startTime = DateTime.UtcNow; // リクエスト情報のログ _logger.LogInformation( "Request {Method} {Path} started at {StartTime}", context.Request.Method, context.Request.Path, startTime); await _next(context); // レスポンス情報のログ var duration = DateTime.UtcNow - startTime; _logger.LogInformation( "Request completed with status {StatusCode} in {Duration}ms", context.Response.StatusCode, duration.TotalMilliseconds); } catch (Exception ex) { _logger.LogError( ex, "Request failed with error: {ErrorMessage}", ex.Message); throw; } } }
カスタムメトリクスの実装
public class MetricsService { private readonly TelemetryClient _telemetryClient; private readonly ILogger<MetricsService> _logger; public MetricsService(TelemetryClient telemetryClient, ILogger<MetricsService> logger) { _telemetryClient = telemetryClient; _logger = logger; } public void TrackDatabaseOperation(string operation, TimeSpan duration, bool success) { _telemetryClient.TrackMetric(new MetricTelemetry { Name = $"Database.{operation}.Duration", Value = duration.TotalMilliseconds }); _telemetryClient.TrackEvent($"Database.{operation}", new Dictionary<string, string> { ["Success"] = success.ToString(), ["Duration"] = duration.TotalMilliseconds.ToString() }); } }
これらの実装により、以下のような利点が得られます:
リアルタイムのパフォーマンス監視
異常検知の自動化
詳細なログ分析が可能
カスタムメトリクスによる業務指標の追跡
ロールバック戦略の実装
ブルー/グリーンデプロイメントの設定(Azure Pipelines)
stages: - stage: Deploy jobs: - deployment: Deploy environment: production strategy: blueGreen: # プレプロダクションスロットへのデプロイ - task: AzureWebApp@1 inputs: azureSubscription: '$(azureSubscription)' appName: '$(webAppName)' slotName: 'staging' package: '$(Pipeline.Workspace)/drop/**/*.zip' # テストの実行 - task: PowerShell@2 inputs: targetType: 'inline' script: | $statusCode = (Invoke-WebRequest -Uri "https://$(webAppName)-staging.azurewebsites.net/health").StatusCode if ($statusCode -ne 200) { throw "Health check failed" } # トラフィックの切り替え - task: AzureAppServiceManage@0 inputs: azureSubscription: '$(azureSubscription)' action: 'Swap Slot' webAppName: '$(webAppName)' sourceSlot: 'staging' targetSlot: 'production'
カナリアリリースの実装
public class CanaryRoutingMiddleware { private readonly RequestDelegate _next; private const double CanaryPercentage = 0.1; // 10%のトラフィック public async Task InvokeAsync(HttpContext context) { var random = new Random(); var isCanary = random.NextDouble() < CanaryPercentage; if (isCanary) { context.Request.Headers["X-Version"] = "canary"; // カナリアバージョンへルーティング await RouteToCanary(context); } else { await _next(context); } } }
自動ロールバックの監視設定
public class HealthMonitorService : BackgroundService { private readonly ILogger<HealthMonitorService> _logger; private readonly IDeploymentService _deploymentService; private int _failureCount = 0; private const int FailureThreshold = 3; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { var isHealthy = await CheckApplicationHealth(); if (!isHealthy) { _failureCount++; _logger.LogWarning("Health check failed. Failure count: {Count}", _failureCount); if (_failureCount >= FailureThreshold) { _logger.LogError("Health check threshold exceeded. Initiating rollback..."); await _deploymentService.RollbackToLastKnownGoodVersion(); } } else { _failureCount = 0; } await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); } } private async Task<bool> CheckApplicationHealth() { try { // アプリケーションの健全性チェック // - API エンドポイントの応答確認 // - データベース接続の確認 // - 重要な依存サービスの状態確認 return true; } catch (Exception ex) { _logger.LogError(ex, "Health check failed"); return false; } } }
これらの実装により、以下のような利点が得られます:
無停止でのバージョン切り替え
段階的なトラフィック移行
自動化された障害検知と復旧
リスクを最小限に抑えたデプロイメント
これらの実装により、効率的で安全なデプロイメントプロセスを確立できます。
最後に
ASP.NET Coreは、モダンなWeb開発における強力なフレームワークとして、高いパフォーマンスとセキュリティ、優れた拡張性を提供します。基本的な概念から実践的な実装手法まで、本記事で解説した内容を活用することで、効率的で堅牢なWebアプリケーション開発が可能となります。継続的な学習と実践を通じて、ASP.NET Coreの真価を発揮させましょう。