RoZ.Api.Core 20265.12.13.18

dotnet add package RoZ.Api.Core --version 20265.12.13.18
                    
NuGet\Install-Package RoZ.Api.Core -Version 20265.12.13.18
                    
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="RoZ.Api.Core" Version="20265.12.13.18" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RoZ.Api.Core" Version="20265.12.13.18" />
                    
Directory.Packages.props
<PackageReference Include="RoZ.Api.Core" />
                    
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 RoZ.Api.Core --version 20265.12.13.18
                    
#r "nuget: RoZ.Api.Core, 20265.12.13.18"
                    
#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 RoZ.Api.Core@20265.12.13.18
                    
#: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=RoZ.Api.Core&version=20265.12.13.18
                    
Install as a Cake Addin
#tool nuget:?package=RoZ.Api.Core&version=20265.12.13.18
                    
Install as a Cake Tool

Roz.Api.Core

A reusable ASP.NET Core library providing foundational components for API development, including Entity Framework integration, caching, authentication, authorization, and common utilities.

Installation

Reference this project in your API project. Ensure .NET 10.0+ is targeted.

Table of Contents


Entities

BaseEntity<T>

Base class for entities with a strongly-typed primary key and auditing support.

public class Product : BaseEntity<long> { }

Properties:

  • Id (T) - Primary key with auto-generation
  • Guid (Guid) - Global unique identifier
  • CreatedBy (Guid?) - Creator's user ID
  • CreatedTime (DateTime) - Creation timestamp (UTC)
  • ModifiedBy (Guid?) - Last modifier's user ID
  • ModifiedTime (DateTime) - Last modification timestamp (UTC)

BaseEntityWithSoftDelete<T>

Extends BaseEntity<T> with soft deletion support.

public class Product : BaseEntityWithSoftDelete<long> { }

Additional Properties:

  • DeletedBy (Guid?) - User who deleted
  • DeletedTime (DateTime?) - Deletion timestamp
  • IsDeleted (bool) - Soft delete flag

ISoftDelete

Interface for entities supporting soft deletion.

IModificationAudited<TAudited>

Interface for entities tracking creation/modification audit info.

DefaultUserEntity

Extends IdentityUser<long> with audit and soft delete support. Includes all BaseEntity properties plus ASP.NET Identity properties.


EntityFramework

BaseDbContext<TUser, TRole, TKey>

Base DbContext integrating ASP.NET Core Identity with Entity Framework Core. Configures Npgsql for UTC timestamp handling.

public class AppDbContext : BaseDbContext<DefaultUserEntity, IdentityRole<long>, long>
{
    public AppDbContext(DbContextOptions options, IHttpContextAccessor httpContext)
        : base(options, httpContext) { }
}

UtcDateTimeConverters

Value converters ensuring all DateTime values are stored/retrieved as UTC.

Usage in entity configuration:

modelBuilder.Entity<Product>()
    .Property(p => p.CreatedTime)
    .HasConversion(UtcDateTimeConverters.DateTimeToUtc);

SoftDeleteQueryExtension

Adds global query filter for soft-delete functionality:

modelBuilder.Entity<Product>().AddSoftDeleteQueryFilter();

SortableExtension

Extension methods for dynamic sorting on IQueryable.

ApplySorting<T>(data, sortedField, isDescending)

Applies sorting by property name.

var sorted = context.Products.ApplySorting("Name", false);

ApplyVietnameseSorting<T>(data, getFullName, getLastName?)

Vietnamese-aware sorting for names (uses vi-VN culture).

var sorted = people.ApplyVietnameseSorting(p => p.FullName);

GetFieldNameExpression<TEntity>(propertyName)

Creates a delegate to retrieve property values by name for sorting.


QueryableExtensions

Paging extension methods for IQueryable.

Paging<T>(data, pageIndex, pageSize)

Simple pagination using Skip/Take.

var page = context.Products.Paging(2, 10);

Paging<T>(data, pageIndex, pageSize, fieldName, isDescending)

Paginate with sorting. Defaults to CreatedTime or Id.

Paging<T>(data, filterable)

Paginate using a Filterable object.

OrderedPaging<T>(data, pageIndex, pageSize)

Paginate an already-ordered query.


Exception Handling

Custom Exceptions

Exception HTTP Status Usage
BadRequestException 400 Invalid input
UnauthorizedException 401 Not authenticated
ForbiddenException 403 Access denied
NotFoundException 404 Resource not found
CustomException 500 Generic application error
throw new NotFoundException("Product with ID {0} not found", productId);

ExceptionMiddleware

Global exception handler middleware. Catches exceptions, logs them, and converts to standardized API responses.

Registration in Program.cs:

app.UseMiddleware<ExceptionMiddleware>();

Constants

ErrorFeedbackConstants

Vietnamese validation error messages.

ErrorFeedbackConstants.Required   // "{0} không được để trống"
ErrorFeedbackConstants.MinLength // "{0} phải có độ dài tối thiểu là {1} ký tự"
ErrorFeedbackConstants.MaxLength
ErrorFeedbackConstants.Regex
ErrorFeedbackConstants.RegexName
ErrorFeedbackConstants.Name
ErrorFeedbackConstants.Password
ErrorFeedbackConstants.NumericRange
ErrorFeedbackConstants.MinItems

