Fingent-Shared-Core 1.0.3

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

Fingent Shared Core

A foundational shared library for .NET applications that provides essential utilities, extensions, helpers, and custom exception types. Fingent.Shared.Core serves as the core building block for other Fingent packages and provides commonly used functionality across enterprise applications.

🚀 Features

  • Custom Exception Types: Comprehensive exception handling with structured error information
  • Extension Methods: Powerful extension methods for enums, strings, and date/time operations
  • Helper Classes: Utility classes for mathematical operations and date/time calculations
  • JSON Converters: Custom JSON converters for enum serialization
  • Identifiers: Type-safe identifier classes for domain modeling
  • Constants: Common constants for application use
  • Lightweight: Minimal dependencies for maximum compatibility
  • Well-Documented: Comprehensive XML documentation for all public APIs

📦 Installation

dotnet add package Fingent-Shared-Core

🔧 Dependencies

  • .NET 8.0

💻 Usage

Custom Exceptions

using Fingent.Shared.Core.Exceptions;
using System.ComponentModel;

// Define your error enum
public enum ApplicationErrors
{
    [Description("User not found")]
    UserNotFound = 1001,
    
    [Description("Invalid credentials provided")]
    InvalidCredentials = 1002,
    
    [Description("Access denied to the requested resource")]
    AccessDenied = 1003,
    
    [Description("Data validation failed")]
    ValidationFailed = 1004
}

public class UserService
{
    private readonly ILogger<UserService> _logger;
    
    public UserService(ILogger<UserService> logger)
    {
        _logger = logger;
    }
    
    public User GetUser(int userId)
    {
        var user = FindUserById(userId);
        
        if (user == null)
        {
            // Throw exception with enum-based error
            throw new AppException(ApplicationErrors.UserNotFound);
        }
        
        return user;
    }
    
    public void ValidateUser(User user)
    {
        var validationErrors = new List<string>();
        
        if (string.IsNullOrEmpty(user.Email))
            validationErrors.Add("Email is required");
            
        if (string.IsNullOrEmpty(user.Name))
            validationErrors.Add("Name is required");
        
        if (validationErrors.Any())
        {
            // Throw validation exception with multiple errors
            throw new RequestValidationException(
                "User validation failed", 
                validationErrors.ToArray());
        }
    }
    
    public void ProcessUserData(User user)
    {
        try
        {
            // Database operation
            SaveUserToDatabase(user);
        }
        catch (Exception ex)
        {
            // Wrap database exceptions
            throw new DatabaseException("Failed to save user data", ex);
        }
    }
}

Enum Extensions

using Fingent.Shared.Core.Extensions;
using System.ComponentModel;

// Define enums with descriptions
public enum OrderStatus
{
    [Description("Order is pending approval")]
    Pending = 1,
    
    [Description("Order has been approved")]
    Approved = 2,
    
    [Description("Order is being processed")]
    Processing = 3,
    
    [Description("Order has been shipped")]
    Shipped = 4,
    
    [Description("Order has been delivered")]
    Delivered = 5,
    
    [Description("Order has been cancelled")]
    Cancelled = -1
}

public class OrderService
{
    public void DisplayOrderStatus()
    {
        var status = OrderStatus.Processing;
        
        // Get description from enum
        var description = status.ToDescription();
        Console.WriteLine($"Status: {description}");
        // Output: "Status: Order is being processed"
        
        // Convert enum to list of key-value pairs
        var statusList = EnumExtensions.ToList<OrderStatus>();
        foreach (var item in statusList)
        {
            Console.WriteLine($"Value: {item.Key}, Description: {item.Value}");
        }
        
        // Get all enum values as a list
        var allStatuses = EnumExtensions.GetList<OrderStatus>();
        Console.WriteLine($"Total statuses: {allStatuses.Count}");
    }
    
    public List<SelectListItem> GetStatusDropdownItems()
    {
        return EnumExtensions.ToList<OrderStatus>()
            .Select(x => new SelectListItem
            {
                Value = x.Key.ToString(),
                Text = x.Value
            })
            .ToList();
    }
}

public class SelectListItem
{
    public string Value { get; set; }
    public string Text { get; set; }
}

Math Helper

using Fingent.Shared.Core.Helpers;

