CSharpEssentials is a comprehensive library that enhances C#'s functional programming capabilities. It provides a robust set of tools and utilities designed to make your C# applications more maintainable, testable, and aligned with functional programming principles.
- NuGet Package: CSharpEssentials
- NuGet Package EntityFrameworkCore: CSharpEssentials.EntityFrameworkCore
- NuGet Package AspNetCore: CSharpEssentials.AspNetCore
- NuGet Package RequestResponseLogging: CSharpEssentials.RequestResponseLogging
- NuGet Package GcpSecretManager: CSharpEssentials.GcpSecretManager
- GitHub Repository: SenRecep/CSharpEssentials
- Author: Recep Εen
- Functional Programming Support: Enhanced functional programming capabilities for C#
- Type Safety: Strong type safety across all modules
- Error Handling: Comprehensive error handling with Result pattern
- Domain-Driven Design: Support for DDD patterns and practices
- Performance: Optimized for high performance with modern C# features
- Testing: Built with testability in mind
Maybe<T>
- Safe handling of nullable values:
Maybe<string> someValue = Maybe.From("Hello");
Maybe<string> noValue = Maybe.None;
// LINQ support
var result = someValue
.Select(str => str.ToUpper())
.Where(str => str.Length > 5);
Result<T>
- Functional approach to error handling:
public Result<User> CreateUser(UserDto dto)
{
if (string.IsNullOrEmpty(dto.Email))
return Error.Validation("EMAIL_REQUIRED", "Email is required");
var user = new User(dto);
return Result<User>.Success(user);
}
RuleEngine
- Complex business rule management:
public class EmailValidationRule : IRule<string>
{
public Result Evaluate(string email, CancellationToken cancellationToken = default)
{
return email.Contains("@")
? Result.Success()
: Error.Validation("INVALID_EMAIL", "Email must contain @");
}
}
Error
- Structured error handling:
var error = Error.Validation(
code: "USER_INVALID_AGE",
description: "User age must be greater than 18"
);
Any<T0,T1,...>
- Type-safe union types:
public Any<string, int> ParseOrKeepAsString(string input)
{
return int.TryParse(input, out int number)
? number
: input;
}
EntityFrameworkCore
- Enhanced EF Core support with functional patterns:
public class Product : SoftDeletableEntityBase<Guid>
{
private Product(string name, decimal price)
{
Id = Guid.NewGuid();
Name = name;
Price = price;
}
public static Product Create(string name, decimal price)
{
var product = new Product(name, price);
product.Raise(new ProductCreatedEvent(product.Id));
return product;
}
}
// Configure in DbContext
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.SoftDeletableEntityBaseGuidIdMap();
builder.OptimisticConcurrencyVersionMap();
}
DateTimeProvider
- Testable datetime handling:
public class OrderService
{
private readonly IDateTimeProvider _dateTimeProvider;
public Order CreateOrder()
{
return new Order { CreatedAt = _dateTimeProvider.UtcNow };
}
}
JSON
- Enhanced JSON capabilities:
var options = EnhancedJsonSerializerOptions.DefaultOptions;
string json = myObject.ConvertToJson(options);
Extensions
- Useful extension methods:
// String transformations
"helloWorld".ToPascalCase(); // => "HelloWorld"
"hello_world".ToCamelCase(); // => "helloWorld"
// Collection operations
var randomItem = list.GetRandomItem();
RequestResponseLogging
- Comprehensive HTTP traffic monitoring:
public void Configure(IApplicationBuilder app)
{
app.AddRequestResponseLogging(opt =>
{
// Configure logging options
var loggingOptions = LoggingOptions.CreateAllFields();
loggingOptions.HeaderKeys.Add("X-Correlation-Id");
// Use the configured logger
opt.UseLogger(app.Services.GetRequiredService<ILoggerFactory>(), loggingOptions);
});
}
AspNetCore
- Enhanced ASP.NET Core capabilities:
public void ConfigureServices(IServiceCollection services)
{
services
.AddExceptionHandler<GlobalExceptionHandler>()
.ConfigureModelValidatorResponse()
.ConfigureSystemTextJson()
.AddEnhancedProblemDetails()
.AddAndConfigureApiVersioning()
.AddSwagger<DefaultConfigureSwaggerOptions>(
SecuritySchemes.JwtBearerTokenSecurity,
Assembly.GetExecutingAssembly()
);
}
public void Configure(IApplicationBuilder app)
{
app.UseVersionableSwagger();
app.UseExceptionHandler();
app.UseStatusCodePages();
}
GcpSecretManager
- Seamless integration with Google Cloud Secret Manager:
// Basic configuration in Program.cs or Startup.cs
builder.Configuration.AddGcpSecretManager();
// Advanced configuration with options
builder.Configuration.AddGcpSecretManager(options =>
{
options.CredentialsPath = "/path/to/credentials.json";
options.AddProject(new ProjectSecretConfiguration
{
ProjectId = "your-gcp-project-id",
Region = "europe-west1",
PrefixFilters = ["app_", "service_"],
SecretIds = ["specific-secret1"],
RawSecretIds = ["config-json"], // Skip JSON parsing for these secrets
RawSecretPrefixes = ["raw_"] // Skip JSON parsing for secrets with these prefixes
});
});
// Configuration in appsettings.json
{
"GoogleSecretManager": {
"Projects": [
{
"ProjectId": "your-gcp-project-id",
"Region": "europe-west1",
"PrefixFilters": ["app_"],
"SecretIds": ["specific-secret1"],
"RawSecretIds": ["config-json"],
"RawSecretPrefixes": ["raw_"]
}
]
}
}
Key features:
- Seamless integration with .NET configuration system
- Region-specific secret management
- Flexible secret filtering with prefix and exact matches
- JSON value flattening with control over parsing behavior
- Batch processing for optimal performance
- Automatic secret rotation support
- Built-in retry policies for resilience
- Use region-specific endpoints for better latency
- Implement proper credentials management
- Use prefix filters to limit secret access
- Configure appropriate batch sizes
- Monitor secret loading performance
- Implement proper error handling
- Use JSON flattening for complex values with control over parsing behavior
- Configure proper retry policies
- Use RawSecretIds and RawSecretPrefixes to control JSON parsing behavior
Choose the packages you need:
dotnet add package CSharpEssentials
dotnet add package CSharpEssentials.EntityFrameworkCore
dotnet add package CSharpEssentials.AspNetCore
dotnet add package CSharpEssentials.RequestResponseLogging
dotnet add package CSharpEssentials.GcpSecretManager
You can also install the packages directly from the NuGet Gallery.
Import the required namespaces based on your needs:
// Core functionality
using CSharpEssentials;
// Entity Framework Core integration
using CSharpEssentials.EntityFrameworkCore;
// ASP.NET Core integration
using CSharpEssentials.AspNetCore;
// Request Response Logging
using CSharpEssentials.RequestResponseLogging;
- Maybe Monad - Null-safe programming with Maybe pattern
- Result Pattern - Railway-oriented programming with Result types
- Any Type (Discriminated Unions) - Type-safe union types for C#
- Extensions - Functional programming extension methods
- Rule Engine - Business rule validation and processing
- Error Types - Structured error handling system
- Entity Base - Base classes and patterns for domain entities
- JSON Utilities - Enhanced JSON serialization and handling
- Time Management - Testable datetime operations
- ASP.NET Core Integration
- Global exception handling
- API versioning
- Swagger integration
- Problem Details support
- Model validation
- Security configurations
- Entity Framework Core Integration
- Soft delete support
- Audit logging
- Query interceptors
- Domain events
- Optimistic concurrency
- Entity configurations
- Request Response Logging
- HTTP traffic monitoring
- Request/Response logging
- Performance tracking
- Custom log writers
- Google Cloud Secret Manager Integration
- Configuration provider integration
- Region-specific secret management
- Flexible secret filtering
- Batch processing support
- JSON value flattening
- Automatic secret rotation
- Built-in retry policies
- Use
Result<T>
for operations that can fail - Prefer
Maybe<T>
over null values for optional values - Use structured
Error
types for domain errors - Chain operations with LINQ-style methods on
Result<T>
- Handle validation errors separately from domain errors
- Use
Error.Validation()
for input validation failures - Use
Error.NotFound()
for resource not found scenarios - Use
Error.Unauthorized()
for authentication/authorization failures
- Extend
EntityBase
for domain entities - Use
RuleEngine
for complex validations - Implement domain events for state changes
- Keep entities immutable where possible
- Use static factory methods for entity creation
- Encapsulate business rules within the domain model
- Use value objects for complex value types
- Implement
IRule<T>
for reusable business rules
- Use
Any<T0,T1>
for type-safe union types - Leverage extension methods for fluent interfaces
- Use pure functions where possible
- Avoid side effects in business logic
- Use immutable collections when appropriate
- Chain operations using LINQ and functional extensions
- Use pattern matching with discriminated unions
- Use global exception handling middleware
- Configure proper API versioning
- Implement proper request/response logging
- Use problem details for error responses
- Configure Swagger documentation properly
- Use proper security headers
- Implement proper model validation
- Use proper HTTP status codes
- Use
SoftDeletableEntityBase
for soft delete support - Configure proper entity type configurations
- Use optimistic concurrency where needed
- Implement proper audit logging
- Use proper indexing strategies
- Configure proper lazy loading settings
- Use proper query tracking behavior
- Monitor slow queries with interceptors
- Use
DateTimeProvider
for time-dependent tests - Mock interfaces instead of concrete implementations
- Utilize
Result<T>
for predictable error scenarios - Write unit tests for business rules
- Test error scenarios thoroughly
- Use proper test data builders
- Implement integration tests for critical paths
- Test validation rules independently
- Use proper caching strategies
- Implement proper database indexing
- Use async/await properly
- Avoid N+1 query problems
- Use proper connection pooling
- Implement proper response compression
- Monitor and log performance metrics
- Use proper batch operations
- Use region-specific endpoints for better latency
- Implement proper credentials management
- Use prefix filters to limit secret access
- Configure appropriate batch sizes
- Monitor secret loading performance
- Implement proper error handling
- Use JSON flattening for complex values with control over parsing behavior
- Configure proper retry policies
- Use RawSecretIds and RawSecretPrefixes to control JSON parsing behavior
We welcome contributions! Please see our Contributing Guide for details.
This project is licensed under the MIT License - see the LICENSE file for details.
This library was inspired by and builds upon the work of several excellent open-source projects:
- ErrorOr - A simple, fluent discriminated union of an error or a result
- CSharpFunctionalExtensions - Functional extensions for C#
- OneOf - Easy to use F#-like discriminated unions for C#
- TechBuddySolution - The foundation for our Request Response Logging module
Special thanks to all contributors who have helped shape this library and to the maintainers of these inspiring projects.
For support, please open an issue in the GitHub repository or contact the maintainers.
Take a look at SenRecep.Aspire, a modern microservices template built with .NET Aspire 9.0. The template provides a robust foundation for building scalable, maintainable, and cloud-ready microservices applications. Check out the GitHub repository for more details.
- Add the following configuration to your
appsettings.json
:
{
"GoogleSecretManager": {
"Projects": [
{
// Required: Your Google Cloud project ID
"ProjectId": "your-gcp-project-id",
// Optional: Specific region for better latency (e.g., "europe-west1", "us-central1")
"Region": "europe-west1",
// Optional: Only load secrets with these prefixes
"PrefixFilters": ["app_", "service_"],
// Optional: Load only these specific secrets
"SecretIds": ["database-password", "api-key"],
// Optional: Skip JSON parsing for these specific secrets
"RawSecretIds": ["config-json", "plain-text"],
// Optional: Skip JSON parsing for secrets with these prefixes
"RawSecretPrefixes": ["raw_", "text_"]
}
]
}
}
- Configure the secret manager in your application:
var builder = WebApplication.CreateBuilder(args);
// Add GCP Secret Manager configuration
builder.Configuration.AddGcpSecretManager();