# .NET Ayarlarınızı Yönetmenin Modern ve Güvenli Yolu: Options Pattern

Uygulamalarımızın can damarı olan yapılandırma (configuration) ayarlarını nasıl yönetiyorsunuz? Veritabanı bağlantıları, API anahtarları, servis adresleri... Bu değerli bilgileri kodun içine gömmek (hard-coding) kabul edilemez. Peki bu ayarları yönetmenin en doğru, en modern ve en **güvenli** yolu nedir?

Cevap, .NET'in bize sunduğu zarif bir desende gizli: **Options Pattern**.

Bu yazıda, .NET 9'da Options Pattern'i sıfırdan ele alacağız. Sadece nasıl çalıştığını değil, aynı zamanda ayarlarımızı daha en başından nasıl doğrulanabilir ve kurşun geçirmez hale getirebileceğimizi bolca örnekle öğreneceğiz. Arkanıza yaslanın, çünkü `appsettings.json` karmaşasına son veriyoruz!

### Neden Options Pattern'e İhtiyacımız Var?

Eski yöntemleri hatırlayalım: Kod içinde sihirli string'ler (`configuration["Smtp:Server"]`), tip dönüşümüyle uğraşma, test yazmanın zorluğu... Bunların hepsi hem hata yapmaya çok açık hem de kod kalitesini düşüren alışkanlıklardı.

Options Pattern bu sorunları kökünden çözer:

* **Güçlü Tip Desteği (Strongly-Typed):** String'lerle değil, bildiğiniz C# nesneleriyle (POCO) çalışırsınız.
    
* **Merkezi Yönetim:** Ayarlarınız tek bir yerden yönetilir ve uygulamanın her yerine kolayca dağıtılır.
    
* **Test Edilebilirlik:** Ayarlarınızı taklit etmek (mock) ve testler yazmak çocuk oyuncağı haline gelir.
    
* **Güvenilirlik:** Ayarlarınızı uygulama başlarken doğrulayarak (validate) hataları anında yakalarsınız.
    

Hadi modern bir .NET projesinde bu deseni nasıl uygulayacağımıza bakalım.

### Adım Adım Modern Options Pattern Kullanımı

Senaryomuz basit: Uygulamamızın bir e-posta gönderme özelliği var ve SMTP ayarlarını `appsettings.json` dosyasından güvenli bir şekilde okumak istiyoruz.

#### Adım 1: `appsettings.json` Dosyasını Hazırlama

Her şeyin başladığı yer! Projenizin `appsettings.json` dosyasına ayarlarımızı ekleyelim.

```bash
{
  "Logging": {
    // ...
  },
  "AllowedHosts": "*",
  "SmtpSettings": {
    "Server": "smtp.example.com",
    "Port": 587,
    "Username": "user@example.com",
    "Password": "gizli-bir-sifre",
    "EnableSsl": true
  }
}
```

Burada `SmtpSettings` adında, sınıfımızın (class) adıyla aynı olacak şekilde bir bölüm oluşturduk. Bu isimlendirme standardı birazdan çok işimize yarayacak.

#### Adım 2: Ayar Sınıfını (POCO) ve Kurallarını Tanımlama

Şimdi JSON yapısıyla eşleşen ve **doğrulama kurallarını içeren** C# sınıfımızı oluşturalım. `System.ComponentModel.DataAnnotations` kütüphanesinden gelen attribute'ları burada kullanacağız.

```csharp
// Models/SmtpSettings.cs

using System.ComponentModel.DataAnnotations;

public class SmtpSettings
{
    [Required(ErrorMessage = "SMTP Sunucusu boş olamaz.")]
    public string Server { get; set; }

    [Range(1, 65535, ErrorMessage = "Port numarası 1 ile 65535 arasında olmalıdır.")]
    public int Port { get; set; }

    [Required]
    [EmailAddress]
    public string Username { get; set; }

    [Required]
    [MinLength(6)]
    public string Password { get; set; }

    public bool EnableSsl { get; set; }
}
```

Gördüğünüz gibi, sadece property'leri tanımlamakla kalmadık, aynı zamanda hangi alanın zorunlu olduğunu, hangisinin bir e-posta formatında olması gerektiğini de belirttik. Kuralları verinin kendisine en yakın yere koymuş olduk.

#### Adım 3: Servisleri Modern Yöntemle Konfigüre Etme (`Program.cs`)

İşte sihrin gerçekleştiği yer! .NET'e ayarlarımızı nasıl okuyacağını, bağlayacağını ve en önemlisi nasıl doğrulayacağını tek bir akıcı (fluent) kod bloğuyla söyleyeceğiz.

Projenizin `Program.cs` dosyasını açın ve aşağıdaki satırları ekleyin:

```csharp
// Program.cs

var builder = WebApplication.CreateBuilder(args);

// --- Options Pattern Yapılandırması ---
builder.Services.AddOptions<SmtpSettings>()
    .BindConfiguration(nameof(SmtpSettings))
    .ValidateDataAnnotations()
    .ValidateOnStart();
// -------------------------------------------

// Örnek bir servis ekleyelim
builder.Services.AddScoped<IEmailService, EmailService>();

// Kalan servisleriniz...

var app = builder.Build();

// ... (kalan kod)
```

