TB
← Tüm yazılar

Cok katmanli .NET cozumleri

Enterprise .NET uygulamalarinda katmanli mimari, proje sınırları, bağımlılık yonu ve pratik çözüm organizasyonu uzerine kapsamlı bir rehber.

Kurumsal .NET cozumlerinde katmanli mimari, sorumluluklari ayirarak kodun test edilebilirligini ve ekip olceklenebilirligini artirir. Presentation, application, domain ve infrastructure katmanları arasindaki bağımlılık yonu iceriden disariya doğrudur: domain hicbir altyapi detayina bağımlı olmamali, UI dogrudan veritabanına erişmemelidir. Bu makale, Visual Studio solution organizasyonundan pratik proje sinirlarina kadar cok katmanli yapinin nasil insa edilecegini inceler.

Katmanlar ve sorumluluklar

Klasik dört katman modeli su şekilde ozetlenir:

  • Presentation (Web/API): HTTP, routing, authentication, request/response modeli.
  • Application: Use case orchestration, transaction sınırları, DTO mapping, validation pipeline.
  • Domain: Is kurallari, entity, value object, domain event, repository arayuzleri.
  • Infrastructure: EF Core, dis API istemcileri, e-posta, cache, dosya sistemi implementasyonlari.

Bağımlılık kurali: Infrastructure → Application → Domain. Presentation → Application. Domain kimseyi tanimaz.

Solution ve proje yapisi

Tipik bir solution duzeni:

MyShop.sln
  src/
    MyShop.Domain/
    MyShop.Application/
    MyShop.Infrastructure/
    MyShop.Api/
  tests/
    MyShop.Domain.Tests/
    MyShop.Application.Tests/
    MyShop.Integration.Tests/

Her proje tek bir katmanı temsil eder. Shared kernel gerekiyorsa ayri bir MyShop.Contracts veya BuildingBlocks projesi oluşturulur; ancak "common" projesi hizla cop kutusuna donmemek icin siki tutulmalidir.

Application katmanı ve Mediator

Application katmaninda command/query handler'lar is akisini yönetir. Mediator deseni (MediatR) handler'lari loose coupling ile baglar:

public record CreateOrderCommand(int CustomerId, IReadOnlyList<LineItem> Lines) : IRequest<int>;

public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, int>
{
    private readonly IOrderRepository _orders;
    private readonly IUnitOfWork _uow;

    public async Task<int> Handle(CreateOrderCommand request, CancellationToken ct)
    {
        var order = Order.Create(request.CustomerId, request.Lines);
        await _orders.AddAsync(order, ct);
        await _uow.SaveChangesAsync(ct);
        return order.Id;
    }
}

Controller veya minimal API endpoint sadece Mediator'a delegasyon yapar; is mantigi application ve domain'de kalir.

Domain katmanı safligi

Domain projesinde NuGet referansi minimum tutulur: genelde sadece analizor veya hafif kutuphaneler. EF attribute'lari domain entity'lerine konmamali; persistence ignorance ilkesi korunur. Repository arayüzü domain'de tanimlanir:

public interface IOrderRepository
{
    Task<Order?> GetByIdAsync(int id, CancellationToken ct);
    Task AddAsync(Order order, CancellationToken ct);
}

Implementasyon Infrastructure'da EF Core ile yazilir.

Infrastructure ve DI kayitlari

Tüm somut implementasyonlar ve DbContext kayitlari Infrastructure'da toplanir:

public static class DependencyInjection
{
    public static IServiceCollection AddInfrastructure(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        services.AddDbContext<AppDbContext>(options =>
            options.UseSqlServer(configuration.GetConnectionString("Default")));
        services.AddScoped<IOrderRepository, OrderRepository>();
        services.AddScoped<IUnitOfWork, UnitOfWork>();
        return services;
    }
}

Api projesinde tek satir: builder.Services.AddInfrastructure(builder.Configuration);

DTO ve mapping

API modelleri ile domain modelleri karistirilmamali. Mapster veya manuel extension metodlari Application veya Api'de kullanılır. AutoMapper büyük cozumlerde profil yönetimini kolaylastirir; küçük projelerde explicit mapping daha okunabilir olabilir.

Capraz kesen endiseler

Logging, caching, validation pipeline gibi endiseler katman sinirlarini ihlal etmeden uygulanir:

  • Validation: FluentValidation handler oncesi MediatR pipeline behavior.
  • Logging: Application'da behavior veya decorator.
  • Authorization: API katmaninda attribute; fine-grained kurallar application'da.

Test piramidi ve katmanlar

Domain birim testleri hızlı ve bagimsizdir. Application testleri repository fake'leri ile handler davranisini dogrular. Integration testleri Infrastructure ile gerçek veritabanı (Testcontainers) kullanır. Api testleri WebApplicationFactory ile HTTP contract'i test eder. Katman ayrimi, her seviyede uygun test aracinin secilmesini kolaylastirir.

