• 4.09.2026 21:23:33
  • Admin Admin

ASP.NET Core uygulamalarında ProblemDetails tabanlı, sürümlenebilir hata sözleşmesi kurun. Bu asp.net core eğitimi rehberi; exception mapping, doğrulama hataları, traceId ve entegrasyon testlerini somut örneklerle ele alır.

ASP.NET Core Eğitimi: ProblemDetails ile Hata Sözleşmesi Tasarımı

ASP.NET Core Eğitimi ile hata sözleşmesini HTTP'den türetin

Hata gövdesini exception sınıfının `Message` alanından üretmek, istemciyi uygulamanın iç detayına bağlar. Bunun yerine HTTP semantiğini sözleşmenin merkezi yapın: geçersiz istek için 400, kimliği doğrulanmamış istek için 401, yetkisiz erişim için 403, bulunamayan kaynak için 404, iş kuralı ihlali için 409 veya 422 kullanın. `application/problem+json` medyası ve RFC 9457 Problem Details alanları (`type`, `title`, `status`, `detail`, `instance`) istemcinin hata türünü metin eşleştirmeden ayırmasını sağlar. Örneğin mobil istemci `type` URI'sine göre yeniden deneme, kullanıcı mesajı veya form alanı işaretleme davranışı seçebilir.

GET /orders/6ec0d0e7-19d7-4a0f-aac8-0d6c7f86cb76 HTTP/1.1
Accept: application/problem+json

HTTP/1.1 404 Not Found
Content-Type: application/problem+json

{
  "type": "https://api.example.com/problems/order-not-found",
  "title": "Sipariş bulunamadı",
  "status": 404,
  "detail": "İstenen sipariş mevcut değil.",
  "instance": "/orders/6ec0d0e7-19d7-4a0f-aac8-0d6c7f86cb76",
  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00"
}

Sözleşmede `detail` alanını kullanıcıya gösterilebilir, kararlı metin kabul etmeyin. Lokalizasyon, A/B metin değişiklikleri veya güvenlik nedeniyle ayrıntı seviyesini değiştirmek gerektiğinde istemci kırılır. İstemcinin karar vermesi için sabit bir `type` URI'si veya örneğin `extensions.code = "ORDER_NOT_FOUND"` kullanın. `traceId` ise destek ekibinin log korelasyonu içindir; PII, SQL hata metni, connection string veya stack trace taşımamalıdır. Bu ayrım, csharp eğitimi sırasında sık görülen `catch (Exception ex) { return BadRequest(ex.Message); }` kalıbının üretimde neden riskli olduğunu da açıklar.

.NET Core eğitimi: IExceptionHandler ile merkezi ProblemDetails üretimi

Controller, Minimal API ve middleware zincirinde aynı exception'ı farklı formatta döndürmemek için `IExceptionHandler` kullanın. Handler, response başladıktan sonra gövdeyi değiştiremez; bu nedenle streaming endpoint'lerinde veya response'a erken yazan middleware'lerde exception yakalamak yalnızca log üretir. Kritik endpoint'lerde `HttpResponse.HasStarted` durumunu test edip hata cevabı yazmayı atlamak gerekir.

using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;

public sealed class ApiExceptionHandler(
    IProblemDetailsService problemDetails,
    ILogger<ApiExceptionHandler> logger) : IExceptionHandler
{
    public async ValueTask<bool> TryHandleAsync(
        HttpContext context,
        Exception exception,
        CancellationToken cancellationToken)
    {
        var (status, type, title) = exception switch
        {
            OrderNotFoundException => (StatusCodes.Status404NotFound,
                "https://api.example.com/problems/order-not-found", "Sipariş bulunamadı"),
            DuplicateOrderException => (StatusCodes.Status409Conflict,
                "https://api.example.com/problems/duplicate-order", "Çakışan sipariş"),
            DomainValidationException => (StatusCodes.Status422UnprocessableEntity,
                "https://api.example.com/problems/domain-validation", "İş kuralı ihlali"),
            _ => (StatusCodes.Status500InternalServerError,
                "https://api.example.com/problems/internal-error", "Beklenmeyen hata")
        };

        logger.LogError(exception, "Request failed. TraceId: {TraceId}", context.TraceIdentifier);

        if (context.Response.HasStarted)
            return false;

        context.Response.StatusCode = status;
        return await problemDetails.TryWriteAsync(new ProblemDetailsContext
        {
            HttpContext = context,
            ProblemDetails = new ProblemDetails
            {
                Status = status,
                Type = type,
                Title = title,
                Detail = status == 500 ? null : exception.Message,
                Instance = context.Request.Path
            }
        });
    }
}

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails(options =>
{
    options.CustomizeProblemDetails = context =>
        context.ProblemDetails.Extensions["traceId"] = context.HttpContext.TraceIdentifier;
});
builder.Services.AddExceptionHandler<ApiExceptionHandler>();

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