Bu zincirleme yapı ne anlama geliyor? Tek tek inceleyelim:

* `.AddOptions<SmtpSettings>()`: Options Pattern sürecini başlatır ve `SmtpSettings` sınıfı için bir yapılandırma oluşturucu (OptionsBuilder) döndürür.
    
* `.BindConfiguration(nameof(SmtpSettings))`: En temiz kısım burası! `appsettings.json` dosyasında, sınıfın adıyla (`"SmtpSettings"`) eşleşen bölümü bulur ve tüm değerleri otomatik olarak `SmtpSettings` nesnesine bağlar. `nameof()` kullandığımız için "string" derdinden kurtuluruz.
    
* `.ValidateDataAnnotations()`: .NET'e "Az önce `SmtpSettings` sınıfında tanımladığım `[Required]`, `[Range]` gibi kuralları dikkate al!" der.
    
* `.ValidateOnStart()`: İşte bu bizim sigortamız! Uygulama başlar başlamaz, `ValidateDataAnnotations` ile belirtilen kuralları çalıştırır. Eğer ayarlarda herhangi bir kural ihlali varsa (örneğin `Port` değeri eksikse), uygulama **başlamadan çöker** ve size sorunun ne olduğunu açıkça söyleyen bir hata fırlatır.
    

#### Adım 4: Ayarları Kullanma (Dependency Injection)

Yapılandırmamız artık hazır ve güvenli. Şimdi onu bir serviste kullanalım.

```csharp
// Services/EmailService.cs

using Microsoft.Extensions.Options;

public interface IEmailService
{
    void SendEmail(string to, string subject, string body);
}

public class EmailService(IOptions<SmtpSettings> smtpSettings) : IEmailService
{
    // Primary constructor'dan gelen parametreyi kullanarak
    // sınıf içinde kullanacağımız private field'ı hemen burada başlatıyoruz.
    private readonly SmtpSettings _settings = smtpSettings.Value;

    public void SendEmail(string to, string subject, string body)
    {
        Console.WriteLine("E-posta gönderiliyor...");
        Console.WriteLine($"Server: {_smtpSettings.Server}:{_smtpSettings.Port}");
        Console.WriteLine($"Kullanıcı: {_smtpSettings.Username}");
        Console.WriteLine($"SSL Aktif: {_smtpSettings.EnableSsl}");
        // Burada e-posta gönderme kodu olacak.
    }
}
```

Gördüğünüz gibi, ayarları kullanma şeklimiz değişmedi. `EmailService`, ayarların nasıl okunduğundan veya doğrulandığından tamamen habersiz. O sadece `IOptions<SmtpSettings>` arayüzü üzerinden ihtiyacı olan geçerli ayarlara ulaşıyor.

### Peki Ayarlar Hatalıysa Ne Olur? `ValidateOnStart`'ın Gücü

Diyelim ki bir geliştirici `appsettings.json` dosyasından `Port` satırını sildi. Eğer `.ValidateOnStart()` kullanmasaydık, uygulamanız başarıyla başlar, ancak `SendEmail` metodu çağrıldığında `_smtpSettings.Port` değeri `0` olacağı için çalışma anında (runtime) bir hata alırdınız.

Ancak bizim modern yapılandırmamız sayesinde, uygulamayı başlattığınız anda konsolda şöyle bir hata görürsünüz:

```bash
Microsoft.Extensions.Options.OptionsValidationException: DataAnnotation validation failed for 'SmtpSettings' members: 'Port' with the error: 'Port numarası 1 ile 65535 arasında olmalıdır.'.
```

Bu "fail-fast" (hata anında dur) yaklaşımı, yapılandırma hatalarını anında yakalamanızı sağlayarak sizi production'da yaşanacak büyük sorunlardan kurtarır.

### `IOptions`, `IOptionsSnapshot` ve `IOptionsMonitor`

* `IOptions<T>` (Singleton): Ayarları uygulama başlarken bir kez okur.
    
* `IOptionsSnapshot<T>` (Scoped): Her HTTP isteği için ayarları yeniden okur. Web uygulamaları için harikadır.
    
* `IOptionsMonitor<T>` (Singleton): `appsettings.json` dosyasındaki değişiklikleri uygulama çalışırken bile anlık olarak algılar.
    

Kullanım senaryonuza göre constructor'ınıza bu arayüzlerden uygun olanı enjekte edebilirsiniz.

### Özet

.NET ile uygulama geliştirirken, ayarlarınızı yapılandırmak için `AddOptions()` ile başlayan bu akıcı ve güvenli yöntemi kullanmak en iyi pratiktir. Bu yöntem size şunları sağlar:

* **Okunabilirlik:** Zincirleme yapı, ayarların nasıl yüklendiğini ve doğrulandığını net bir şekilde anlatır.
    
* **Güvenlik:** `ValidateOnStart` ile hatalı yapılandırmaların uygulamanızı başlatmasını engellersiniz.
    
* **Bakım Kolaylığı:** `nameof()` kullanımı, "sihirli string" kaynaklı hataların önüne geçer.
    

Artık ayarlarınızı yönetirken endişelenmenize gerek yok. Bu modern yaklaşımı benimseyin ve daha sağlam, güvenilir ve bakımı kolay uygulamalar geliştirin.
