141 lines
7.2 KiB
Markdown
141 lines
7.2 KiB
Markdown
# .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 (`<Nullable>enable</Nullable>`).
|
||
Ş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<X, Guid> 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<T>` 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.
|