# .NET / ABP Kod Standardı Bu doküman `api/` altındaki tüm projeler için bağlayıcıdır. Platform davranışına dair kurallar için `ai.instructions.md` esastır; çelişki olursa o dosya kazanır. Standart derlemede zorlanır: `api/Directory.Build.props` analizörleri açar, `api/.editorconfig` kural şiddetlerini tanımlar. Bu iki dosya standardın tek kaynağıdır; proje dosyalarında tekrar edilmez. ## 1. Hedef sürümler | Katman | Sürüm | Nerede tanımlı | | --- | --- | --- | | SDK | .NET 10 (`10.0.300`) | `api/global.json` | | TargetFramework | `net10.0` | proje dosyaları | | Dil | C# 14 (`LangVersion=latest`) | `api/common.props` | | ABP | 10.0.0 | `Volo.Abp.*` paket referansları | Sürüm yükseltmesi tek noktadan yapılır: `global.json` + `common.props` + paket sürümleri. Proje dosyalarına TFM/LangVersion tekrar yazılmaz. ## 2. Nullable `Directory.Build.props` içinde **çözüm geneli `Nullable` ayarı yapılmaz.** Sebebi EF Core: kolonun zorunlu olup olmadığını, entity assembly'sinin nullable annotation bağlamından türetir. Global bir `enable`/`annotations` anahtarı, bir sonraki `dotnet ef migrations add` çağrısında tüm `string` özelliklerini sessizce NOT NULL kolona çevirir — seeder'ın doldurmadığı her alan da o anda kırılır. Kural: - Nullable, proje bazında ve bilinçli olarak açılır (`enable`). Şu an açık olanlar: `Sozsoft.Platform.Application`, `Sozsoft.Notifications.*`, test projeleri. - **Entity taşıyan projelerde** (`*.Domain`) nullable açılacaksa, aynı PR'da `dotnet ef migrations add` çıktısı gözden geçirilir; şema değişikliği isteniyorsa kabul edilir, istenmiyorsa kolon zorunluluğu `PlatformDbContext` içinde `.IsRequired(false)` ile açıkça sabitlenir. - Kolon zorunluluğu tercihen NRT'ye değil, `PlatformDbContext` yapılandırmasına yazılır; böylece derleyici anahtarından bağımsız olur. ## 3. Ölü kod politikası Aşağıdaki kurallar ihlal edilmiş kod merge edilmez: | Kural | Anlamı | | --- | --- | | IDE0005 | Kullanılmayan `using` | | IDE0051 | Çağrılmayan private üye | | IDE0052 | Yazılıp hiç okunmayan private alan (kullanılmayan enjekte bağımlılık) | | IDE0059 | Gereksiz değer ataması | | IDE0161 | `namespace X;` (file-scoped) | Tarama ve otomatik düzeltme (kalıcı yapılandırma gerektirmez): ```bash # Rapor dotnet build api/Sozsoft.Platform.sln --no-incremental \ -p:EnforceCodeStyleInBuild=true -p:GenerateDocumentationFile=true # Düzeltme dotnet format api/Sozsoft.Platform.sln --diagnostics IDE0005,IDE0161 --severity warn ``` > Kurallar `.editorconfig`'te `warning` seviyesindedir ve `EnforceCodeStyleInBuild` > açık olduğu için normal `dotnet build` de bunları raporlar. IDE0052 düzeltilirken alan ile birlikte **constructor parametresi de** silinir; yoksa DI hâlâ gereksiz servisi çözer. `CS0162` (erişilemez kod) `Directory.Build.props` içinde gerekçesiyle susturulmuştur: veritabanı sağlayıcısı derleme zamanı sabiti olduğu için diğer sağlayıcının dalları erişilemez görünür. Bu durum dışında erişilemez kod bırakılmaz. Ek kurallar: - Bir tip/dosya silinmeden önce **repo genelinde** (api + ui + configs) referans taraması yapılır. DI ile çözülen tipler (AppService, Manager, Provider, Repository, Seeder, Localizer, Notification sağlayıcıları) düz metin aramasında "referanssız" görünür — bunlar yalnızca modül/DI kaydı incelendikten sonra silinir. - Yorum satırına alınmış kod bloğu bırakılmaz; ihtiyaç varsa git geçmişinden alınır. - "İleride lazım olur" gerekçesiyle kullanılmayan DTO/Input/Consts tutulmaz. - `Migrations/` ve `*.g.cs` üretilmiş koddur, bu kuralların dışındadır. ## 4. Modern C# kullanımı (yeni kod) - File-scoped namespace: `namespace Sozsoft.Platform.ListForms;` - Primary constructor: `public class XAppService(IRepository repo) : PlatformAppService` — parametre doğrudan kullanılır, `private readonly ... = param;` şeklinde tekrar tanımlanmaz. - Koleksiyon ifadeleri (`[]`, `[.. items]`), `is not null`, `switch` ifadesi, desen eşleme, `Index/Range`, hedefi belli `new()`. - `out var`, tuple deconstruction; kullanılmayan çıktı için `_`. - `async` metotlar `Async` ile biter ve `Task`/`Task` döner; `async void` yasak. ABP'de `ConfigureAwait` kullanılmaz. - Biçim: `api/.editorconfig` geçerlidir (4 boşluk girinti, `using` blokları namespace dışında ve System önce, dosya sonunda satır sonu, UTF-8 BOM). ## 5. ABP kuralları - **Katman sınırı**: Domain.Shared → Domain → Application.Contracts → Application → HttpApi → HttpApi.Host. Ters yönde referans verilmez; `EntityFrameworkCore` yalnızca Domain'e bakar. - **AppService**: `PlatformAppService`'ten türer, arayüzü Application.Contracts'ta tanımlanır. Controller yazılmaz — ABP otomatik API üretir. Controller sadece ABP konvansiyonunun karşılamadığı durumda (dosya indirme, harici webhook) eklenir. - **Yetki**: her AppService/metot `[Authorize(PlatformConsts.AppCodes....)]` ile korunur; izin adları `PermissionDefinitionProvider` içinde tanımlanır. Yetki kontrolü koda gömülmez, izin adı sabitten okunur. - **Tenant izolasyonu**: sorgular `ICurrentTenant` bağlamında çalışır; `IMultiTenant` entity'lerde manuel `TenantId` filtresi yazılmaz, veri filtreleri devre dışı bırakılacaksa (`ICurrentTenant.Change`, `IDataFilter`) gerekçe yorumla yazılır. - **Repository**: özel sorgu gerekiyorsa Domain'de arayüz + EntityFrameworkCore'da implementasyon. AppService içinde `DbContext` doğrudan kullanılmaz. - **Dinamik SQL**: parametreli çalıştırılır; string birleştirme ile sorgu kurulmaz. - **Mapping**: Mapperly (`[Mapper]` partial class) kullanılır; AutoMapper eklenmez. RMG012 uyarısı "hedefte karşılığı olmayan alan" demektir; yeni mapper eklerken bu uyarı bırakılmaz. - **Localization**: kullanıcıya görünen metin koda gömülmez, `PlatformResource` anahtarı üzerinden verilir. - **Çok değerli alan taşıyan girdi DTO'su**: ekranda `dxTagBox` (ya da çoklu seçimli `dxGridBox`) ile doldurulan bir alan tipli bir DTO'ya bağlanıyorsa property `string` kalır ve `[JsonConverter(typeof(MultiValueStringJsonConverter))]` ile işaretlenir — UI diziyi olduğu gibi yollar, converter `PlatformConsts.MultiValueDelimiter` ile tek string üretir. Varsayılan `list-form-data/*` ucundan geçen ekranlarda bu iş `QueryHelper` tarafından yapılır, DTO yoktur; okuma DTO'larına öznitelik eklenmez. - **Sabitler**: bağlantı dizesi, tenant id, anahtar/secret koda yazılmaz; konfigürasyon veya `SettingDefinition` üzerinden okunur. ## 6. Değişiklik öncesi kontrol listesi ```bash dotnet build api/Sozsoft.Platform.sln --no-incremental \ -p:EnforceCodeStyleInBuild=true -p:GenerateDocumentationFile=true # 0 hata, yeni IDE00xx yok dotnet format api/Sozsoft.Platform.sln --verify-no-changes --diagnostics IDE0005,IDE0161 --severity warn dotnet test api/test/Sozsoft.Platform.EntityFrameworkCore.Tests ``` > Not: EntityFrameworkCore testleri şu an SQLite şema oluşturmada > (`nvarchar(max)` → `SQLite Error 1`) kırık; bu kırıklık bu standarttan önce de vardı > ve ayrı bir iş olarak ele alınmalıdır.