Nera.Lib.Core 1.0.20

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

Nera.Lib.Core

A comprehensive .NET 9 library providing core utilities, extensions, validation, CQRS patterns, logging, and common components for Nera applications.

๐Ÿ“ฆ Installation

dotnet add package Nera.Lib.Core

๐Ÿš€ Quick Start

using Nera.Lib.Core.Builders;
using Nera.Lib.Core.Middlewares;

var builder = WebApplication.CreateBuilder(args);

// Configure Nera Core with fluent API
builder.Services
    .AddNeraCore(builder.Configuration)
    .WithCoreOptions(options =>
    {
        options.ApplicationName = "MyApp";
        options.Version = "v1";
    })
    .WithMediatR()
    .WithValidation()
    .WithLogging()
    .WithTimestampConverter()
    .Build();

var app = builder.Build();

// Use Nera middleware for response transformation
app.UseMiddleware<ResultTransformationMiddleware>();

app.Run();

๐Ÿ“š Table of Contents


โœจ Features

Feature Description
CQRS MediatR integration with Command/Query separation
Validation FluentValidation with automatic pipeline integration
Logging Serilog with Elasticsearch, Console, and File sinks
Result Pattern MethodResult<T> for consistent API responses
Pagination Built-in pagination support with metadata
Exception Handling Global exception handling with localized messages
JSON Converters Unix timestamp converters for DateTime
Response Transformation Automatic API response wrapping

โš™๏ธ Configuration

Builder Pattern

Use the fluent CoreBuilder API to configure services:

builder.Services
    .AddNeraCore(builder.Configuration)
    
    // Core application options
    .WithCoreOptions(options =>
    {
        options.ApplicationName = "MyApp";
        options.Version = "v1";
        options.Environment = "Production";
        options.AcceptedLanguages = "en-US,vi-VN";
    })
    
    // Database configuration
    .WithDatabase(options =>
    {
        options.ConnectionString = "Host=localhost;...";
        options.MaxPoolSize = 100;
        options.CommandTimeout = 30;
    })
    // Or simply:
    // .WithDatabase("Host=localhost;...")
    
    // Redis caching
    .WithRedis(options =>
    {
        options.ConnectionString = "localhost:6379";
        options.InstanceName = "myapp:";
        options.DefaultExpirationMinutes = 60;
    })
    
    // RabbitMQ messaging
    .WithRabbitMq(options =>
    {
        options.ConnectionString = "amqp://guest:guest@localhost:5672";
        options.ExchangeName = "my_exchange";
        options.QueueName = "my_queue";
    })
    
    // Elasticsearch for logging
    .WithElasticsearch(options =>
    {
        options.Url = "http://localhost:9200";
        options.IndexFormat = "logs-{0:yyyy.MM.dd}";
    })
    
    // MediatR with behaviors
    .WithMediatR()
    
    // FluentValidation
    .WithValidation()
    
    // Serilog logging
    .WithLogging(options =>
    {
        options.MinimumLevel = Serilog.Events.LogEventLevel.Information;
        options.UseConsoleLogging = true;
        options.UseFileLogging = true;
        options.LogFilePath = "logs/app.log";
    })
    
    // JSON serialization with Unix timestamps
    .WithTimestampConverter(useSeconds: false) // milliseconds by default
    
    // Scan assemblies for handlers/validators
    .WithAssemblies(typeof(Program).Assembly)
    
    .Build();

Configuration File (appsettings.json)

All options can be configured via appsettings.json:

{
  "NeraCore": {
    "ApplicationName": "MyApp",
    "Version": "v1",
    "Environment": "Production",
    "AcceptedLanguages": "en-US,vi-VN",
    "AllowOrigin": "*"
  },
  "Database": {
    "ConnectionString": "Host=localhost;Port=5432;Database=mydb;Username=postgres;Password=postgres",
    "EnablePooling": true,
    "MinPoolSize": 1,
    "MaxPoolSize": 100,
    "ConnectionTimeout": 30,
    "CommandTimeout": 30
  },
  "Redis": {
    "Enabled": true,
    "ConnectionString": "localhost:6379",
    "InstanceName": "myapp:",
    "DefaultExpirationMinutes": 60,
    "UseSsl": false
  },
  "RabbitMq": {
    "Enabled": true,
    "ConnectionString": "amqp://guest:guest@localhost:5672",
    "ExchangeName": "my_exchange",
    "QueueName": "my_queue",
    "RoutingKey": "my_routing_key"
  },
  "Elasticsearch": {
    "Enabled": true,
    "Url": "http://localhost:9200",
    "Username": "elastic",
    "Password": "changeme",
    "IndexFormat": "logs-{0:yyyy.MM.dd}"
  },
  "JsonSerialization": {
    "UseUnixTimestamp": true,
    "UseSeconds": false,
    "UseCamelCase": true,
    "IgnoreNullValues": true
  },
  "ResponseTransformation": {
    "Enabled": true,
    "IncludeTraceId": true,
    "IncludeProcessingTime": true,
    "ExcludePaths": ["/swagger*", "/health*"]
  }
}

