Duna.Libs.Web
1.0.14
dotnet add package Duna.Libs.Web --version 1.0.14
NuGet\Install-Package Duna.Libs.Web -Version 1.0.14
<PackageReference Include="Duna.Libs.Web" Version="1.0.14" />
<PackageVersion Include="Duna.Libs.Web" Version="1.0.14" />
<PackageReference Include="Duna.Libs.Web" />
paket add Duna.Libs.Web --version 1.0.14
#r "nuget: Duna.Libs.Web, 1.0.14"
#:package Duna.Libs.Web@1.0.14
#addin nuget:?package=Duna.Libs.Web&version=1.0.14
#tool nuget:?package=Duna.Libs.Web&version=1.0.14
Duna.Libs.Web
ASP.NET Core integration library for Dunasoft applications. Provides JWT authentication, permission-based authorization, generic API base controllers, error handling middleware, background services, event bus registration, and more — all designed to work with Duna.Libs.Core.
Table of Contents
- License
- Installation
- Package Structure
- Configuration
- Authentication
- Authorization
- Controllers
- Middleware & Filters
- Background Services
- Extensions
- Exceptions
- Type Reference
- License
License
Free for non-commercial, educational, and learning use.
Small Business License — up to 3 people in the organization AND up to 100 users:
$200 / year (includes Duna.Libs.Core)
Enterprise License — more than 3 people OR more than 100 users:
20% of gross revenue of all products built using this library, billed quarterly. (includes Duna.Libs.Core)
Copyright © 2021-present Soroush Dehbidi Asadzadeh / LOCBEEZ. All Rights Reserved.
Contact: info@soroushasadzadeh.com
Installation
dotnet add package Duna.Libs.Web
Requires Duna.Libs.Core (included as a dependency).
Package Structure
Duna.Libs.Web
├── Authentication/ JWT token generation, config keys, DI extensions
├── Authorization/ Permission attributes (IPermission<TId>, IPermission<TId, TLevel>)
│ and DI policy registration
├── Controllers/ ApiBase<TDto, TId> — generic CRUD controller base
├── Extensions/ EventBus, server instance, and service DI helpers
├── Middleware/ CORS options, global exception handling middleware
├── Filters/ ErrorMessageExceptionFilter for MVC exception handling
├── Services/ PeriodicBackgroundService base class
└── Exceptions/ Web-layer error codes and Exception type
Configuration
Full appsettings.json sample
Below is a complete appsettings.json example covering every key that Configs and DefaultConfigKeys recognise.
{
// ── JWT ────────────────────────────────────────────────────────────────
"SigningJwtKey": "your-secret-signing-key-min-32-chars",
// ── Connection strings ─────────────────────────────────────────────────
//
// Set DatabaseProvider to the name of the active provider (case-insensitive).
// The matching sub-section is resolved dynamically by the enum value name,
// so adding a new provider never requires code changes — only a new enum
// value in DatabaseProvider and a matching JSON key here.
//
"EnableConnectionStringLoadBalancer": "true",
"ConnectionStrings": {
"DatabaseProvider": "MsSql",
"MsSql": {
"Domain": "Server=.;Database=MyDb;User Id=sa;Password=P@ssword;",
"Writes": [
"Server=write-1;Database=MyDb;User Id=sa;Password=P@ssword;",
"Server=write-2;Database=MyDb;User Id=sa;Password=P@ssword;"
],
"Reads": [
"Server=read-1;Database=MyDb;User Id=sa;Password=P@ssword;",
"Server=read-2;Database=MyDb;User Id=sa;Password=P@ssword;"
]
},
"MySql": {
"Domain": "Server=localhost;Database=MyDb;User=root;Password=P@ssword;",
"Writes": [
"Server=mysql-write-1;Database=MyDb;User=root;Password=P@ssword;"
],
"Reads": [
"Server=mysql-read-1;Database=MyDb;User=root;Password=P@ssword;"
]
},
"PostgreSql": {
"Domain": "Host=localhost;Database=MyDb;Username=postgres;Password=P@ssword;",
"Writes": [
"Host=pgsql-write-1;Database=MyDb;Username=postgres;Password=P@ssword;"
],
"Reads": [
"Host=pgsql-read-1;Database=MyDb;Username=postgres;Password=P@ssword;"
]
}
},
// ── Environment ────────────────────────────────────────────────────────
"EnvironmentBackgroundColor": "#1e1e2e",
"EnvironmentColor": "#cdd6f4",
// ── CORS ───────────────────────────────────────────────────────────────
"CorsOptionAllowUrls": [
"https://app.example.com",
"https://admin.example.com"
],
// ── Server instance (used by Snowflake / Hybrid ID providers) ──────────
"SERVER_INSTANCE_ID": "1",
// ── EventBus (RabbitMQ) ────────────────────────────────────────────────
"EventBus": {
"Connection": {
"Host": "localhost",
"Port": 5672,
"UserName": "guest",
"Password": "guest"
},
"Queue": {
"Name": "my-service-queue"
}
}
}
Environment variables — any string value can be replaced with an environment variable reference using the syntax
$ENV_VARIABLE|VAR_NAME. For example:"Domain": "$ENV_VARIABLE|MSSQL_CONNECTION_STRING"
Configsresolves these at read time viaGetValueFromConfigurationValue().
IConfigKeys / DefaultConfigKeys
Duna.Libs.Web.Interfaces.IConfigKeys
Duna.Libs.Web.DefaultConfigKeys
IConfigKeys defines the configuration key names used throughout Configs.
DefaultConfigKeys provides the default implementation. Override any property to remap keys in your own deployment.
| Property | Default value | Purpose |
|---|---|---|
ConnectionStrings |
"ConnectionStrings" |
Root section for all DB connection config |
DatabaseProvider |
"DatabaseProvider" |
Key (inside ConnectionStrings) that selects the active provider |
EnableConnectionStringLoadBalancer |
"EnableConnectionStringLoadBalancer" |
Enables round-robin write/read balancing |
SigningJwtKey |
"SigningJwtKey" |
JWT HMAC signing key |
EnvironmentBackgroundColor |
"EnvironmentBackgroundColor" |
UI hint for the current environment |
EnvironmentColor |
"EnvironmentColor" |
UI hint for the current environment |
CorsOptionAllowUrls |
"CorsOptionAllowUrls" |
Array of allowed CORS origins |
EnvironmentVariableKey |
"$ENV_VARIABLE" |
Prefix for environment variable references |
EnvironmentVariableKeySplitter |
"|" |
Separator between prefix and variable name |
ValueSplitter |
"|" |
Separator for multi-value connection strings |
EventBus |
"EventBus" |
EventBus configuration section |
ServerInstanceId |
"SERVER_INSTANCE_ID" |
Node index for distributed ID generators |
Configs
Duna.Libs.Web.Configs
Static class. Call Configs.Init(configuration, env) once during startup (e.g. in Program.cs) before using any other Configs members.
// Program.cs
Configs.Init(builder.Configuration, app.Environment);
// With custom key names
Configs.Init(builder.Configuration, app.Environment, new MyConfigKeys());
| Member | Description |
|---|---|
Configs.DatabaseProvider |
Parsed DatabaseProvider enum from ConnectionStrings:DatabaseProvider (case-insensitive; falls back to MsSql) |
Configs.GetProviderConnectionStringConfig() |
Returns the ConnectionStringProviderConfig for the active provider, resolved dynamically by enum value name |
Configs.DomainDbConnectionString |
Domain string from the active provider sub-section |
Configs.WriteDbConnectionString |
Next write string from the round-robin balancer, or DomainDbConnectionString when balancing is disabled |
Configs.ReadDbConnectionString |
Next read string from the round-robin balancer, or DomainDbConnectionString when balancing is disabled |
Configs.SigningJwtKey |
JWT signing key |
Configs.EventBusConfigs |
Bound EventBusConfigs object |
Configs.ServerInstanceId |
Node index integer |
Configs.Environment |
Parsed Enums.Environment from the hosting environment name |
Configs.CorsOptionAllowUrls |
Array of allowed CORS origins |
Configs.Version / Product / Company |
Assembly metadata |
ConnectionStringProviderConfig
Duna.Libs.Web.ConnectionStrings.ConnectionStringProviderConfig
POCO bound from the provider sub-section inside ConnectionStrings.
public class ConnectionStringProviderConfig
{
public string Domain { get; set; } // primary / single connection string
public List<string> Writes { get; set; } = []; // write-replica pool
public List<string> Reads { get; set; } = []; // read-replica pool
}
The sub-section is selected by matching the DatabaseProvider enum value name case-insensitively against the child keys of ConnectionStrings. This means:
DatabaseProvider.MsSql→ looks for a child keyMsSql(ormssql,MSSQL, …)DatabaseProvider.MySql→ looks forMySqlDatabaseProvider.PostgreSql→ looks forPostgreSql- Any future provider added to the enum → works automatically with a matching JSON key, no code changes required
Authentication
TokenService
Duna.Libs.Web.Authentication.TokenService
Static helper for generating signed JWT tokens from permission collections.
// Generate a token encoding IPermission<TAccessId> claims
string token = TokenService.GenerateNewToken(signingKey, username, permissions, validDays: 1);
// Generate a token encoding IPermission<TAccessId, TAccessLevel> claims
string token = TokenService.GenerateNewTokenWithAccessLevel(signingKey, username, permissions, validDays: 7);
// Low-level: generate a token with an arbitrary Claim
string token = TokenService.GenerateToken(signingKey, username, new Claim("my-claim", "value"), validDays: 1);
Permissions are Base64-encoded into a single JWT claim using PermissionEncoder from Duna.Libs.Core.Security.
Authentication ServiceCollectionExtension
Duna.Libs.Web.Authentication namespace
// Register JWT bearer authentication
services.AddJwtAuthentication(configuration);
// Or with custom config keys
services.AddJwtAuthentication(configuration, new MyConfigKeys());
Configures JwtBearerDefaults.AuthenticationScheme with signature validation from SigningJwtKey in configuration.
Authorization
AuthorizeAccessAttribute
Duna.Libs.Web.Authorization.AuthorizeAccessAttribute
An AuthorizeAttribute that also implements IPermission<long>. Decorate controllers or actions with it to enforce resource-level access:
[AuthorizeAccess(AccessId = 10)]
public IActionResult GetOrder(int id) { ... }
Implements:
bool IsAuthorized(IEnumerable<IPermission<long>> permissions)— returnstrueif any permission matchesAccessId.bool IsAuthorized(string base64EncodedPermission)— decodes the claim value and delegates to the above.
AuthorizeAccessWithLevelAttribute
Duna.Libs.Web.Authorization.AuthorizeAccessWithLevelAttribute
Like AuthorizeAccessAttribute but also enforces a bitflag AccessLevel:
[AuthorizeAccessWithLevel(AccessId = 10, AccessLevel = AccessLevel.Get | AccessLevel.Update)]
public IActionResult UpdateOrder(int id) { ... }
Implements IPermission<long, AccessLevel>. The check passes when a token permission matches AccessId and its AccessLevel flags contain all required bits.
ServiceCollectionExtention
Duna.Libs.Web.Authorization.ServiceCollectionExtention
Registers ASP.NET Core authorization policies linked to the JWT permission claims.
// Register the default policy (AuthorizeAccessWithLevelAttribute, long, AccessLevel)
// Uses built-in DefaultActionsAccessLevelFunc to infer access level from action name
services.AddAuthorizationJwtAccessWithLevel();
// Custom TPermission, TAccessId, TAccessLevel
services.AddAuthorizationJwtAccessWithLevel<MyPermission, int, MyLevel>();
// With a custom function that maps action names to access levels
services.AddAuthorizationJwtAccessWithLevel<MyPermission, int, MyLevel>(
actionName => actionName == "Export" ? MyLevel.Advance : MyLevel.Get);
// Simple access (no level) — generic TAccessId
services.AddAuthorizationJwtAccess<long>();
// Simple access — custom TPermission
services.AddAuthorizationJwtAccess<AuthorizeAccessAttribute, long>();
// Convenience overload (uses AuthorizeAccessAttribute + long)
services.AddAuthorizationJwtAccess();
DefaultActionsAccessLevelFunc
Maps action method names (case-insensitive) to AccessLevel flags automatically:
| Action name | Access level |
|---|---|
get, getlist |
Get |
getall |
Advance |
add |
Add |
addlist |
Add \| Batch |
update |
Update |
updatelist |
Update \| Batch |
remove |
Remove |
removelist |
Remove \| Batch |
Controllers
ApiBase
Duna.Libs.Web.Controllers.ApiBase<TDto, TId>
Generic CRUD API base class. Wire up a service and get full CRUD endpoints:
[Route("api/[controller]")]
public class ProductsController : ApiBase<ProductDto, int>
{
public ProductsController(ICrudServiceProvider<ProductDto, int> service)
: base(service) { }
}
Provides:
GET /api/products/{id}GET /api/products?sortExpression=...&startIndex=0&size=20GET /api/products/allGET /api/products/countGET /api/products/longcountPOST /api/productsPUT /api/productsDELETE /api/products/{id}- Batch add, update, and remove list endpoints
Middleware & Filters
ApiExceptionHandlerMiddleware
Duna.Libs.Web.Middleware.ApiExceptionHandlerMiddleware
Global exception handler that converts unhandled exceptions into structured JSON responses:
app.UseMiddleware<ApiExceptionHandlerMiddleware>();
ExceptionBase→ setsStatusCode,ModuleId,ErrorCode, andMessagefields from the exception.- All other exceptions → returns
IsUnknown: truewith HTTP 500.
Response shape:
{
"IsUnknown": false,
"ModuleId": 3,
"ErrorCode": 1001,
"Message": "Resource not found"
}
ErrorMessageExceptionFilter
Duna.Libs.Web.Filters.ErrorMessageExceptionFilter
MVC exception filter alternative to the middleware. Register as a global filter:
services.AddControllers(options =>
{
options.Filters.Add<ErrorMessageExceptionFilter>();
});
Produces the same JSON error shape as ApiExceptionHandlerMiddleware.
OptionsMiddleware
Duna.Libs.Web.Middleware.OptionsMiddleware
Handles CORS pre-flight OPTIONS requests and injects Access-Control-* headers for allowed origins.
app.UseMiddleware<OptionsMiddleware>(new[] { "https://app.example.com" });
- Allowed origins receive CORS headers and
200 OKforOPTIONS. - Disallowed origins receive
400 Bad RequestforOPTIONS. - Non-OPTIONS requests pass through.
OptionsMiddlewareExtensions
Duna.Libs.Web.Middleware.OptionsMiddlewareExtensions
Convenience extension:
app.UseOptionsMiddleware("https://app.example.com", "https://admin.example.com");
Background Services
PeriodicBackgroundService
Duna.Libs.Web.Services.PeriodicBackgroundService
Abstract IHostedService base class for recurring background work:
public class CleanupService : PeriodicBackgroundService
{
protected override TimeSpan Period => TimeSpan.FromHours(1);
protected override async Task DoWorkAsync(CancellationToken token)
{
// periodic work here
}
}
Register with:
services.AddHostedService<CleanupService>();
Extensions
EventBusServiceCollectionExtensions
Duna.Libs.Web.Extensions.EventBusServiceCollectionExtentions
Registers the Duna.Libs.Core event bus infrastructure with ASP.NET Core DI. The active database provider is read from Configs.DatabaseProvider automatically.
// Register all event bus services (DbContext, RabbitMQ connection, message service, …)
services.AddEventBusServices();
The EventBus RabbitMQ connection and queue are configured via appsettings.json:
"EventBus": {
"Connection": {
"Host": "localhost",
"Port": 5672,
"UserName": "guest",
"Password": "guest"
},
"Queue": {
"Name": "my-service-queue"
}
}
Start the periodic send loop after app.Build():
app.RunSendMessage();
---
### ServerInstanceIdExtensions
`Duna.Libs.Web.Extensions.ServerInstanceIdExtensions`
Registers an `IWorker` implementation that reads the server instance index from configuration (used by Snowflake / Hybrid ID providers):
```csharp
services.AddServerInstanceId(configuration);
ServiceExtensions
Duna.Libs.Web.Extensions.ServiceExtensions
Convenience DI helpers for common patterns:
// Register a transient ICrudServiceProvider + TService pair
services.AddTransientServiceDefault<IProductService, ProductService, ProductDto, int>();
// Register a scoped IAuthorizedService + TService pair
services.AddScopedAuthorizedServiceDefault<IOrderService, OrderService, OrderDto, int>();
// Register a scoped ICurrentUserDataProvider
services.AddScopedCurrentUserDataProvider<UserDataProvider, UserDto, long>();
Exceptions
Duna.Libs.Web.Exceptions.Exception — thrown when a web-layer error occurs.
Duna.Libs.Web.Exceptions.ErrorCode — enum of web error codes:
| Code | Meaning |
|---|---|
ResourceEndPointActionNotFound |
Route endpoint has no matching controller action descriptor |
ResourceUnknown |
Authorization resource type is not recognized |
Type Reference
| Type | Namespace | Description |
|---|---|---|
IConfigKeys |
Duna.Libs.Web.Interfaces |
Configuration key name contract |
DefaultConfigKeys |
Duna.Libs.Web |
Default configuration key names |
Configs |
Duna.Libs.Web |
Static app configuration accessor; call Init() at startup |
ConnectionStringProviderConfig |
Duna.Libs.Web.ConnectionStrings |
Per-provider connection string POCO (Domain, Writes, Reads) |
TokenService |
Duna.Libs.Web.Authentication |
JWT token generation |
AuthorizeAccessAttribute |
Duna.Libs.Web.Authorization |
IPermission<long> authorization attribute |
AuthorizeAccessWithLevelAttribute |
Duna.Libs.Web.Authorization |
IPermission<long, AccessLevel> authorization attribute |
ServiceCollectionExtention |
Duna.Libs.Web.Authorization |
Authorization policy DI registration |
ApiBase<TDto, TId> |
Duna.Libs.Web.Controllers |
Generic CRUD controller base |
ApiExceptionHandlerMiddleware |
Duna.Libs.Web.Middleware |
Global JSON exception handler |
ErrorMessageExceptionFilter |
Duna.Libs.Web.Filters |
MVC exception filter |
OptionsMiddleware |
Duna.Libs.Web.Middleware |
CORS pre-flight handler |
OptionsMiddlewareExtensions |
Duna.Libs.Web.Middleware |
UseOptionsMiddleware extension |
PeriodicBackgroundService |
Duna.Libs.Web.Services |
Recurring hosted service base |
EventBusServiceCollectionExtentions |
Duna.Libs.Web.Extensions |
EventBus DI registration |
ServerInstanceIdExtensions |
Duna.Libs.Web.Extensions |
Worker node index DI registration |
ServiceExtensions |
Duna.Libs.Web.Extensions |
CRUD/authorized service DI helpers |
ErrorMessage |
Duna.Libs.Web |
Error response payload model |
Consts |
Duna.Libs.Web |
Claim type and policy name constants |
ErrorCode |
Duna.Libs.Web.Exceptions |
Web-layer error code enum |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Duna.Libs.Core (>= 1.0.8)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.8)
- Microsoft.AspNetCore.Authorization (>= 10.0.8)
- Swashbuckle.AspNetCore (>= 10.1.7)
- Swashbuckle.AspNetCore.Swagger (>= 10.1.7)
- Swashbuckle.AspNetCore.SwaggerUI (>= 10.1.7)
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 |
|---|---|---|
| 1.0.14 | 106 | 5/26/2026 |
| 1.0.13 | 87 | 5/26/2026 |
| 1.0.12 | 91 | 5/25/2026 |
| 1.0.11 | 101 | 5/25/2026 |
| 1.0.9 | 89 | 5/25/2026 |
| 1.0.8 | 93 | 5/25/2026 |
| 1.0.7 | 111 | 5/22/2026 |
| 1.0.6 | 94 | 5/22/2026 |
| 1.0.5 | 95 | 5/19/2026 |
| 1.0.4 | 95 | 5/16/2026 |
| 1.0.3 | 94 | 5/16/2026 |
| 1.0.2 | 98 | 5/12/2026 |
| 1.0.1 | 102 | 5/12/2026 |
| 0.1.6 | 105 | 5/12/2026 |
| 0.1.5 | 101 | 5/4/2026 |
| 0.1.4 | 99 | 5/4/2026 |
| 0.1.3 | 100 | 5/4/2026 |
| 0.1.2 | 96 | 5/4/2026 |
| 0.0.72 | 132 | 3/27/2026 |
| 0.0.71 | 126 | 2/23/2026 |