Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Cấu hình & Logging

appsettings.json

Cấu trúc cơ bản

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=MyDb;Trusted_Connection=true;"
  },
  "AppSettings": {
    "MaxItemsPerPage": 50,
    "EnableCache": true
  }
}

Environment-specific Configuration

appsettings.Development.json  // Development
appsettings.Staging.json      // Staging  
appsettings.Production.json   // Production
// Program.cs
var builder = WebApplication.CreateBuilder(args);

// Tự động load appsettings.{Environment}.json
// Development: appsettings.json + appsettings.Development.json

IConfiguration

Truy cập Configuration

public class Startup
{
    public IConfiguration Configuration { get; }
    
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    
    public void ConfigureServices(IServiceCollection services)
    {
        // Cách 1: GetValue
        var maxItems = Configuration.GetValue<int>("AppSettings:MaxItemsPerPage", 10);
        
        // Cách 2: GetSection
        var appSettings = Configuration.GetSection("AppSettings").Get<AppSettings>();
        
        // Cách 3: Bind to object
        services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
    }
}

Options Pattern (IOptions)

// Model class
public class AppSettings
{
    public int MaxItemsPerPage { get; set; } = 10;
    public bool EnableCache { get; set; }
    public EmailSettings Email { get; set; }
}

public class EmailSettings
{
    public string SmtpHost { get; set; }
    public int SmtpPort { get; set; }
}

// Đăng ký
builder.Services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

// Sử dụng
public class ProductService
{
    private readonly AppSettings _settings;
    
    public ProductService(IOptions<AppSettings> options)
    {
        _settings = options.Value;
    }
    
    public int GetPageSize() => _settings.MaxItemsPerPage;
}

IOptions vs IOptionsSnapshot vs IOptionsMonitor

// IOptions - Đọc config một lần khi app khởi động
// Singleton services nên dùng cái này

// IOptionsSnapshot - Đọc lại config mỗi request
// Scoped services nên dùng cái này để có config mới nhất
builder.Services.AddScoped<IOptionsSnapshot<AppSettings>>();

// IOptionsMonitor - Theo dõi thay đổi config real-time
// Dùng cho hot-reload configuration
builder.Services.AddSingleton<IOptionsMonitor<AppSettings>>();

Serilog Logging

Cài đặt

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File

Cấu hình cơ bản

// Program.cs
using Serilog;

var builder = WebApplication.CreateBuilder(args);

// Configure Serilog
Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
    .MinimumLevel.Override("System", LogEventLevel.Warning)
    .Enrich.FromLogContext()
    .Enrich.WithProperty("Application", "MyApp")
    .WriteTo.Console(outputTemplate: 
        "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}")
    .WriteTo.File(
        "logs/log-.txt",
        rollingInterval: RollingInterval.Day,
        retainedFileCountLimit: 30,
        outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}")
    .CreateLogger();

builder.Host.UseSerilog();

var app = builder.Build();

// Sử dụng
Log.Information("Application starting");

app.Run();

// Flush log trước khi exit
Log.CloseAndFlush();

Structured Logging

public class ProductService
{
    private readonly ILogger<ProductService> _logger;
    
    public ProductService(ILogger<ProductService> logger)
    {
        _logger = logger;
    }
    
    public void GetProduct(int id)
    {
        // ✅ Structured logging - dễ query và filter
        _logger.LogInformation("Fetching product {ProductId} for user {UserId}", 
            id, 
            _userId);
        
        // ❌ String interpolation - tránh dùng
        _logger.LogInformation($"Fetching product {id}");
    }
}

Log Levels

LevelUsage
VerboseDetailed tracing
DebugDebugging information
InformationGeneral information
WarningSomething unexpected happened
ErrorFunctionality issue
FatalCritical error causing shutdown

Best Practices

1. Sử dụng correct log levels

// ✅ Correct
Log.Debug("Processing request {RequestId}", requestId);
Log.Information("Product {ProductId} created successfully", productId);
Log.Warning("Cache miss for key {CacheKey}", key);
Log.Error(ex, "Failed to process order {OrderId}", orderId);
Log.Fatal(ex, "Application terminating due to unhandled exception");

2. Include context

public async Task<IActionResult> UpdateProduct(int id, [FromBody] Product product)
{
    Log.LogInformation(
        "Updating product {ProductId} by user {UserId}", 
        id, 
        User.Identity.Name);
        
    // ... code
}

3. Tránh logging sensitive data

// ❌ Bad - Log sensitive data
Log.Information("User login: {Email}, Password: {Password}", email, password);

// ✅ Good - Log masked data
Log.Information("User login attempt for {Email}", email);