Environment Variables

Environment variables take precedence over configuration files:

Variable Description Default
APPLICATION_NAME Application name Nera.Lib.Core
APP_VERSION Application version v1
ENV_CONNECTION_STRING Database connection string -
ENV_REDIS_CONNECTION_STRING Redis connection string localhost:6379
ENV_REDIS_CACHE_ENABLE Enable Redis caching false
ENV_RABBITMQ_CONNECTION_STRING RabbitMQ connection string -
ENV_ES_URL Elasticsearch URL http://localhost:9200
ENV_ES_LOGS_ENABLE Enable Elasticsearch logging false
ENV_ACCEPT_LANGUAGES Accepted languages en-US
ALLOW_ORIGIN CORS allowed origins *

๐Ÿ—๏ธ Core Components

CQRS Pattern

Commands
using Nera.Lib.Core.CQRS;
using Nera.Lib.Core.Results.ActionResult;

// Define a command
public record CreateUserCommand(string Name, string Email) : ICommand<MethodResult<UserDto>>;

// Implement the handler
public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand, MethodResult<UserDto>>
{
    private readonly IUserRepository _repository;
    
    public CreateUserCommandHandler(IUserRepository repository)
    {
        _repository = repository;
    }
    
    public async Task<MethodResult<UserDto>> Handle(
        CreateUserCommand request, 
        CancellationToken cancellationToken)
    {
        var user = new User { Name = request.Name, Email = request.Email };
        await _repository.AddAsync(user, cancellationToken);
        
        var result = new MethodResult<UserDto>();
        result.AddResult(user.Adapt<UserDto>());
        return result;
    }
}
Queries
// Define a query
public record GetUserByIdQuery(Guid Id) : IQuery<MethodResult<UserDto>>;

// Implement the handler
public class GetUserByIdQueryHandler : IQueryHandler<GetUserByIdQuery, MethodResult<UserDto>>
{
    private readonly IUserRepository _repository;
    
    public async Task<MethodResult<UserDto>> Handle(
        GetUserByIdQuery request, 
        CancellationToken cancellationToken)
    {
        var user = await _repository.GetByIdAsync(request.Id, cancellationToken);
        
        var result = new MethodResult<UserDto>();
        if (user == null)
        {
            result.AddError("NOT_FOUND", "User not found", "User not found", new ErrorResult());
            return result;
        }
        
        result.AddResult(user.Adapt<UserDto>());
        return result;
    }
}

Validation

Validators are automatically discovered and integrated into the MediatR pipeline:

using FluentValidation;
using Nera.Lib.Core.Validation;

public class CreateUserCommandValidator : AbstractValidator<CreateUserCommand>
{
    public CreateUserCommandValidator()
    {
        RuleFor(x => x.Name)
            .NotEmpty().WithMessage("Name is required")
            .MaximumLength(100).WithMessage("Name must not exceed 100 characters");
            
        RuleFor(x => x.Email)
            .NotEmpty().WithMessage("Email is required")
            .EmailAddress().WithMessage("Invalid email format");
    }
}
Common Validation Rules
using Nera.Lib.Core.Validation;

public class MyValidator : AbstractValidator<MyCommand>
{
    public MyValidator()
    {
        // Use common validation rules
        RuleFor(x => x.PhoneNumber).ValidPhoneNumber();
        RuleFor(x => x.Url).ValidUrl();
        RuleFor(x => x.Date).ValidDate();
    }
}

Result Pattern

MethodResult<T>
using Nera.Lib.Core.Results.ActionResult;

