asp.net core / validasyon / iş kuralları·4 dk okuma

.net api’niz hatalı bir isteğe ne söylüyor?

asp.net core ile giriş doğrulama, iş kuralları ve problem details yanıtlarını küçük bir fiyat hesaplama örneği üzerinden öğrenin.

bir form düşünün: kullanıcı ürün adedini giriyor, indirim oranını seçiyor ve hesapla düğmesine basıyor. her şey doğru doldurulduğunda toplamı bulmak kolay. asıl soru, adet boş bırakıldığında ya da iki alan birlikte geçersiz bir sonuç oluşturduğunda ne olacağı. iyi bir backend, bu durumda istemciyi tahmin yürütmeye zorlamaz; hangi bilginin neden kabul edilmediğini anlatır.

güncellendi:

istek doğrulaması: geçersiz istek 400 problem details, geçerli istek 200 döner.
bu yazıda01/06

01önce isteğin sınırını çizelim

örneğimiz, tek bir asp.net core uygulamasında çalışan fiyat önizleme endpoint’i. ürünün birim fiyatı sunucuda 100 tl; istemci yalnızca adet ve indirim yüzdesini gönderiyor. henüz sipariş oluşturmuyor, ödeme almıyor veya veri kaydetmiyoruz. böylece bir isteğin kabul edilip edilmeyeceğine odaklanabiliriz.

ilk kuralımız basit: adet 1–100 arasında, indirim 0–50 arasında olmalı ve iki alan da gönderilmeli. ikinci kural ise alanların ilişkisiyle ilgili: 10 adetten az ürün için yüzde 20’den fazla indirim uygulanamaz. ilk grubu istek modelinde, ikinciyi hesaplama öncesinde kontrol edeceğiz. bu ayrım, kuralları okuyan kişinin neyin eksik veri, neyin iş kararı olduğunu anlamasını sağlar.

02çalıştırabileceğiniz küçük bir örnek

.net 10 sdk ile “dotnet new web -n ValidationDemo” komutunu çalıştırın. oluşan program.cs dosyasını aşağıdaki kodla değiştirin. ardından proje klasöründe “dotnet run --no-launch-profile --urls http://localhost:5080” komutunu kullanın. kod bloğunda c# büyük/küçük harf düzeni özellikle korunmuştur.

bu örnek controller tabanlıdır. [ApiController], model bağlama veya doğrulama başarısız olduğunda action çalışmadan 400 yanıtı üretir. [Required] ile birlikte nullable sayılar kullanmamızın nedeni, gönderilmeyen bir alanı sıfırdan ayırmaktır. özellikle indirim için sıfır geçerli bir değerdir; eksik bilgiyle aynı anlama gelmez.

program.cs · c# / .net 10
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();

var app = builder.Build();
app.UseExceptionHandler();
app.MapControllers();
app.Run();

public sealed class QuoteRequest
{
    [Required]
    [Range(1, 100)]
    public int? Quantity { get; init; }

    [Required]
    [Range(typeof(decimal), "0", "50")]
    public decimal? DiscountPercent { get; init; }
}

[ApiController]
[Route("api/quotes")]
public sealed class QuotesController : ControllerBase
{
    [HttpPost("preview")]
    public IActionResult Preview(QuoteRequest request)
    {
        var quantity = request.Quantity!.Value;
        var discount = request.DiscountPercent!.Value;

        if (quantity < 10 && discount > 20m)
        {
            ModelState.AddModelError(
                nameof(request.DiscountPercent),
                "Orders below 10 items allow at most 20% discount.");
            return ValidationProblem(ModelState);
        }

        const decimal unitPrice = 100m;
        var total = decimal.Round(
            quantity * unitPrice * (1 - discount / 100m),
            2, MidpointRounding.AwayFromZero);

        return Ok(new { total, currency = "TRY" });
    }
}

03alanlar geçerli olsa da istek yanlış olabilir

adet 2 ve indirim 30 olduğunda iki değer de kendi aralığındadır. fakat birlikte iş kuralını ihlal ederler. bu yüzden yalnızca attribute eklemek yeterli değildir. örnekte bu ilişkiyi açık bir koşulla kontrol ediyor, hatayı ilgili alana bağlıyor ve ValidationProblem ile dönüyoruz. istemci böylece indirim alanının yanında bir açıklama gösterebilir.