`UseExceptionHandler()` çağrısını endpoint eşlemesinden önce kurun. Ayrıca `Detail = exception.Message` satırını yalnızca bilinen domain exception'ları için kullanın. Veritabanı sağlayıcısının exception'ı, `HttpRequestException` veya `InvalidOperationException` için `Message` alanı iç sistem topolojisini açığa çıkarabilir. Bu mekanizma, .net core kursu projelerinde hata yönetimini controller filtrelerine dağıtmak yerine tek bir denetlenebilir noktaya toplar.

C# eğitimi için doğrulama hatalarını alan bazında modelleyin

JSON sözdizimi bozuksa, zorunlu alan eksikse veya tür dönüşümü başarısızsa bu bir transport doğrulama hatasıdır ve `ValidationProblemDetails` ile 400 dönmelidir. Buna karşılık `deliveryDate` geçmişteyse veya sipariş limiti aşılmışsa istek JSON olarak geçerlidir ancak iş kuralını ihlal eder; bunu alan adı ve hata kodu içeren 422 yanıtıyla modellemek istemcinin form davranışını belirginleştirir. `errors` sözlüğünün anahtarlarını CLR property adı değil, API'nin dışarı açtığı JSON alan adı yapın.

public sealed record CreateOrderRequest(
    string CustomerId,
    DateOnly DeliveryDate,
    IReadOnlyList<CreateOrderLine> Lines);

public sealed record DomainViolation(string Field, string Code, string Message);

public sealed class DomainValidationException(
    IReadOnlyList<DomainViolation> violations) : Exception("İş kuralı doğrulaması başarısız.")
{
    public IReadOnlyList<DomainViolation> Violations { get; } = violations;
}

// Handler içinde DomainValidationException için ek alanlar:
var validation = (DomainValidationException)exception;
problem.Extensions["errors"] = validation.Violations
    .GroupBy(x => x.Field)
    .ToDictionary(
        x => x.Key,
        x => x.Select(v => new { v.Code, v.Message }).ToArray());

// Örnek hata anahtarı: "deliveryDate", CLR adı olan "DeliveryDate" değil.

Buradaki ince nokta, `Dictionary<string, string[]>` ile yalnızca metin taşımaktır. Metin değiştiğinde istemcinin davranışı değişmemeli; bu nedenle her ihlalde makinece okunabilir `Code` alanı bulunmalıdır. `ORDER_LIMIT_REACHED` kodu üzerinden kullanıcıya uygun mesaj gösterilebilir, telemetry etiketi eklenebilir ve istemci belirli bir aksiyonu devre dışı bırakabilir. c# kursu kapsamında record, pattern matching ve `GroupBy` öğretmek faydalıdır; ancak API sınırında bunların ürettiği JSON anahtarlarını açıkça test etmek daha önemlidir.

Entity Framework eğitimi bağlamında veritabanı hatalarını sızdırmadan eşleyin

Entity Framework Core'da unique index ihlalini doğrudan `DbUpdateException` türünden 409'a çevirmek hatalıdır. Aynı exception; foreign key ihlali, NOT NULL kısıtı, timeout veya bağlantı kesilmesiyle de gelebilir. Sağlayıcıya özgü iç exception kodunu yalnızca repository ya da persistence katmanında yorumlayın, ardından domain seviyesinde `DuplicateOrderException` fırlatın. SQL Server için `SqlException.Number` 2601 ve 2627, PostgreSQL için Npgsql `PostgresException.SqlState` 23505 unique ihlalini ifade eder.

try
{
    await dbContext.SaveChangesAsync(cancellationToken);
}
catch (DbUpdateException ex) when (
    ex.InnerException is Microsoft.Data.SqlClient.SqlException sql &&
    sql.Number is 2601 or 2627)
{
    throw new DuplicateOrderException(order.ExternalReference, ex);
}

// PostgreSQL kullanan bir persistence adapter'ında:
catch (DbUpdateException ex) when (
    ex.InnerException is Npgsql.PostgresException pg &&
    pg.SqlState == "23505")
{
    throw new DuplicateOrderException(order.ExternalReference, ex);
}

Constraint adına göre hata eşlemek istiyorsanız migration'da açık ve değişmez ad verin: `HasDatabaseName("ux_orders_external_reference")`. Otomatik üretilen constraint adları tablo veya kolon refactor'unda değişebilir; production kodunun string karşılaştırması sessizce devre dışı kalır. entity framework eğitimi içinde bu mapping'i provider bağımlılığı olarak ele almak, domain katmanının SQL Server veya PostgreSQL hata numaralarını tanımamasını sağlar.

ASP.NET Core hata sözleşmesini entegrasyon testiyle kilitleyin

Hata sözleşmesinin en değerli testi unit test değil, `WebApplicationFactory` ile çalışan HTTP pipeline testidir. Bu test `UseExceptionHandler`, JSON serializer ayarları, content type ve status code'u birlikte doğrular. Snapshot testi kullanılacaksa `traceId` gibi her istekte değişen alanları normalize edin; aksi halde test rastgele kırılır ve ekip snapshot onayını refleks haline getirir.