RegexConstants

Pre-built regex patterns for validation.

RegexConstants.Email      // Email validation
RegexConstants.Password  // Requires lower, upper, digit, special char (min 6)
RegexConstants.PhoneNumber
RegexConstants.Name      // Unicode letters and spaces
RegexConstants.NameWithDashAndDot

Models

Filterable

Extends Pageable with sorting. Use with repository queries.

var filter = new Filterable(pageIndex: 1, pageSize: 20, "Name", true);
var result = await repo.Query().Paging(filter).ToListAsync();

Properties:

  • PageIndex (int) - 1-based page index
  • PageSize (int) - Items per page (default 10)
  • FieldName (string?) - Sort field
  • IsDescending (bool?) - Sort direction
  • Sortable - Constructs Sortable from FieldName/IsDescending
  • Offset (int) - Calculated: (PageIndex-1)*PageSize

Pageable

Simple pagination parameters.

var paging = new Pageable(pageIndex: 1, pageSize: 10);

Sortable

Sorting parameters.

var sort = new Sortable(fieldName: "CreatedTime", isDescending: true);

ServiceResponse<T>

Paginated response wrapper.

var response = new ServiceResponse<T>(totalCount, filter, data);

Properties:

  • PageIndex, PageSize, TotalCount, Data, TotalPages

SearchRequest

Base for search requests with keyword.

public class ProductSearch : SearchRequest
{
    public string? Category { get; set; }
}

DefaultReponseDto

Simple response with Code and Message.

BaseDto

Base DTO with Guid property.

AppSettings

Application configuration model.

services.Configure<AppSettings>(configuration.GetSection("App"));

Properties:

  • Id, Name, Origins (CORS), Authentication (JwtSettings), AllowedSwagger, AllowedCaching

JwtSettings

JWT token configuration.

public class JwtSettings {
    public string Secret { get; set; }
    public string? Issuer { get; set; }
    public string? Audience { get; set; }
    public int AccessTokenValidityInMinutes { get; set; } = 10;
    public int? RefreshTokenValidityInMinutes { get; set; }
}

RedisConfig

Redis connection configuration.

public class RedisConfig {
    public List<string> Hosts { get; set; }
    public string? Password { get; set; }
    public int Database { get; set; }
    public bool UseCluster { get; set; }
}

Repositories

IRepository<TEntity, TKey>

Generic repository interface with full CRUD + soft delete support.

Key Methods:

  • GetAllAsync() - Get all entities (no tracking)
  • FindByIdAsync(TKey id) - Find by primary key
  • FindByGuidAsync(Guid guid) - Find by Guid property
  • AddAsync(entity, autoSave) - Add entity
  • UpdateAsync(entity, autoSave) - Update entity
  • DeleteAsync(entity, autoSave) - Delete entity
  • GetByIdAsync(id, includeDeleted) - Get with optional soft-deleted
  • RestoreByIdAsync(id) - Restore soft-deleted entity
  • PurgeByIdAsync(id) - Hard delete
  • Query(tracking, includeDeleted) - Create query
  • AnyAsync(predicate) - Check existence

BaseRepository<TEntity, TKey, TContext>

Abstract implementation of IRepository. Extend in your application:

public class ProductRepository : BaseRepository<Product, long, AppDbContext>
{
    public ProductRepository(AppDbContext context) : base(context) { }
}

Services

JwtService

JWT token generation and AES encryption/decryption.

var service = new JwtService(jwtSettings);

// Generate token
var token = service.GenerateToken(new Dictionary<string, object>
{
    ["Guid"] = userGuid,
    ["Region"] = "ADMIN"
});

// Encrypt/decrypt data
var encrypted = service.Encrypt(plainText);
var decrypted = service.Decrypt(cipherText);

IdentityService

Service for extracting user identity information from JWT tokens.

// Get current user GUID
var userGuid = await identityService.GetCurrentUserGuid();

// Check region access
var hasRegion = await identityService.IsHaveRegion("ADMIN");

// Check module access
var accessResult = await identityService.IsHaveAccess("Product");

IAppCache / Implementations

Caching abstraction with multiple backing stores.

Implementations:

  • NoCacheAppCache - Disabled caching (no-op)
  • MemoryAppCache - IMemoryCache backing
  • RedisAppCache - Redis backing
// Get or create
var data = await cache.GetOrCreateAsync("key", () => FetchData(), TimeSpan.FromMinutes(5));

// Set directly
await cache.SetAsync("key", data, TimeSpan.FromMinutes(5));

// Remove
await cache.RemoveAsync("key");

IRedisCacheService

Redis-specific cache operations.

await redis.SetAsync("key", value, TimeSpan.FromDays(1));
var (found, value) = await redis.TryGetValue<T>("key");
await redis.RemoveAsync("key");
await redis.ExistsAsync("key");
var keys = await redis.GetAllKeysAsync("user:*");

IRedisKeyManager