public class CalculationService
{
    public void PerformCalculations()
    {
        // Safe division that handles division by zero
        var result1 = MathHelper.Divide(10, 3);  // Returns 3 (rounded)
        var result2 = MathHelper.Divide(10, 0);  // Returns 0 (safe)
        
        // Decimal division
        var decimalResult = MathHelper.Divide(10.5m, 3.2m);
        
        // Double division
        var doubleResult = MathHelper.Divide(10.5, 3.2);
        
        // Rounding operations
        var rounded1 = MathHelper.Round(3.14159);        // Returns 3
        var rounded2 = MathHelper.Round(3.14159m);       // Returns 3
        var rounded3 = MathHelper.Round(3.14159m, 2);    // Returns 3.14
        
        Console.WriteLine($"Integer division: {result1}");
        Console.WriteLine($"Decimal division: {decimalResult}");
        Console.WriteLine($"Rounded value: {rounded3}");
    }
    
    public decimal CalculatePercentage(decimal value, decimal total)
    {
        if (total == 0) return 0;
        
        var percentage = MathHelper.Divide(value * 100, total);
        return MathHelper.Round(percentage, 2);
    }
    
    public double CalculateAverage(IEnumerable<double> values)
    {
        if (!values.Any()) return 0;
        
        var sum = values.Sum();
        var count = values.Count();
        
        return MathHelper.Round(MathHelper.Divide(sum, count));
    }
}

Enum Identifiers and Converters

using Fingent.Shared.Core.Identifiers;
using Fingent.Shared.Core.Converters;
using System.Text.Json;
using System.ComponentModel;

public enum Priority
{
    [Description("Low priority")]
    Low = 1,
    
    [Description("Medium priority")]
    Medium = 2,
    
    [Description("High priority")]
    High = 3,
    
    [Description("Critical priority")]
    Critical = 4
}

public class TaskItem
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    
    // Use EnumIdentifier for type-safe enum handling
    public EnumIdentifier Priority { get; set; }
    public DateTime CreatedAt { get; set; }
}

public class TaskService
{
    public void CreateTask()
    {
        var task = new TaskItem
        {
            Id = 1,
            Title = "Fix bug in payment module",
            Description = "Address the issue with payment processing",
            Priority = new EnumIdentifier(Priority.High),
            CreatedAt = DateTime.UtcNow
        };
        
        // Serialize to JSON with custom converter
        var options = new JsonSerializerOptions();
        options.Converters.Add(new EnumConverter());
        
        var json = JsonSerializer.Serialize(task, options);
        Console.WriteLine(json);
        // Output includes: "Priority": "High priority"
    }
    
    public List<TaskItem> GetTasksByPriority(Priority priority)
    {
        // Filter tasks by priority
        return GetAllTasks()
            .Where(t => Convert.ToInt32(t.Priority.Value) == (int)priority)
            .ToList();
    }
    
    private List<TaskItem> GetAllTasks()
    {
        // Mock implementation
        return new List<TaskItem>();
    }
}

Sorting Constants

using Fingent.Shared.Core.Constants;

public class DataService
{
    public List<T> SortData<T>(List<T> data, string sortField, string sortDirection)
    {
        var query = data.AsQueryable();
        
        if (sortDirection == SortingDirections.Ascending)
        {
            // Apply ascending sort
            return ApplySort(query, sortField, true).ToList();
        }
        else if (sortDirection == SortingDirections.Descending)
        {
            // Apply descending sort
            return ApplySort(query, sortField, false).ToList();
        }
        
        return data;
    }
    
    private IQueryable<T> ApplySort<T>(IQueryable<T> query, string sortField, bool ascending)
    {
        // Implementation for dynamic sorting
        // This is a simplified example
        return query;
    }
}

public class UserController : ControllerBase
{
    private readonly DataService _dataService;
    
    public UserController(DataService dataService)
    {
        _dataService = dataService;
    }
    
    [HttpGet]
    public IActionResult GetUsers(
        string sortBy = "Name", 
        string sortDirection = SortingDirections.Ascending)
    {
        var users = GetAllUsers();
        var sortedUsers = _dataService.SortData(users, sortBy, sortDirection);
        
        return Ok(sortedUsers);
    }
    
    private List<User> GetAllUsers()
    {
        // Mock implementation
        return new List<User>();
    }
}

Error Handling Middleware

using Fingent.Shared.Core.Exceptions;