// Success result
var result = new MethodResult<UserDto>();
result.AddResult(userDto);
result.AddMessage("User created successfully");

// Error result
var errorResult = new MethodResult<UserDto>();
errorResult.AddError(
    code: "USER_EXISTS",
    message: "User already exists",
    errorMessage: "A user with this email already exists",
    errorResult: new ErrorResult { Details = "email@example.com" }
);
VoidMethodResult
// For operations without return data
var result = new VoidMethodResult();
result.AddMessage("Operation completed successfully");

Pagination

using Nera.Lib.Core.Results.Pagination;

// Create paginated result
var paginatedResult = new PaginatedResult<UserDto>(
    page: 1,
    pageSize: 10,
    count: totalCount,
    data: users
);

// Convert entity to DTO
var dtoResult = paginatedResult.ToResult<UserResponseDto>();

๐Ÿ”ง Middleware

ResultTransformationMiddleware

Automatically wraps API responses in a standard format:

var app = builder.Build();

// Add before other middleware
app.UseMiddleware<ResultTransformationMiddleware>();

app.MapControllers();

Features:

  • Wraps all responses in standard format
  • Adds metadata (traceId, processingTime, timestamp)
  • Handles pagination metadata automatically
  • Translates error messages based on Accept-Language header
  • Excludes gRPC requests automatically
  • Excludes file responses (PDF, images, etc.)

๐Ÿ“ Logging

Basic Configuration

builder.Services
    .AddNeraCore(builder.Configuration)
    .WithLogging(options =>
    {
        options.MinimumLevel = LogEventLevel.Information;
        options.UseConsoleLogging = true;
        options.UseFileLogging = true;
        options.LogFilePath = "logs/app.log";
    })
    .Build();

With Elasticsearch

.WithLogging(options =>
{
    options.UseElasticsearch = true;
    options.ElasticsearchUrl = "http://localhost:9200";
    options.IndexFormat = "myapp-logs-{0:yyyy.MM.dd}";
})

Pre-configured Environments

using Nera.Lib.Core.Logging;

// Development
.WithLogging(_ => SerilogExtensions.CreateDevelopmentOptions())

// Production
.WithLogging(_ => SerilogExtensions.CreateProductionOptions())

// Testing
.WithLogging(_ => SerilogExtensions.CreateTestingOptions())

Sensitive Data Masking

The following data is automatically masked in logs:

  • Passwords, secrets, credentials
  • API keys, tokens
  • Credit card numbers
  • Email addresses, phone numbers
  • SSN, personal identifiers

๐Ÿ“„ JSON Serialization

Unix Timestamp Converter

Configure DateTime to be serialized as Unix timestamps:

builder.Services
    .AddNeraCore(builder.Configuration)
    .WithTimestampConverter(useSeconds: false) // milliseconds
    .Build();

// Or with full options
.WithJsonOptions(options =>
{
    options.UseUnixTimestamp = true;
    options.UseSeconds = false;      // Use milliseconds
    options.UseCamelCase = true;
    options.IgnoreNullValues = true;
})

Manual Configuration

using Nera.Lib.Core.Extensions;

// Get pre-configured JsonSerializerOptions
var options = JsonOptionsExtensions.CreateNeraJsonOptions(useSeconds: false);

// Or configure MVC JSON options
builder.Services.AddNeraJsonOptions(useSeconds: false);

๐Ÿ• DateTime Handling

Request (Input)

The library accepts both formats in requests:

// ISO 8601 format
{ "createdAt": "2025-12-03T10:30:00Z" }

// Unix timestamp (milliseconds)
{ "createdAt": 1733224200000 }

// Unix timestamp (seconds) - auto-detected
{ "createdAt": 1733224200 }

Response (Output)

All DateTime values are returned as Unix timestamps (milliseconds):

{
  "data": {
    "id": "123",
    "createdAt": 1733224200000,
    "updatedAt": 1733310600000
  },
  "_metadata": {
    "timestamp": 1733224200000
  }
}

โš ๏ธ Exception Handling

Built-in Exceptions

using Nera.Lib.Core.Exceptions;

// 400 Bad Request
throw new BadRequestException("Invalid input");
throw new InvalidValidatorException("Validation failed");
throw new BusinessRuleViolationException("Business rule violated");