bu küçük örnekte kuralı controller içinde görmek akışı takip etmeyi kolaylaştırır. aynı hesaplama başka bir giriş noktasından da çağrılmaya başladığında kuralı ortak bir uygulama veya domain bileşenine taşımak gerekir. http yanıtına dönüştürme işi controller’da kalabilir. doğrulama, yetkilendirmenin yerini de tutmaz: gerçek bir satış uygulaması, kullanıcının indirim yapma yetkisini ve geçerli fiyatı ayrıca sunucuda doğrulamalıdır.

04hatayı istemcinin anlayacağı biçimde dönelim

problem details, hata yanıtları için ortak bir yapı sunar. status http durumunu, title kısa hata özetini, detail ise varsa bu olaya özgü açıklamayı taşır. doğrulama yanıtındaki errors uzantısı, alanlarla hata mesajlarını eşleştirir. bütün alanların her yanıtta bulunacağını varsaymak yerine, istemcinin ihtiyaç duyduğu sözleşmeyi belirlemek gerekir.

bu örnekte hem aralık hataları hem de indirim kuralı 400 döner. bu, seçtiğimiz api sözleşmesidir; her iş hatasının daima 400 olması gerektiği anlamına gelmez. başarılı hesaplama ise 200 döner. istemcide yalnızca mesaj metnine göre karar vermeyin; metin değişebilir veya çevrilebilir. durum kodunu ve alan anahtarlarını kullanın; farklı iş hatalarını ayırmanız gerekiyorsa belgelenmiş, sabit hata kodları ekleyin.

beklenmeyen bir hata için her action’a geniş bir try/catch koymak yerine merkezi hata işleyicisini kullanıyoruz. AddProblemDetails ve UseExceptionHandler bu temel kurulumu sağlar. kullanıcıya exception mesajı, bağlantı bilgisi veya stack trace göndermeyin. sunucu tarafında isteği ilişkilendirebilen kayıtlar tutun; parola, token ve tüm istek gövdesini gelişigüzel loglamayın.

05yalnızca doğru isteği denemek yetmez

aşağıdaki isteği .http dosyası destekleyen bir editörden gönderebilirsiniz. 2 adet ve yüzde 10 indirim için toplam 180 tl olur. para hesabında decimal kullanıyoruz; yuvarlamayı iki basamak ve AwayFromZero olarak açıkça seçiyoruz. gerçek bir uygulamada para birimi ve yuvarlama kuralı ayrıca iş gereksinimi olarak belirlenmelidir.

request.http
POST http://localhost:5080/api/quotes/preview
Content-Type: application/json
Accept: application/json

{ "quantity": 2, "discountPercent": 10 }

06sınır değerler bize ne anlatıyor?

önce boş bir json nesnesi gönderin: zorunlu alanlar için 400 bekleyin. ardından adedi 0 yapın; aralık kontrolü devreye girmeli. adet 2 ve indirim 30 iken iş kuralı 400 üretmeli; adet 10 ve indirim 30 iken toplam 700 tl ve durum 200 olmalı. indirim 0 ise geçerli kabul edilmeli. bunlar birbirine benzese de farklı davranışları sınar.

otomatik test yazarken gerçek http hattını da çalıştırın. controller metodunu doğrudan çağırmak, [ApiController] filtresinin davranışını kanıtlamaz. durum kodunu, yanıtın alanlarını ve hesaplanan sonucu kontrol edin. bir hata mesajındaki noktalama değişikliğini, iş kuralının bozulmasıyla karıştırmayın.

bir sonraki endpoint’i yazarken önce üç soruyu cevaplamak işinizi kolaylaştırır: hangi veri zorunlu, hangi değerler birlikte geçersiz ve istemci bu hatayı nasıl düzeltecek? bunları netleştirdiğinizde doğrulama kodu rastgele if blokları olmaktan çıkar; api’nin anlaşılır bir parçasına dönüşür.

okuduğunuz için teşekkürler← tüm yazılar

bu konuda uygulama desteği

mevcut .net uygulamanız için kod incelemesi, hata giderme ve performans danışmanlığı kapsamını inceleyebilirsiniz.

.net danışmanlığı