public class GlobalExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionMiddleware> _logger;
    
    public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }
    
    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An unhandled exception occurred");
            await HandleExceptionAsync(context, ex);
        }
    }
    
    private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        
        var response = new ErrorResponse();
        
        switch (exception)
        {
            case AppException appEx:
                response.StatusCode = 400;
                response.Message = appEx.Message;
                response.ErrorCode = appEx.ErrorCode;
                response.Errors = appEx.Errors ?? Array.Empty<string>();
                break;
                
            case RequestValidationException validationEx:
                response.StatusCode = 400;
                response.Message = validationEx.Message;
                response.Errors = validationEx.Errors ?? Array.Empty<string>();
                break;
                
            case DatabaseException dbEx:
                response.StatusCode = 500;
                response.Message = "A database error occurred";
                response.Errors = new[] { dbEx.Message };
                break;
                
            case RateLimitExceededException rateLimitEx:
                response.StatusCode = 429;
                response.Message = rateLimitEx.Message;
                break;
                
            default:
                response.StatusCode = 500;
                response.Message = "An internal server error occurred";
                break;
        }
        
        context.Response.StatusCode = response.StatusCode;
        
        var jsonResponse = JsonSerializer.Serialize(response);
        await context.Response.WriteAsync(jsonResponse);
    }
}

public class ErrorResponse
{
    public int StatusCode { get; set; }
    public string Message { get; set; }
    public int ErrorCode { get; set; }
    public string[] Errors { get; set; } = Array.Empty<string>();
}

// Register middleware in Program.cs
var app = builder.Build();
app.UseMiddleware<GlobalExceptionMiddleware>();

Service Registration and Configuration

// Program.cs
public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddSharedCore(this IServiceCollection services)
    {
        // Configure JSON options with custom converters
        services.ConfigureHttpJsonOptions(options =>
        {
            options.SerializerOptions.Converters.Add(new EnumConverter());
            options.SerializerOptions.Converters.Add(new FullEnumConverter());
        });
        
        // Configure System.Text.Json
        services.Configure<JsonSerializerOptions>(options =>
        {
            options.Converters.Add(new EnumConverter());
            options.Converters.Add(new FullEnumConverter());
        });
        
        return services;
    }
}

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

// Add shared core services
builder.Services.AddSharedCore();

var app = builder.Build();

Domain Modeling with Enum Identifiers

using Fingent.Shared.Core.Identifiers;
using System.ComponentModel;

public enum DocumentType
{
    [Description("PDF Document")]
    PDF = 1,
    
    [Description("Word Document")]
    Word = 2,
    
    [Description("Excel Spreadsheet")]
    Excel = 3,
    
    [Description("PowerPoint Presentation")]
    PowerPoint = 4
}

public enum DocumentStatus
{
    [Description("Document is in draft")]
    Draft = 1,
    
    [Description("Document is under review")]
    Review = 2,
    
    [Description("Document is published")]
    Published = 3,
    
    [Description("Document is archived")]
    Archived = 4
}

public class Document
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public EnumIdentifier Type { get; set; }
    public EnumIdentifier Status { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime UpdatedAt { get; set; }
}

public class DocumentService
{
    public Document CreateDocument(string title, DocumentType type)
    {
        return new Document
        {
            Title = title,
            Type = new EnumIdentifier(type),
            Status = new EnumIdentifier(DocumentStatus.Draft),
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };
    }
    
    public void PublishDocument(Document document)
    {
        if (Convert.ToInt32(document.Status.Value) != (int)DocumentStatus.Review)
        {
            throw new AppException("Document must be in review status before publishing");
        }
        
        document.Status = new EnumIdentifier(DocumentStatus.Published);
        document.UpdatedAt = DateTime.UtcNow;
    }
    
    public List<Document> GetDocumentsByType(DocumentType type)
    {
        return GetAllDocuments()
            .Where(d => Convert.ToInt32(d.Type.Value) == (int)type)
            .ToList();
    }
    
    private List<Document> GetAllDocuments()
    {
        // Mock implementation
        return new List<Document>();
    }
}

🔧 Configuration and Best Practices

Exception Handling Strategy

public class BusinessService
{
    private readonly ILogger<BusinessService> _logger;
    
    public BusinessService(ILogger<BusinessService> logger)
    {
        _logger = logger;
    }
    