Builds consistent cache keys with optional tenant scoping.

var key = keyManager.BuildKey("products", "123");  // "products:123"
var tenantKey = keyManager.BuildTenantKey("tenant1", "cache", "key", encrypt: true);

ServiceBase<T> / ServiceBaseWithMapper<T>

Base classes for application services.

public class ProductService : ServiceBaseWithMapper<ProductService>
{
    public ProductService(ILogger<ProductService> logger, IMapper mapper)
        : base(logger, mapper) { }
}

BaseSignalRService

Base class for SignalR hubs with [Authorize] by default.

public class NotificationHub : BaseSignalRService
{
    public NotificationHub(ILogger<NotificationHub> logger) : base(logger) { }
}

Settings

DefaultSetting

Extension methods for configuring MVC, CORS, Swagger, JWT authentication, and hybrid cache.

// In Program.cs
services.AddDefaultConfigures(configuration, environment, "App", "Redis", null, "ADMIN");
app.UseDefaultConfigures(configuration, logging, "App", "ADMIN");

CacheSetting

Hybrid cache configuration. Automatically chooses Redis or in-memory based on configuration.

// Register cached service proxy
services.AddCachedService<IProductService, ProductService>();

Authorization

CustomAuthorizeAttribute

Authorization filter attribute for controllers/actions.

[CustomAuthorize(Region = "ADMIN", Access = "Product:3")]
public class ProductController : ControllerBase<ProductController>
{
}

CustomAuthorizeRequirement

Authorization requirement with Region and Access.

CustomAuthorizationHandler

Authorization handler validating encrypted Region/Access JWT claims.

CustomAuthorizationPolicyProvider

Policy provider for dynamic "CustomAuthorize" policies.

StaticFunction

Utility for authorization.

// Generate module access string with bitwise flags
var access = StaticFunction.GetModuleAccess("Product", ModuleInteractionEnum.Read, ModuleInteractionEnum.Create);
// Returns: "Product:3"

// Generate random string
var random = StaticFunction.GenerateString(16);

ModuleInteractionEnum / ModuleInteraction

Bitwise interaction flags for module permissions.

[Flags]
public enum ModuleInteractionEnum : int
{
    None = 0,
    Read = 1,    // 1 << 0
    Create = 2,  // 1 << 1
    Update = 4,  // 1 << 2
    Delete = 8   // 1 << 3
}

Validation Attributes

RequiredIfOtherHasValueAttribute

Makes a property required when another property has a value.

public class Dto
{
    public string? AlternativeEmail { get; set; }

    [RequiredIfOtherHasValue("AlternativeEmail")]
    [EmailAddress]
    public string? PrimaryEmail { get; set; }
}

RequiredIfOtherIsEmptyAttribute

Makes a property required when another property is empty.

public class Dto
{
    public string? ReferenceCode { get; set; }

    [RequiredIfOtherIsEmpty("ReferenceCode")]
    public string? Name { get; set; }
}

MinItemsAttribute

Validates minimum item count in collections.

[MinItems(1)]
public List<string> Categories { get; set; }

NumericRangeAttribute

Validates numeric values within a range.

[NumericRange(0, 100)]
public int Percentage { get; set; }

Serilog

ClickHouseFormatter

Serilog text formatter outputting JSON for ClickHouse.

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console(new ClickHouseFormatter())
    .CreateLogger();

Complete Setup Example

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDefaultConfigures(
    builder.Configuration,
    builder.Environment,
    "App",
    "Redis",
    null,
    "ADMIN");

var app = builder.Build();

app.UseDefaultConfigures(
    app.Configuration,
    app.Logging,
    "App",
    "ADMIN");

app.MapControllers();
app.Run();

appsettings.json Example

{
  "App": {
    "Name": "MyApp",
    "Origins": ["http://localhost:3000"],
    "Authentication": {
      "Secret": "your-256-bit-secret-key-here-minimum-32-chars",
      "Issuer": "MyApp",
      "Audience": "MyApp",
      "AccessTokenValidityInMinutes": 60
    },
    "AllowedSwagger": true,
    "AllowedCaching": true
  },
  "Redis": {
    "Hosts": ["localhost:6379"],
    "Database": 0,
    "UseCluster": false
  }
}
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
20265.12.13.18 74 5/12/2026
20265.11.14.16 88 5/11/2026
20265.11.10.43 89 5/11/2026
20265.11.10.26 80 5/11/2026
20265.8.13.55 103 5/8/2026
20265.8.13.37 84 5/8/2026
20265.7.23.18 89 5/7/2026
20265.6.20.57 89 5/6/2026
20265.5.16.43 84 5/5/2026
20265.5.16.40 67 5/5/2026
20265.5.16.30 73 5/5/2026
20265.5.16.27 86 5/5/2026
20265.4.11.24 96 5/4/2026
20265.4.11.12 82 5/4/2026
20265.4.10.58 83 5/4/2026
20264.28.14.4 88 4/28/2026
20264.28.10.8 82 4/28/2026
20264.28.10 91 4/28/2026
20264.28.9.51 90 4/28/2026
Loading failed