public sealed class OrderErrorsTests(ApiFactory factory)
    : IClassFixture<ApiFactory>
{
    [Fact]
    public async Task Missing_order_returns_contractual_problem_details()
    {
        var client = factory.CreateClient();

        var response = await client.GetAsync("/orders/00000000-0000-0000-0000-000000000001");
        var problem = await response.Content.ReadFromJsonAsync<ProblemDetails>();

        Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
        Assert.Equal("application/problem+json", response.Content.Headers.ContentType?.MediaType);
        Assert.Equal("https://api.example.com/problems/order-not-found", problem?.Type);
        Assert.Equal(404, problem?.Status);
    }
}

# CI adımı
dotnet test --configuration Release --logger "trx;LogFileName=api-contract.trx"

Sözleşmeyi tüketen bir Blazor istemciniz varsa `HttpResponseMessage.IsSuccessStatusCode` çağrısından önce content type kontrol edin. Proxy veya gateway'in HTML hata sayfası döndürdüğü durumda `ReadFromJsonAsync<ProblemDetails>` JSON parse exception üretir ve asıl upstream arızasını gizler. blazor eğitimi örneklerinde bu nedenle `application/problem+json` kontrolü yapıp bilinmeyen gövdeler için ayrı bir `UnexpectedHttpFailure` sonucu üretin. Bu pratik, microsoft teknolojileri eğitimi içinde API ve UI ekiplerinin hata sözleşmesini aynı test verisiyle paylaşmasına da imkan verir.

.NET Core kursu için uygulanabilir hata sözleşmesi kontrol listesi

Bir .net core eğitimi veya .net core kursu projesinde inceleme kriterini somutlaştırın: her 4xx/5xx yanıtında `Content-Type: application/problem+json` kontrolü, her bilinen domain hatasında sabit `type` URI'si, yalnızca 5xx için maskelenmiş `detail`, değişken `traceId` için log korelasyonu ve en az bir `WebApplicationFactory` kontrat testi bulunmalı. `curl -i -H "Accept: application/problem+json" https://localhost:5001/orders/missing` komutunu CI dışı smoke kontrolünde çalıştırmak, gateway'in content type dönüştürmesi gibi pipeline sorunlarını hızlıca görünür kılar.

csharp eğitimi ve c# eğitimi materyallerinde exception fırlatmanın kontrol akışı maliyetini de ayırın: beklenen form doğrulama hatasını exception ile taşımak yerine endpoint sınırında doğrulayın; benzersiz kayıt yarışı gibi gerçekten istisnai persistence çakışmasını ise exception mapping ile 409'a dönüştürün. csharp kursu veya c# kursu katılımcıları için ölçülebilir çıktı, her yeni hata türü eklendiğinde type URI'si, HTTP statüsü, istemci davranışı ve entegrasyon testi aynı pull request içinde yer almasıdır.

İlgili Eğitim

.NET Core Eğitimi

Sık Sorulan Sorular

ASP.NET Core eğitimi kapsamında ProblemDetails için 400 ve 422 nasıl ayrılır?

JSON parse hatası, eksik zorunlu alan veya sayısal alana metin gönderilmesi 400'dür; HTTP isteği temsil olarak geçerlidir ancak iş kuralı ihlali varsa 422 kullanın. Örneğin `deliveryDate` alanının geçmiş tarih olması için 422 ve `errors.deliveryDate[0].code = "DATE_IN_PAST"` döndürün.

Entity Framework eğitimi sırasında DbUpdateException neden doğrudan 409 dönmemeli?

DbUpdateException unique constraint dışında foreign key ihlali, timeout ve bağlantı hatalarını da sarar. İç exception'ı sağlayıcı koduyla ayırın: SQL Server'da 2601 veya 2627, PostgreSQL'de 23505 unique ihlalidir. Yalnız bu durumlarda domain exception üretip 409 döndürün.

C# eğitimi için IExceptionHandler mı yoksa controller exception filter mı seçilmeli?

Minimal API ve controller endpoint'lerini aynı sözleşmeyle yönetmek istiyorsanız `IExceptionHandler` tercih edin. Filter yalnızca MVC pipeline'ında çalışır. Handler'da `HttpResponse.HasStarted` kontrolü ekleyin; response başladıysa yeni bir ProblemDetails gövdesi yazmaya çalışmayın.

Blazor eğitimi projesinde ProblemDetails yanıtı nasıl tüketilir?

Önce `response.Content.Headers.ContentType?.MediaType` değerinin `application/problem+json` olduğunu doğrulayın, sonra `ReadFromJsonAsync()` çağırın. Content type HTML ise gateway veya proxy kaynaklı beklenmeyen hata olarak ele alın; JSON parse hatasını kullanıcı hatası gibi göstermeyin.

AI / LLM Discovery

Bu makale Opendart Akademi Microsoft / C# eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

Opendart Akademi llms.txt