    public async Task<BusinessResult> ProcessBusinessLogicAsync(BusinessRequest request)
    {
        try
        {
            // Validate input
            ValidateRequest(request);
            
            // Process business logic
            var result = await ExecuteBusinessLogic(request);
            
            return new BusinessResult { Success = true, Data = result };
        }
        catch (RequestValidationException validationEx)
        {
            _logger.LogWarning("Validation failed: {Message}", validationEx.Message);
            return new BusinessResult 
            { 
                Success = false, 
                Message = validationEx.Message,
                Errors = validationEx.Errors 
            };
        }
        catch (AppException appEx)
        {
            _logger.LogError("Application error: {Message} (Code: {Code})", 
                appEx.Message, appEx.ErrorCode);
            return new BusinessResult 
            { 
                Success = false, 
                Message = appEx.Message,
                ErrorCode = appEx.ErrorCode,
                Errors = appEx.Errors 
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unexpected error in business logic");
            throw new AppException("An unexpected error occurred while processing the request");
        }
    }
    
    private void ValidateRequest(BusinessRequest request)
    {
        var errors = new List<string>();
        
        if (request == null)
            errors.Add("Request cannot be null");
            
        if (string.IsNullOrEmpty(request?.Name))
            errors.Add("Name is required");
            
        if (errors.Any())
            throw new RequestValidationException("Request validation failed", errors.ToArray());
    }
    
    private async Task<object> ExecuteBusinessLogic(BusinessRequest request)
    {
        // Implementation
        await Task.Delay(100);
        return new { Id = 1, Name = request.Name };
    }
}

public class BusinessRequest
{
    public string Name { get; set; }
    public string Description { get; set; }
}

public class BusinessResult
{
    public bool Success { get; set; }
    public string Message { get; set; }
    public int ErrorCode { get; set; }
    public string[] Errors { get; set; } = Array.Empty<string>();
    public object Data { get; set; }
}

🛡️ Best Practices

Exception Handling

  • Use specific exception types for different error scenarios
  • Include detailed error information without exposing sensitive data
  • Log exceptions at appropriate levels
  • Provide user-friendly error messages

Enum Usage

  • Always use description attributes for user-facing enum values
  • Use meaningful enum names and values
  • Consider using EnumIdentifier for domain modeling
  • Leverage extension methods for common enum operations

Mathematical Operations

  • Use MathHelper for safe division operations
  • Always handle division by zero scenarios
  • Use appropriate rounding for financial calculations
  • Consider precision requirements for decimal operations

🏗️ Architecture

The shared core library provides:

  • Foundation: Core utilities used across all Fingent packages
  • Consistency: Standardized exception handling and data structures
  • Type Safety: Strongly-typed identifiers and converters
  • Extensibility: Extension methods for common operations
  • Performance: Lightweight helpers with minimal overhead

⚠️ Considerations

  • String and DateTime extensions are currently internal (placeholders)
  • DateTimeHelper is internal and not yet implemented
  • Consider thread safety when using in concurrent scenarios
  • Exception serialization may need customization for specific use cases

🔮 Future Enhancements

Potential improvements could include:

  • Complete implementation of String and DateTime extensions
  • Additional mathematical operations and helpers
  • More specialized exception types
  • Enhanced JSON serialization options
  • Localization support for error messages
  • Performance optimizations for large-scale operations

👨‍💻 Author

Frebin Francis
Fingent Technology Solutions Pvt Ltd

📄 License

Copyright © 2025 Fingent Technology Solutions Pvt Ltd

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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.
  • net8.0

    • No dependencies.

NuGet packages (5)

Showing the top 5 NuGet packages that depend on Fingent-Shared-Core:

Package Downloads
Fingent-ASPNet-Identity

Package Description

Fingent-Database-Repository-PostgreSQL

A clean and extensible repository layer for PostgreSQL in .NET applications. Data.Repository.PostgreSQL simplifies database access by providing strongly typed repository classes that integrate seamlessly with Entity Framework Core or Dapper. It helps enforce separation of concerns, reduce boilerplate code, and standardize data access patterns.

Fingent-Application-Default

Package Description

Fingent-Services-Default

Package Description

Fingent-Database-Repository-SQL

A lightweight and extensible repository layer for Microsoft SQL Server in .NET applications. Data.Repository.MsSql helps simplify database access by providing reusable repository classes that implement common CRUD operations, while supporting clean architecture principles such as separation of concerns and testability.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.3 366 9/24/2025