A comprehensive .NET Standard 2.1 utility library providing robust, production-ready tools for common development tasks. ClearTools offers utilities for string manipulation, cryptography, image processing, Azure services integration, HTTP client operations, and much more.
dotnet add package ClearToolsusing ClearTools.Extensions;
using Clear.Tools;
// String extensions
string text = "Hello 123 World!";
int number = text.ToInt32(); // Extracts numbers: 123
string cleaned = StringUtility.StripSymbols(text); // Removes symbols, preserves spaces: "Hello 123 World"
// Image processing
var scaledImage = ImageUtility.ScaleImage(originalImage, 800, 600);
// Cryptography
string salt = Crypto.CreateSalt();
string hash = Crypto.EncodeSHA256("password", salt);
// OTP generation
var otpResult = OtpUtility.GenerateCode("user@example.com", 12345, TimeSpan.FromMinutes(5));NEW! Strongly-typed, attribute-driven configuration framework for parsing and managing connection strings and key-value configuration strings.
- β Strongly-typed connection strings with compile-time safety
- β
Attribute-driven property mapping with
[ConnectionStringKey] - β
Built-in validation using
[Required]attribute - β 10+ pre-built types for Azure and non-Azure services
- β
DI integration via
AddConnectionString<T>() - β Customizable delimiters, escaping, and case sensitivity
- β Bidirectional parsing and serialization (ToString())
- β Extensible - easily create custom configuration types
using ClearTools.Configuration.BuiltIn;
using ClearTools.Extensions;
// Parse SQL Server connection string
var sqlConfig = new SqlServerConnectionString(
"Server=localhost;Database=MyDb;User Id=sa;Password=mypass");
Console.WriteLine(sqlConfig.Server); // "localhost"
Console.WriteLine(sqlConfig.Database); // "MyDb"
// Register with DI
services.AddConnectionString<SqlServerConnectionString>(
configuration, "ConnectionStrings:MyDatabase");
// Inject into services
public class MyService
{
public MyService(SqlServerConnectionString config)
{
_connectionString = config.ToString();
}
}Azure Services:
ServiceBusConnectionString- Azure Service BusAppConfigurationConnectionString- Azure App ConfigurationKeyVaultConnectionString- Azure Key VaultSqlServerConnectionString- SQL Server / Azure SQLCosmosDbConnectionString- Azure Cosmos DBBlobStorageConnectionString- Azure Blob Storage
Non-Azure Services:
MongoDbConnectionString- MongoDBPostgreSqlConnectionString- PostgreSQLRedisConnectionString- RedisRabbitMqConnectionString- RabbitMQ
public class MyServiceConfig : ConnectionStringBase
{
[ConnectionStringKey("ApiUrl")]
[Required]
public string? ApiUrl { get; set; }
[ConnectionStringKey("ApiKey")]
[Required]
public string? ApiKey { get; set; }
[ConnectionStringKey("Timeout")]
public int? Timeout { get; set; }
public MyServiceConfig(string connectionString)
: base(connectionString) { }
}
// Store in Key Vault as single string
// "ApiUrl=https://api.example.com;ApiKey=secret123;Timeout=30"
// Use with DI
services.AddConnectionString<MyServiceConfig>(keyVaultSecret);- Custom delimiters: Use
|,,, or any delimiter instead of; - Escaping support: Include delimiters in values with
\; - Case sensitivity: Configure case-sensitive or insensitive key matching
- Validation: Required properties throw exceptions if missing
- Serialization: Convert back to string with
ToString()(excludes nulls)
See full documentation for comprehensive examples.
- Connection String Framework
- Core Utilities
- Extension Methods
- Azure Integration
- HTTP Client
- Middleware
- Data Models
- Installation & Setup
- Examples
- Documentation
- Publishing to NuGet
- Contributing
- License
Comprehensive string manipulation and processing tools:
// URL and SEO-friendly string generation
string urlKey = StringUtility.GenerateUrlKey("My Blog Post Title!"); // "my-blog-post-title"
// HTML and symbol stripping
string cleanText = StringUtility.StripHTML("<p>Hello <b>World</b></p>"); // "Hello World"
string alphanumeric = StringUtility.StripSymbols("Hello @World! 123"); // "Hello World 123"
// Date-based unique identifiers
string dateCode = StringUtility.GetDateCode(); // File time-based code
string updateId = StringUtility.AddUpDate(); // Timestamp-based ID
// Tag generation
string tags = StringUtility.GenerateTags("tag1", "tag2", "tag3"); // "tag1,tag2,tag3"Advanced image manipulation capabilities:
// Image scaling with aspect ratio preservation
Image scaledImage = ImageUtility.ScaleImage(sourceImage, 800, 600, ImageSizePreference.Width);
// Image cropping and resizing
Image croppedImage = ImageUtility.CropImage(sourceBitmap, 300, 300);
Bitmap resizedImage = ImageUtility.ResizeImage(sourceImage, 400, 300);
// Format conversion
byte[] imageBytes = ImageUtility.ConvertBitmapToBytes(bitmap, ImageFormat.Jpeg);
string base64Image = ImageUtility.ConvertImageToBase64(image, ImageFormat.Png);
// High-quality JPEG saving
ImageUtility.SaveJpegToFile("output.jpg", image, quality: 85);string key = "MySecretEncryptionKeyThatIsLongEnough123"; // 32+ chars required
string encrypted = Encryption.Encrypt("sensitive data", key);
string decrypted = Encryption.Decrypt(encrypted, key);// Hashing algorithms
string salt = Crypto.CreateSalt(128);
string sha256Hash = Crypto.EncodeSHA256("password", salt);
string sha512Hash = Crypto.EncodeSHA512("password", salt);
string sha1Hash = Crypto.EncodeSHA1("password");
// Base64 encoding/decoding
string encoded = Crypto.EncodeBase64("text to encode");
string decoded = Crypto.DecodeBase64(encoded);// Generate OTP with custom expiry
var otpResult = OtpUtility.GenerateCode("user@example.com", 12345, TimeSpan.FromMinutes(5));
Console.WriteLine($"Code: {otpResult.Code}, Expires: {otpResult.ExpiryTime}");
// Validate OTP
bool isValid = OtpUtility.ValidateCode("user@example.com", 12345, "123456", otpResult.ExpiryTime);Convert numbers between different bases and formats:
// Convert from any base to decimal
long decimal = BaseConverter.ConvertToDecimal("1010", 2); // Binary to decimal: 10
long hexDecimal = BaseConverter.ConvertToDecimal("FF", 16); // Hex to decimal: 255
// Convert decimal to any base
string binary = BaseConverter.ConvertFromDecimal(10, 2); // "1010"
string hex = BaseConverter.ConvertFromDecimal(255, 16); // "FF"
// Convert to alphabetic representation
string alpha = BaseConverter.ConvertToAlpha(26); // "BA"Parse and convert EditorJS content to HTML:
// Parse EditorJS JSON to HTML
string html = EditorJS.Parse(editorJsJsonString);
// Supports: headers, paragraphs, lists, images, embeds (YouTube, Vimeo)Powerful string manipulation extensions:
// Value toggling
string toggled = "active".Toggle("inactive"); // "inactive"
// Case-insensitive operations
bool contains = "Hello World".Search("WORLD"); // true
bool equals = "Hello".EqualsNoCase("HELLO"); // true
// Number and symbol extraction
string numbers = "abc123def456".ExtractNumbers(); // "123456"
string clean = "Hello;World*".StripSymbols(); // "HelloWorld" (removes specific symbols)
// Type conversions
int number = "abc123".ToInt32(); // 123
decimal price = "Price: $29.99".ToDecimal(); // 29.99
// CSV processing
List<string> items = "apple,banana,cherry".ToListFromCsv();
HashSet<string> uniqueItems = "apple,banana,apple".ToHashSetFromCsv();Enhanced DateTime formatting:
DateTime now = DateTime.Now;
string dateStr = now.ToDateString(); // "15/Aug/2025"
string dateTimeStr = now.ToDateTimeString(); // "15/Aug/2025 14:30:15"NEW in v3.2.1 - Fluent conditional string building:
using System.Text;
using ClearTools.Extensions;
var sb = new StringBuilder();
// Conditionally append content based on boolean conditions
sb.AppendIfTrue(isActive, "Active")
.AppendIfTrue(hasWarnings, " (warnings)")
.AppendLineIfTrue(isComplete, "Process complete");
// Example: Build dynamic messages
bool isAdmin = true;
bool hasErrors = false;
string message = new StringBuilder()
.Append("User logged in")
.AppendIfTrue(isAdmin, " with admin privileges")
.AppendIfTrue(hasErrors, " - errors detected")
.ToString();
// Result: "User logged in with admin privileges"
// Example: Conditional HTML generation
var html = new StringBuilder()
.Append("<div class='user'")
.AppendIfTrue(isPremium, " premium")
.AppendIfTrue(isVerified, " verified")
.AppendLine(">")
.AppendLineIfTrue(showDetails, "<p>User details...</p>")
.Append("</div>");NEW in v3.2.0 - Comprehensive Azure App Configuration support with advanced features:
// Define settings class with regular config and feature flags
public class AppSettings
{
public string DatabaseConnectionString { get; set; }
[AppConfigurationKey("MyApp:ApiKey")]
public string ApiKey { get; set; }
public int MaxRetries { get; set; }
// Feature flags (bool/bool? only)
[FeatureFlag("enable-new-ui")]
public bool NewUiEnabled { get; set; }
[FeatureFlag("beta-features")]
public bool? BetaFeaturesEnabled { get; set; }
}
// Web Applications - Using Managed Identity (recommended for Azure)
var builder = WebApplication.CreateBuilder(args);
builder.AddAppConfigurationForWebApplication<AppSettings>(
appConfigEndpoint: new Uri("https://myapp.azconfig.io/"),
out AppSettings settings,
label: "Production", // Environment-specific config
keyFilter: "MyApp:*", // Filter keys by prefix
credential: new DefaultAzureCredential()
);
// Web Applications - Using Connection String (flexible)
builder.AddAppConfigurationForWebApplication<AppSettings>(
connectionString: Environment.GetEnvironmentVariable("AppConfigConnectionString"),
out AppSettings settings,
label: "Staging"
);
// Azure Functions - Direct client access with environment fallback
hostBuilder.AddAppConfigurationForAzureFunctions<AppSettings>(
appConfigEndpoint: new Uri("https://myapp.azconfig.io/"),
out AppSettings functionSettings,
skipDevelopment: true // Uses environment variables in dev
);
// Optional: Configuration refresh with sentinel keys
var refreshOptions = new AppConfigurationRefreshOptions
{
EnableRefresh = true,
RefreshInterval = TimeSpan.FromMinutes(5), // Minimum 30s recommended
SentinelKeys = new[] { "AppSettings:Version" }, // Trigger refresh
OnRefreshError = ex => logger.LogWarning(ex, "Config refresh failed")
};
builder.AddAppConfigurationForWebApplication<AppSettings>(
appConfigEndpoint: new Uri("https://myapp.azconfig.io/"),
out AppSettings settings,
refreshOptions: refreshOptions
);Key Features:
- β Label-based environment configs (Production, Staging, Development)
- β
Key filtering with wildcards (
MyApp:*,Database:*) - β Attribute-based feature flags with bool validation
- β Optional auto-refresh with sentinel keys
- β Managed Identity or connection string authentication
- β Development fallback to environment variables
- β Automatic type conversion and error handling
Robust Azure Key Vault integration for secrets management:
// Define your settings class
public class AppSettings
{
public string DatabaseConnectionString { get; set; }
[KeyVaultKey("api-key")]
public string ApiKey { get; set; }
}
// For ASP.NET Web Applications
var builder = WebApplication.CreateBuilder(args);
builder.AddKeyVaultForWebApplication<AppSettings>(
keyVaultUri: "https://your-keyvault.vault.azure.net/",
out AppSettings settings
);
// For Azure Functions
hostBuilder.AddKeyVaultForAzureFunctions<AppSettings>(
keyVaultUri: "https://your-keyvault.vault.azure.net/",
out AppSettings functionSettings
);Azure Blob Storage operations:
string connectionString = "DefaultEndpointsProtocol=https;AccountName=...";
// Upload operations
AzureStorageManager.UploadToAzure(connectionString, "container", stream, "application/pdf", "file.pdf", "folder");
// Download operations
AzureStorageManager.DownloadFromAzure(connectionString, "container", fileInfo, "folder");
// Check folder existence
bool exists = AzureStorageManager.AzureFolderExists(connectionString, "container", "folder");Automatic service registration by interface:
// Register all services implementing IService
services.AddScopedServicesByInterface<IService>();
services.AddSingletonServicesByInterface<IRepository>();
services.AddTransientServicesByInterface<IValidator>();Comprehensive HTTP client with built-in error handling and serialization:
// Initialize
var apiClient = new ApiClient(httpClient);
// GET with various options
var user = await apiClient.GetAsync<User>("https://api.example.com/users/1");
var userWithAuth = await apiClient.GetAsync<User>("https://api.example.com/users/1", bearerToken);
// POST operations
var response = await apiClient.PostAsync("https://api.example.com/users", newUser);
var createdUser = await apiClient.PostAsync<User, User>("https://api.example.com/users", newUser);
// reCAPTCHA validation
var captchaResult = await apiClient.ValidateGoogleCaptcharAsync(secretKey, response, remoteIp);ASP.NET Core middleware for API key validation with flexible path exclusion:
// Basic setup
services.AddRequestValidation("your_secret_api_key", skipForDevelopment: true);
app.UseRequestValidation();
// With excluded paths (e.g., health checks, public endpoints)
services.AddRequestValidation(
"your_secret_api_key",
skipForDevelopment: true,
skipRootEndPoint: true,
excludedPaths: new[] { "/health", "/api/public", "/webhooks" }
);
app.UseRequestValidation();
// Using RequestValidationOption for more control
var options = new RequestValidationOption(
validationKey: "your_secret_api_key",
skipForDevelopment: true,
skipForRootEndPoint: true,
excludedPaths: new[] { "/health", "/metrics", "/api/public" }
);
services.AddSingleton(new RequestValidationMiddleware(options));
app.UseRequestValidation();
// Client usage - include key in headers
client.DefaultRequestHeaders.Add("key", "your_secret_api_key");Features:
- API Key Validation: Validates incoming requests using a header-based key
- Development Skip: Optionally skip validation for localhost during development
- Root Endpoint Skip: Optionally skip validation for the root endpoint (
/) - Path Exclusion: Exclude specific paths from validation (case-insensitive)
- Supports exact path matching:
/healthmatches only/health - Supports prefix matching:
/api/publicmatches/api/public,/api/public/users, etc.
- Supports exact path matching:
- Flexible Configuration: Use simple parameters or
RequestValidationOptionfor advanced scenarios
Common Use Cases for Excluded Paths:
- Health check endpoints (
/health,/healthz) - Metrics endpoints (
/metrics,/prometheus) - Public API routes (
/api/public) - Webhook receivers that use their own validation
- Static file paths or public documentation
Type-safe enumeration base class with value and name support:
// Define your SmartEnum
public class OrderStatus : SmartEnum<OrderStatus>
{
public static readonly OrderStatus Pending = new OrderStatus("Pending", 1);
public static readonly OrderStatus Processing = new OrderStatus("Processing", 2);
public static readonly OrderStatus Shipped = new OrderStatus("Shipped", 3);
public static readonly OrderStatus Delivered = new OrderStatus("Delivered", 4);
private OrderStatus(string name, int value) : base(name, value) { }
}
// Usage examples
var status = OrderStatus.Parse(2); // Get by value: Processing
var statusByName = OrderStatus.Parse("Shipped"); // Get by name: Shipped
// List all values
foreach (var status in OrderStatus.List())
{
Console.WriteLine($"{status.Name}: {status.Value}");
}
// Type-safe comparisons
OrderStatus current = OrderStatus.Processing;
if (current.Equals(OrderStatus.Processing))
{
Console.WriteLine("Order is being processed");
}Features:
- Type-safe enumeration pattern
- Parse by value or name (case-insensitive)
- List all enum values
- Strongly-typed with compile-time safety
- Thread-safe initialization
Chainable dictionary operations with fluent API:
using Clear;
// Create and populate in one fluent chain
var config = new FluentDictionary<string, string>()
.Add("host", "localhost")
.Add("port", "5432")
.Add("database", "mydb")
.Add("username", "admin");
// Use the static factory method
var settings = FluentDictionary<string, int>.Create("timeout", 30)
.Add("retries", 3)
.Add("maxConnections", 100);
// Chain Add and Remove operations
var userPrefs = new FluentDictionary<string, bool>()
.Add("darkMode", true)
.Add("notifications", true)
.Add("autoSave", false)
.Remove("autoSave")
.Add("autoSave", true);
// All Dictionary<TKey, TValue> methods available
bool hasKey = config.ContainsKey("host");
bool hasValue = config.TryGetValue("port", out string portValue);Features:
-
Fluent, chainable API for dictionary operations
-
Returns
thisfor method chaining onAdd()andRemove() -
Static
Create()factory method for initialization -
Inherits all standard
Dictionary<TKey, TValue>functionality -
Type-safe with full generic support
-
Simplifies builder pattern and configuration setup
-
ValidationCodeResult: OTP generation results with code and expiry -
CaptcherResponse: Google reCAPTCHA validation response -
EditorJS Models: Complete data structures for EditorJS content parsing
# Via .NET CLI
dotnet add package ClearTools
# Via PackageReference
<PackageReference Include="ClearTools" Version="3.1.0" />ClearTools targets .NET Standard 2.1 and includes:
- Azure.Storage.Blobs (12.25.0)
- Azure.Security.KeyVault.Secrets (4.8.0)
- Newtonsoft.Json (13.0.3)
- System.Drawing.Common (9.0.8)
- Microsoft.AspNetCore.Http.Abstractions (2.3.0)
public class ImageProcessor
{
public async Task<string> ProcessAndUploadImage(IFormFile file)
{
using var stream = file.OpenReadStream();
var image = Image.FromStream(stream);
// Process image
var scaledImage = ImageUtility.ScaleImage(image, 800, 600);
var imageBytes = ImageUtility.ConvertBitmapToBytes((Bitmap)scaledImage, ImageFormat.Jpeg);
// Generate unique filename
var fileName = StringUtility.GenerateFileName(file.FileName, "jpg");
// Upload to Azure
using var uploadStream = new MemoryStream(imageBytes);
AzureStorageManager.UploadToAzure(connectionString, "images", uploadStream, "image/jpeg", fileName, "uploads");
return fileName;
}
}public class OtpService
{
private readonly int _secretKey = 123456;
public ValidationCodeResult GenerateOtp(string email)
{
return OtpUtility.GenerateCode(email, _secretKey, TimeSpan.FromMinutes(5));
}
public bool ValidateOtp(string email, string code, DateTime expiry)
{
return OtpUtility.ValidateCode(email, _secretKey, code, expiry);
}
}For comprehensive documentation covering all methods and use cases, see:
- Complete Usage Guide - Detailed documentation with examples for every class and method
- API Reference - Complete API documentation
- Changelog - Version history and changes
β
String Utilities: URL generation, HTML stripping, text processing
β
Image Processing: Scaling, cropping, format conversion, quality optimization
β
Cryptography: Hashing, encryption, salt generation, secure tokens
β
OTP Management: Generation, validation, expiry handling
β
Azure Integration: Key Vault, Blob Storage, managed identity support
β
HTTP Client: RESTful API client with authentication and serialization
β
Extensions: String, DateTime, Byte array, and service collection extensions
β
Middleware: Request validation, API key authentication
β
EditorJS: Content parsing and HTML conversion
β
Base Conversion: Number base conversion utilities
β
File Management: File I/O operations and utilities
This repository includes a GitHub Actions workflow that manually publishes both NuGet packages (ClearTools and ClearTools.Abstraction) to nuget.org.
- Create a NuGet API key on nuget.org (scope it to the package IDs you publish).
- Add the secret to GitHub:
- Go to Settings β Secrets and variables β Actions β New repository secret
- Name:
NUGET_API_KEY - Value: your nuget.org API key
- Go to the Actions tab in this repository.
- Select "Publish NuGet Packages" from the left sidebar.
- Click "Run workflow" β "Run workflow" to trigger a manual publish.
The workflow will restore, build (Release), pack both projects, and push all .nupkg files to nuget.org, skipping any versions that are already published.
We welcome contributions! Please see our Contributing Guidelines for details.
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: GitHub Issues
- NuGet Package: ClearTools on NuGet
- Documentation: Complete Usage Guide
ClearTools - Making .NET development clearer, one utility at a time. π