Moduler monolit ve bounded context

Tek solution icinde birden fazla bounded context varsa proje prefix'leri kullanılır: Ordering.Domain, Catalog.Domain. Context'ler arasi iletişim domain event veya integration event ile yapilir; dogrudan baska context'in repository'sine erişim anti-pattern'dir.

Versioning ve paket yönetimi

Central Package Management (Directory.Packages.props) tüm projelerde NuGet surumlerini senkron tutar. Analyzers ve StyleCop kurallari Directory.Build.props ile solution geneline uygulanir. Tutarlı nullable reference type ayarlari proje referans hatalarini erken yakalar.

Yaygın hatalar

  • Anemic domain: Tüm mantık service siniflarinda; entity sadece property cantasi.
  • Domain'de EF referansi: Katman ihlali ve test zorlugu.
  • Controller'da is mantigi: Tekrar kullanılamaz ve test edilemez kod.
  • Asiri common projesi: Her sey Common'a tasinir; bağımlılık grafigi anlamsizlasir.
  • Circular reference: Proje referans dongusu derlemeyi imkansiz kilar; arayuzleri Domain'e tasiyin.

Microservice gecisi

Moduler monolit doğru sinirlarla baslarsa, ileride context bazli servis ayirma daha az acili hasarla yapilir. Application ve Infrastructure zaten ayri oldugundan, extract edilecek context'in Api ve veritabanı birlikte tasinmasi yeterli olabilir. Erken asamada mikroservis parcalamasi genelde gereksiz operasyonel yük getirir.

Özet

Cok katmanli .NET cozumleri, bağımlılık yonu ve proje sınırları net oldugunda uzun omurlu ve ekip dostu codebase üretir. Domain safligi, application orchestration, infrastructure implementasyonu ve ince presentation katmanı birlikte çalışır. Mediator, DI extension metodlari ve test piramidi bu yapinin gunluk uygulamasini pratiklestirir; anti-pattern'lerden kacinmak ise mimarinin kagit uzerinde kalmasini degil gercekten islemesini sağlar.

Shared kernel ve integration events

Context'ler arasi paylasilan value object'ler dikkatle sinirlandirilir. Integration event contract'lari ayri bir NuGet paketi veya git submodule olabilir; breaking change surumlemesi SemVer ile yönetilir. Outbox pattern ile event gonderimi ve veritabanı yazimi ayni transaction'da tutulur.

Vertical slice alternatifi

Bazi ekipler katman yerine feature klasoru tercih eder: Orders/CreateOrder handler, validator ve endpoint ayni slice icinde. Clean Architecture prensipleri korunabilir; önemli olan bağımlılık yonunun ihlal edilmemesidir. Büyük ekiplerde hibrit model (katman + feature folder) yaygindir.

CI/CD ve katman bazli build

Path filter ile sadece değişen projelerin derlenmesi monorepo'da sure kazandirir. Domain degismediyse sadece etkilenen test projeleri calistirilir. Solution filter (.slnf) büyük codebase'lerde geliştirici deneyimini iyilestirir.

Documentation ve onboarding

Yeni geliştiriciler icin katman diyagrami ve bağımlılık grafigi README'de tutulmalidir. Architecture decision record (ADR) ile katman ihlali kararlari belgelenir. Code review checklist'te 'domain'de infrastructure referansi var mi' sorusu standart olmalidir.

Assembly referans kurallari

Domain projesi hicbir diger katman projesine referans vermemelidir. Application yalnizca Domain'e referans verir. Infrastructure Application ve Domain'e referans verir. Api Presentation olarak Application ve Infrastructure extension'larini cagirir; dogrudan Infrastructure concrete siniflarina bağımlı olmamali, sadece DI extension uzerinden kayıt yapilmalidir.

Cross-cutting pipeline behavior

MediatR IPipelineBehavior ile validation, logging, transaction ve caching sirali uygulanir. Behavior sırası kayıt sirasina baglidir; validation her zaman handler'dan once gelmelidir. Open generic behavior tüm request tiplerine uygulanir.

GlobalUsings ve proje sablonlari

GlobalUsings.cs tekrarlayan using'leri azaltir. Solution template veya dotnet new template ile yeni projeler ayni katman yapisinda acilir; ekip tutarlılığı artar. EditorConfig ve analyzer ruleset tüm solution'a uygulanir.

Packaging ve internal NuGet

Domain ve Application paketleri internal NuGet feed'e publish edilebilir; baska çözümler ayni domain'i tuketir. Public API surface dikkatle yönetilir; breaking change SemVer major bump gerektirir. Source Link debug deneyimini iyilestirir.

ASP.NET Core ve modern C# ekosisteminde katmanli tasarım, test edilebilirlik ve operasyonel gozlemlenebilirlik birlikte dusunuldugunde uzun omurlu yazılım urunleri ortaya cikar.