CAppFramework.Web
1.1.0
dotnet add package CAppFramework.Web --version 1.1.0
NuGet\Install-Package CAppFramework.Web -Version 1.1.0
<PackageReference Include="CAppFramework.Web" Version="1.1.0" />
<PackageVersion Include="CAppFramework.Web" Version="1.1.0" />
<PackageReference Include="CAppFramework.Web" />
paket add CAppFramework.Web --version 1.1.0
#r "nuget: CAppFramework.Web, 1.1.0"
#:package CAppFramework.Web@1.1.0
#addin nuget:?package=CAppFramework.Web&version=1.1.0
#tool nuget:?package=CAppFramework.Web&version=1.1.0
CAppFramework – Paket Dokümantasyonu (v1)
.NET 9 için modüler, NuGet olarak tüketilebilir bir uygulama çatısı. Bu sayfa; paket bazlı kurulum, appsettings örnekleri, Program.cs entegrasyonları ve kullanım örneklerini içerir. Her alt başlık kendi NuGet paketinin README’si olarak da kullanılabilir.
İçindekiler
- Hızlı Başlangıç (hepsi bir arada)
- Paketler ve Amaçları
- CAppFramework.Core
- CAppFramework.Data.EFCore
- CAppFramework.Web
- CAppFramework.Identity
- CAppFramework.SignalR
- CAppFramework.Messaging
- CAppFramework.Licensing
- Sürümleme, NuGet Paketleme ve Yayın
- Sık Karşılaşılan Sorunlar
Hızlı Başlangıç (hepsi bir arada)
Aşağıdaki örnek, tüm paketleri minimal ayarlarla ayağa kaldırır.
NuGet (önerilen paket adları)
# Paketleri tüketen projede
dotnet add package CAppFramework.Core
dotnet add package CAppFramework.Data.EFCore
dotnet add package CAppFramework.Web
dotnet add package CAppFramework.Identity
dotnet add package CAppFramework.SignalR
dotnet add package CAppFramework.Messaging
dotnet add package CAppFramework.Licensing
# (MassTransit kullanacaksanız)
dotnet add package MassTransit
dotnet add package MassTransit.RabbitMQ
appsettings.json (lisans varsayılan olarak kapalı; etkinleştirmek için License:Enabled=true)
{
"Jwt": {
"Issuer": "capp",
"Audience": "capp.clients",
"SigningKey": "CHANGE_ME_32_CHARS_MINIMUM",
"AccessTokenMinutes": 60
},
"Messaging": {
"Enabled": true,
"Provider": "InMemory" // "MassTransit" de olabilir
},
"License": {
"Enabled": false,
"Path": "license.json",
"PublicKeyPemPath": "keys/public.pem", // önerilen: PEM dosya yolu
// veya PEM içeriği:
"PublicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
"Enforce": true
}
}
Program.cs (Minimal)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCAppFrameworkCore(builder.Configuration);
builder.Services.AddCAppFrameworkWeb();
builder.Services.AddCAppSwagger("CApp API", "v1", "Docs");
builder.Services.AddCAppJwtAuthentication(builder.Configuration); // Identity minimal
builder.Services.AddCAppFrameworkSignalR();
builder.Services.AddCAppFrameworkMessaging(builder.Configuration, x =>
{
// MassTransit kullanıyorsanız consumer kayıtlarını burada yapın
// x.AddConsumer<UserCreatedConsumer>();
});
// Lisanslama opsiyonel — devre dışı bırakıldı
// builder.Services.AddCAppFrameworkLicensing(builder.Configuration);
var app = builder.Build();
app.UseCAppFrameworkWeb(); // exception middleware
app.UseAuthentication();
app.UseAuthorization();
// Lisans middleware'i devre dışı (UseCAppFrameworkWeb(useLicense: true) veya UseCAppLicense ile açılır)
// app.UseCAppLicense();
app.UseCAppSwaggerUI("/swagger/v1/swagger.json", "CApp API v1");
app.MapGet("/", () => "OK");
app.MapCAppFrameworkHubs("/hubs");
app.Run();
Paketler ve Amaçları
| Paket | Amaç | Öne Çıkanlar |
|---|---|---|
| CAppFramework.Core | Dil bağımsız temel tipler | Result, Error, ApiResponse<T>, PagedList<T>, ValueObject, Enumeration, audit arayüzleri, ICurrentUser, IClock, IFeatureGate, FrameworkOptions |
| CAppFramework.Data.EFCore | EF Core tabanı ve Repository/Specification | BaseDbContext (global soft-delete & tenant filtreleri), TrackSaveChangesInterceptor, IRepository/IReadRepository/IUnitOfWork, Specification |
| CAppFramework.Web | Web yardımcıları ve middleware’ler | GlobalExceptionMiddleware, LicenseMiddleware, Swagger helper’ları |
| CAppFramework.Identity | Minimal JWT auth + HttpCurrentUser adaptörü | AddCAppJwtAuthentication, HttpCurrentUser (claims → ICurrentUser) |
| CAppFramework.SignalR | Realtime iskelet | ChatHub, AddCAppFrameworkSignalR, MapCAppFrameworkHubs |
| CAppFramework.Messaging | Mesajlaşma soyutlaması ve sağlayıcılar | IMessagePublisher, IMessageConsumer, InMemory provider, MassTransit/RabbitMQ adapter |
| CAppFramework.Licensing | Lisans okuma & doğrulama | FileLicenseProvider, RsaLicenseValidator, LicenseModel |
CAppFramework.Core
Kurulum
dotnet add package CAppFramework.Core
Kayıt
builder.Services.AddCAppFrameworkCore(builder.Configuration);
Özellikler
- Sonuç tipi:
Result,Result<T>,Error,Errors.*katalogu - API cevabı:
ApiResponse<T> - Sayfalama:
PagedList<T>+PagedList.From(...) - Domain tabanı:
Entity,CreationAuditedEntity,AuditedEntity,FullAuditedEntity - Arayüzler:
ICreationAudited,IModificationAudited,ISoftDelete,IMustHaveTenant,IMayHaveTenant - Çekirdek servisler:
IClock(default:SystemClock),IFeatureGate(in-memory) - Değer & enum pattern:
ValueObject,Enumeration<TEnum,TValue>
Kullanım
if (string.IsNullOrWhiteSpace(name))
return Result.Failure(Errors.Validation.Required(nameof(name)));
return Result.Success();
CAppFramework.Data.EFCore
Kurulum
dotnet add package CAppFramework.Data.EFCore
Paket Notu: EF Core sağlayıcısını (Npgsql/SqlServer vs.) host projede ekleyin.
DbContext ve Interceptor
builder.Services.AddDbContext<AppDbContext>((sp, opt) =>
{
var audit = sp.GetRequiredService<CAppFramework.Data.EFCore.Interceptors.TrackSaveChangesInterceptor>();
opt.UseNpgsql(builder.Configuration.GetConnectionString("Default"));
opt.AddInterceptors(audit);
});
builder.Services.AddCAppFrameworkEfCore();
Repository / Specification
public class AppDbContext : BaseDbContext
{
public AppDbContext(DbContextOptions options, IClock clock, ICurrentUser user, IOptions<FrameworkOptions> fw)
: base(options, clock, user, fw) { }
public DbSet<Product> Products => Set<Product>();
}
// Sorgu
var spec = new ProductsByNameSpec("pen");
var list = await repo.ListAsync(spec, ct);
Örnek Specification
public sealed class ProductsByNameSpec : Specification<Product>
{
public ProductsByNameSpec(string term)
{
Criteria = p => EF.Functions.ILike(p.Name, $"%{term}%");
ApplyOrderBy(p => p.Name);
WithNoTracking();
}
}
IUnitOfWork
await repo.AddAsync(entity);
await uow.SaveChangesAsync();
CAppFramework.Web
Kurulum
dotnet add package CAppFramework.Web
Swagger + Exception + License
builder.Services.AddCAppFrameworkWeb();
builder.Services.AddCAppSwagger("My API", "v1", "Docs");
var app = builder.Build();
app.UseCAppFrameworkWeb();
app.UseCAppLicense();
app.UseCAppSwaggerUI("/swagger/v1/swagger.json", "My API v1");
JWT Bearer Swagger Şeması: Web paketindeki AddCAppSwagger Bearer şemasını içerir.
CAppFramework.Identity
Amaç: Sadece JWT doğrulama ve ICurrentUser adaptörü. EF/Identity.EntityFrameworkCore bağımlılığı yoktur.
Kurulum
dotnet add package CAppFramework.Identity
appsettings.json
"Jwt": {
"Issuer": "capp",
"Audience": "capp.clients",
"SigningKey": "CHANGE_ME_32_CHARS_MINIMUM",
"AccessTokenMinutes": 60
}
Program.cs
builder.Services.AddCAppJwtAuthentication(builder.Configuration);
SignalR ile JWT (query access_token)
builder.Services.PostConfigure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, o =>
{
var hubPrefix = "/hubs";
o.Events = new JwtBearerEvents
{
OnMessageReceived = ctx =>
{
var token = ctx.Request.Query["access_token"];
if (!string.IsNullOrEmpty(token) && ctx.HttpContext.Request.Path.StartsWithSegments(hubPrefix))
ctx.Token = token;
return Task.CompletedTask;
}
};
});
CAppFramework.SignalR
Kurulum
dotnet add package CAppFramework.SignalR
Program.cs
builder.Services.AddCAppFrameworkSignalR();
...
app.MapCAppFrameworkHubs("/hubs"); // /hubs/chat
İstemci (HTML)
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.5/signalr.min.js"></script>
<script>
const token = "<jwt>";
const conn = new signalR.HubConnectionBuilder()
.withUrl("/hubs/chat?access_token=" + encodeURIComponent(token))
.withAutomaticReconnect().build();
conn.on("message", m => console.log(m));
conn.start();
</script>
Not: Sunucu tarafında ek bir Microsoft.AspNetCore.SignalR NuGet paketine ihtiyaç yoktur; ASP.NET Core paylaşılan çerçevesi (Microsoft.AspNetCore.App) ile gelir.
CAppFramework.Messaging
Kurulum
dotnet add package CAppFramework.Messaging
# MassTransit kullanacaksanız:
dotnet add package MassTransit
dotnet add package MassTransit.RabbitMQ
appsettings.json
"Messaging": {
"Enabled": true,
"Provider": "InMemory" // veya "MassTransit",
"MassTransit": {
"Host": "rabbitmq",
"Port": 5672,
"VirtualHost": "/",
"Username": "guest",
"Password": "guest",
"PrefetchCount": 16,
"RetryCount": 5,
"RetryIntervalSeconds": 5,
"ServiceInstanceId": "capp-demo"
}
}
Program.cs
builder.Services.AddCAppFrameworkMessaging(builder.Configuration, x =>
{
// MassTransit tüketicileri
// x.AddConsumer<UserCreatedConsumer>();
});
Publish (provider-agnostic)
app.MapPost("/publish", async (IMessagePublisher bus) =>
{
await bus.PublishAsync("user.created", new UserCreatedEvent(1, "demo@site.com"));
return Results.Ok();
});
public sealed record UserCreatedEvent(int Id, string Email) : IIntegrationEvent;
Consumer (MassTransit)
public sealed class UserCreatedConsumer(ILogger<UserCreatedConsumer> log) : IConsumer<UserCreatedEvent>
{
public Task Consume(ConsumeContext<UserCreatedEvent> ctx)
{ log.LogInformation("Consumed: {Id}", ctx.Message.Id); return Task.CompletedTask; }
}
CAppFramework.Licensing
Kurulum
dotnet add package CAppFramework.Licensing
Program.cs
builder.Services.AddCAppFrameworkLicensing(builder.Configuration);
...
app.UseCAppLicense(); // Web paketindeki middleware
appsettings.json
"License": {
"Path": "license.json", // veya `Raw`
"Raw": null, // string olarak lisans
"PublicKeyPemPath": "keys/public.pem", // önerilen: PEM dosya yolu
// veya PEM içeriği:
"PublicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
"Enforce": true
}
Ortam değişkenleri (fallback):
- CAPP_LICENSE_PATH: Lisans dosya yolu ("License:Path" yerine)
- CAPP_LICENSE_RAW: Ham lisans JSON içeriği ("License:Raw" yerine)
- CAPP_LICENSE_PUBLICKEY_PEM_PATH: Public key PEM dosya yolu ("License:PublicKeyPemPath" yerine)
- CAPP_LICENSE_PUBLICKEY_PEM: Public key PEM içeriği ("License:PublicKeyPem" yerine)
PowerShell örneği:
$env:CAPP_LICENSE_PATH = "D:\\secrets\\license.json"
$env:CAPP_LICENSE_PUBLICKEY_PEM_PATH = "D:\\secrets\\public.pem"
Lisans JSON örneği
{
"Product": "CAppFramework",
"Customer": "Acme Inc.",
"ExpiryUtc": "2026-01-01T00:00:00Z",
"Features": ["SignalR", "Messaging"],
"SignatureBase64": "..."
}
Statü endpoint (isteğe bağlı)
app.MapGet("/license/status", (ILicenseProvider p, ILicenseValidator v) =>
{
var raw = p.GetRawLicense();
if (raw is null) return Results.Json(new { valid = false, reason = "missing" });
var ok = v.TryGetPayload(raw, out var model, out var err);
return Results.Json(new { valid = ok, error = ok ? null : err, model });
});
Lisans üretimi
private.pemile imzalanmış JSON üretin (RSA-SHA256 PKCS#1 v1.5).- Public key’i
PublicKeyPemolarak deploy edin. - Örnek araç ve komutlar için “tools/LicenseTool” klasöründeki örneği kullanın.
Sürümleme, NuGet Paketleme ve Yayın
Directory.Build.props (root):
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Authors>CApp</Authors>
<Company>CApp</Company>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryType>git</RepositoryType>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
</PropertyGroup>
</Project>
csproj’e paket bilgisi
<PropertyGroup>
<PackageId>CAppFramework.Core</PackageId>
<Description>Core primitives for CAppFramework</Description>
<Version>1.0.0</Version>
</PropertyGroup>
Paketleme & yayın
# Paketle
dotnet pack src/CAppFramework.Core -c Release
# Publish (NuGet.org veya feed)
dotnet nuget push src/CAppFramework.Core/bin/Release/*.nupkg -k <API_KEY> -s https://api.nuget.org/v3/index.json
GitHub Actions ile otomatik paketleme: .github/workflows/build-and-pack.yml iş akışı, her push/PR’da restore+build+pack çalıştırır ve artifacts/packages içeriğini artifact olarak yükler.
Tag ile NuGet yayın (CI):
- GitHub repo Secrets →
NUGET_API_KEYekleyin (NuGet.org API Key). - SemVer etiketi basın ve push edin (örn.
v0.1.0).
git tag v0.1.0
git push origin v0.1.0
İş akışı tag push’ta sürümü etiketten alır, -p:Version ile paketler ve NuGet.org’a yükler. Yinelenen paketlerde --skip-duplicate uygulanır.
GitHub Packages’tan tüketim:
- Proje köküne bir
NuGet.configekleyin ya da global kaynağa ekleme yapın.
NuGet.config örneği (repository owner’a göre güncelleyin):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
<add key="github" value="https://nuget.pkg.github.com/caferaydin/index.json" />
</packageSources>
<packageSourceCredentials>
<github>
<add key="Username" value="GITHUB_USERNAME" />
<add key="ClearTextPassword" value="GITHUB_TOKEN_OR_PAT" />
</github>
</packageSourceCredentials>
</configuration>
CLI ile kaynak eklemek için:
dotnet nuget add source "https://nuget.pkg.github.com/caferaydin/index.json" \
--name github \
--username "<github kullanıcı adınız>" \
--password "<GitHub Personal Access Token veya GitHub Actions token>" \
--store-password-in-clear-text
Not: GitHub Packages, paket PackageId’sinin Owner alanıyla eşleşmesini gerektirmez; ancak erişim için okuma izni olan bir token gerekir. Public repo ise GITHUB_TOKEN ile CI tüketimi mümkündür; localde PAT kullanın.
SemVer: MAJOR.MINOR.PATCH – kırıcı değişikliklerde MAJOR artırın.
Sık Karşılaşılan Sorunlar
IEndpointRouteBuilderbulunamadı: Tüketen projede sorun yoktur; paket geliştirirkenFrameworkReference Microsoft.AspNetCore.Appgerekebilir. (Bizim paketlerWeb/SignalR/Identityiçin bunu içerir.)- MassTransit
UsingRabbitMqbulunamadı: ProjedeMassTransit.RabbitMQpaketini ekleyin veusing MassTransit;olduğundan emin olun. - InMemoryBus/MassTransit isim çakışması: Paket içinde
CAppInMemoryBuskullanılıyor; tüketen projede ek aksiyon gerekmez. - JWT + SignalR: WebSocket’te
access_tokeniçinPostConfigure<JwtBearerOptions>örneğini uygulayın. - Lisans PEM kaçışları:
PublicKeyPemJSON’da\nkaçışlarını koruyun veya dosya yolu ayarı (PublicKeyPemPath) kullanın.
Örnek Playground Uygulaması
Basit bir demo için:
dotnet new web -n Playground
# Paketleri ekle (yukarıdaki Hızlı Başlangıç bölümünü izleyin)
Program.cs → Hızlı Başlangıç’ta verilen örneği kopyalayın.
Swagger → https://localhost:xxxx/swagger altında test edin.
SignalR → /hubs/chat için örnek HTML kodunu kullanın.
Messaging → /publish endpoint’i ile bir IntegrationEvent yayınlayın.
Licensing → /license/status ile doğrulamayı görün.
Sorular ve katkılar için Issues/PR’larınızı açın. MIT lisanslıdır.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- CAppFramework.Core (>= 1.1.0)
- CAppFramework.Licensing (>= 1.1.0)
- Swashbuckle.AspNetCore (>= 6.9.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|