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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Duna.Libs.Web" Version="1.0.14" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Duna.Libs.Web" Version="1.0.14" />
                    
Directory.Packages.props
<PackageReference Include="Duna.Libs.Web" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Duna.Libs.Web --version 1.0.14
                    
#r "nuget: Duna.Libs.Web, 1.0.14"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Duna.Libs.Web@1.0.14
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Duna.Libs.Web&version=1.0.14
                    
Install as a Cake Addin
#tool nuget:?package=Duna.Libs.Web&version=1.0.14
                    
Install as a Cake Tool

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

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"

Configs resolves these at read time via GetValueFromConfigurationValue().


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 key MsSql (or mssql, MSSQL, …)
  • DatabaseProvider.MySql → looks for MySql
  • DatabaseProvider.PostgreSql → looks for PostgreSql
  • 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) — returns true if any permission matches AccessId.
  • 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=20
  • GET /api/products/all
  • GET /api/products/count
  • GET /api/products/longcount
  • POST /api/products
  • PUT /api/products
  • DELETE /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 → sets StatusCode, ModuleId, ErrorCode, and Message fields from the exception.
  • All other exceptions → returns IsUnknown: true with 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 OK for OPTIONS.
  • Disallowed origins receive 400 Bad Request for OPTIONS.
  • 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
Loading failed