// 401 Unauthorized
throw new UnAuthorizeException("Authentication required");

// 403 Forbidden
throw new ForbidException("Access denied");

// 404 Not Found
throw new NotFoundException("Resource not found");

// 500 Internal Server Error
throw new InternalServerException("An error occurred");

Exception to HTTP Status Mapping

Exception Status Code
BadRequestException 400
InvalidValidatorException 400
BusinessRuleViolationException 400
UnAuthorizeException 401
ForbidException 403
NotFoundException 404
InternalServerException 500

Localized Error Messages

Error messages are automatically translated based on Accept-Language header:

// Add error resources
// Resources/CommonErrors-en.json
{
  "USER_NOT_FOUND": "User not found"
}

// Resources/CommonErrors-vi.json
{
  "USER_NOT_FOUND": "Khรดng tรฌm thแบฅy ngฦฐแปi dรนng"
}

๐Ÿ“‹ API Response Format

Success Response

{
  "status": "Success",
  "message": "Success",
  "data": {
    "id": "123",
    "name": "John Doe",
    "createdAt": 1733224200000
  },
  "_metadata": {
    "traceId": "0HNEFIIB8HKSG:00000001",
    "processingTime": 45,
    "timestamp": 1733224200000
  }
}

Paginated Response

{
  "status": "Success",
  "message": "Success",
  "data": [
    { "id": "1", "name": "User 1" },
    { "id": "2", "name": "User 2" }
  ],
  "_metadata": {
    "traceId": "0HNEFIIB8HKSG:00000001",
    "processingTime": 120,
    "timestamp": 1733224200000,
    "pagination": {
      "page": 1,
      "pageSize": 10,
      "count": 2,
      "total": 50,
      "totalPages": 5,
      "hasPreviousPage": false,
      "hasNextPage": true
    }
  }
}

Error Response

{
  "status": "Fail",
  "message": "Validation failed",
  "data": null,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "One or more validation errors occurred",
    "details": [
      { "field": "email", "message": "Invalid email format" }
    ]
  },
  "_metadata": {
    "traceId": "0HNEFIIB8HKSG:00000001",
    "processingTime": 5,
    "timestamp": 1733224200000
  }
}

๐Ÿ—๏ธ Requirements

  • .NET 9.0 or later
  • ASP.NET Core 9.0 (for web features)

๐Ÿ“ฆ Dependencies

  • FluentValidation 12.x
  • MediatR 13.x
  • Serilog 4.x
  • Mapster 7.x
  • System.Text.Json 9.x

๐Ÿ“– Examples

See the Examples folder for complete working examples.

๐Ÿค Contributing

We welcome contributions! Please see our Contributing Guide for details.

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿข About

Developed by Nextera Systems for building robust .NET applications.


Version: 1.0.0
Target Framework: .NET 9.0
Repository: https://github.com/nextera-systems/nera-lib-core

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (11)

Showing the top 5 NuGet packages that depend on Nera.Lib.Core:

Package Downloads
Nera.Lib.Web

Web models, business rules, aggregates, value objects, and domain services for Nera applications

Nera.Lib.Database

Database access layer with Entity Framework Core, Repository pattern, Specification pattern, and advanced querying capabilities for Nera applications

Nera.Lib.Messaging.Abstractions

Complete messaging abstractions with MassTransit implementation

Nera.Lib.Domain

Domain models, business rules, aggregates, value objects, and domain services for Nera applications

Nera.Lib.Infrastructure

Infrastructure services and implementations for Nera applications

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.20 680 12/2/2025
1.0.19 277 11/27/2025
1.0.18 588 11/13/2025
1.0.17 709 11/9/2025
1.0.16 200 11/9/2025
1.0.15 166 11/9/2025
1.0.14 787 10/18/2025
1.0.13 261 10/13/2025
1.0.12 175 10/12/2025
1.0.11 474 9/28/2025
1.0.10 174 9/27/2025
1.0.9 267 9/15/2025
1.0.8 1,291 9/9/2025
1.0.7 192 9/2/2025
1.0.6 911 8/3/2025
1.0.5 141 8/2/2025
1.0.4 100 8/2/2025
1.0.3 99 8/1/2025
1.0.2 161 7/31/2025
1.0.1 683 7/27/2025
1.0.0 306 7/27/2025