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
<PackageReference Include="Fingent-Shared-Core" Version="1.0.3" />
<PackageVersion Include="Fingent-Shared-Core" Version="1.0.3" />
<PackageReference Include="Fingent-Shared-Core" />
paket add Fingent-Shared-Core --version 1.0.3
#r "nuget: Fingent-Shared-Core, 1.0.3"
#:package Fingent-Shared-Core@1.0.3
#addin nuget:?package=Fingent-Shared-Core&version=1.0.3
#tool nuget:?package=Fingent-Shared-Core&version=1.0.3
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 | Versions 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. |
-
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 |