ApplicationBuilderHelpers 4.0.25

This package has a SemVer 2.0.0 package version: 4.0.25+build.20250822100205.d45837e.
dotnet add package ApplicationBuilderHelpers --version 4.0.25
                    
NuGet\Install-Package ApplicationBuilderHelpers -Version 4.0.25
                    
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="ApplicationBuilderHelpers" Version="4.0.25" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ApplicationBuilderHelpers" Version="4.0.25" />
                    
Directory.Packages.props
<PackageReference Include="ApplicationBuilderHelpers" />
                    
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 ApplicationBuilderHelpers --version 4.0.25
                    
#r "nuget: ApplicationBuilderHelpers, 4.0.25"
                    
#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 ApplicationBuilderHelpers@4.0.25
                    
#: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=ApplicationBuilderHelpers&version=4.0.25
                    
Install as a Cake Addin
#tool nuget:?package=ApplicationBuilderHelpers&version=4.0.25
                    
Install as a Cake Tool

ApplicationBuilderHelpers

A powerful .NET library for building command-line applications with a fluent API, dependency injection, and modular architecture. ApplicationBuilderHelpers simplifies the creation of CLI tools by providing a structured approach to command handling, configuration management, and application composition.

Features

  • 🎯 Command-based Architecture - Build CLI applications using command patterns with automatic argument parsing
  • 🔧 Fluent Builder API - Intuitive application setup using method chaining
  • 💉 Dependency Injection - Full support for Microsoft.Extensions.DependencyInjection
  • 🏗️ Modular Application Structure - Compose applications from reusable components
  • ⚙️ Configuration Management - Seamless integration with .NET configuration system
  • 🎨 Attribute-based Command Options - Define command-line arguments using attributes
  • 🔄 Middleware Pipeline - Support for application middleware and lifecycle hooks
  • 📦 Multiple Application Contexts - Support for WebApplication, ConsoleApp, and custom host builders

Installation

dotnet add package ApplicationBuilderHelpers

Quick Start

1. Create Your Main Program

using ApplicationBuilderHelpers;
using YourApp.Commands;
using YourApp.Applications;

return await ApplicationBuilder.Create()
    .AddApplication<CoreApplication>()
    .AddApplication<InfrastructureApplication>()
    .AddCommand<MainCommand>()
    .AddCommand<ProcessCommand>()
    .AddCommand<MigrateCommand>()
    .RunAsync(args);

2. Define a Command

using ApplicationBuilderHelpers.Attributes;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace YourApp.Commands;

[Command(description: "Main command for your application")]
public class MainCommand : Command
{
    [CommandOption('v', "verbose", Description = "Enable verbose output")]
    public bool Verbose { get; set; }

    [CommandOption('c', "config", Description = "Configuration file path", EnvironmentVariable = "APP_CONFIG")]
    public string? ConfigPath { get; set; }

    [CommandOption("timeout", Description = "Timeout in seconds")]
    public int Timeout { get; set; } = 30;

    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cancellationTokenSource)
    {
        // Access services from DI container
        var logger = applicationHost.Services.GetRequiredService<ILogger<MainCommand>>();
        var myService = applicationHost.Services.GetRequiredService<IMyService>();
        
        logger.LogInformation("Running main command with verbose={Verbose}, config={Config}, timeout={Timeout}", 
            Verbose, ConfigPath, Timeout);
        
        // Your command logic here
        await myService.DoWorkAsync();
        
        cancellationTokenSource.Cancel(); // Stop the application when done
    }
}

3. Create an Application Module

using ApplicationBuilderHelpers;
using ApplicationBuilderHelpers.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace YourApp.Applications;

public class CoreApplication : ApplicationDependency
{
    public override void CommandPreparation(ApplicationBuilder applicationBuilder)
    {
        // Add custom type parsers for command arguments
        applicationBuilder.AddCommandTypeParser<CustomTypeParser>();
    }

    public override void BuilderPreparation(ApplicationHostBuilder applicationBuilder)
    {
        // Prepare the host builder before configuration
    }

    public override void AddConfigurations(ApplicationHostBuilder applicationBuilder, IConfiguration configuration)
    {
        // Add custom configuration providers or bind configuration sections
        applicationBuilder.Services.Configure<AppSettings>(configuration.GetSection("AppSettings"));
    }

    public override void AddServices(ApplicationHostBuilder applicationBuilder, IServiceCollection services)
    {
        // Register your services
        services.AddSingleton<IMyService, MyService>();
        services.AddHttpClient();
        
        // Add other services
        services.AddLogging();
    }

    public override void AddMiddlewares(ApplicationHost applicationHost, IHost host)
    {
        // Add middleware to the application pipeline
    }

    public override void RunPreparation(ApplicationHost applicationHost)
    {
        // Perform any final setup before the application runs
    }
}

Core Components

ApplicationBuilder

The entry point for building your application. Provides a fluent API for composing applications and commands.

Key Methods:

  • Create() - Creates a new ApplicationBuilder instance
  • AddApplication<T>() - Adds an application module
  • AddCommand<T>() - Registers a command
  • RunAsync(args) - Builds and runs the application

Command

Base class for all CLI commands. Override the Run method to implement command logic. Commands can also configure services and application behavior just like ApplicationDependency.

Command Attributes:

  • [Command] - Defines command metadata (name, description, aliases)
  • [CommandOption] - Defines command-line options
  • [CommandArgument] - Defines positional arguments

Command Lifecycle Methods:

Commands inherit the same lifecycle methods as ApplicationDependency:

[Command("process", description: "Process data with custom services")]
public class ProcessCommand : Command
{
    [CommandOption('f', "file", Description = "Input file path")]
    public string? FilePath { get; set; }

    // Configure command-specific services
    public override void AddServices(ApplicationHostBuilder applicationBuilder, IServiceCollection services)
    {
        services.AddScoped<IDataProcessor, DataProcessor>();
        services.AddScoped<IFileValidator, FileValidator>();
        services.AddLogging(logging => logging.AddConsole());
    }

    // Configure command-specific settings
    public override void AddConfigurations(ApplicationHostBuilder applicationBuilder, IConfiguration configuration)
    {
        applicationBuilder.Services.Configure<ProcessingOptions>(
            configuration.GetSection("Processing"));
    }

    // Add command-specific middleware
    public override void AddMiddlewares(ApplicationHost applicationHost, IHost host)
    {
        // Add performance monitoring middleware for this command
        var logger = host.Services.GetRequiredService<ILogger<ProcessCommand>>();
        logger.LogInformation("Process command middleware initialized");
    }

    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cancellationTokenSource)
    {
        var processor = applicationHost.Services.GetRequiredService<IDataProcessor>();
        var validator = applicationHost.Services.GetRequiredService<IFileValidator>();
        var logger = applicationHost.Services.GetRequiredService<ILogger<ProcessCommand>>();
        
        if (await validator.ValidateAsync(FilePath))
        {
            await processor.ProcessFileAsync(FilePath);
            logger.LogInformation("Processing completed");
        }
        
        cancellationTokenSource.Cancel();
    }
}

Accessing Services in Commands:

  1. Service Locator Pattern (through ApplicationHost):
protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cancellationTokenSource)
{
    var logger = applicationHost.Services.GetRequiredService<ILogger<MyCommand>>();
    var dbContext = applicationHost.Services.GetRequiredService<AppDbContext>();
    
    logger.LogInformation("Command started");
    // Use services...
}
  1. Constructor Injection (if supported by the command resolver):
public class ImportCommand : Command
{
    private readonly IDataImporter _importer;
    private readonly ILogger<ImportCommand> _logger;
    
    public ImportCommand(IDataImporter importer, ILogger<ImportCommand> logger)
    {
        _importer = importer;
        _logger = logger;
    }
    
    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cancellationTokenSource)
    {
        _logger.LogInformation("Importing data...");
        await _importer.ImportAsync();
        cancellationTokenSource.Cancel();
    }
}

ApplicationDependency

Base class for application modules that configure services, middleware, and application behavior.

Lifecycle Methods (shared with Command):

  1. CommandPreparation - Configure command parsing
  2. BuilderPreparation - Prepare the host builder
  3. AddConfigurations - Add configuration providers
  4. AddServices - Register services with DI container
  5. AddMiddlewares - Configure middleware pipeline
  6. RunPreparation - Final setup before run

Advanced Features

Custom Type Parsers

Implement custom parsing for command arguments by implementing the ICommandTypeParser interface:

using ApplicationBuilderHelpers.Interfaces;
using System.Diagnostics.CodeAnalysis;

[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public class DateTimeTypeParser : ICommandTypeParser
{
    public Type Type => typeof(DateTime);
    
    public object? Parse(string? value, out string? validateError)
    {
        validateError = null;
        
        if (string.IsNullOrEmpty(value))
        {
            validateError = "Date value cannot be empty";
            return null;
        }
        
        if (DateTime.TryParse(value, out var result))
        {
            return result;
        }
        
        validateError = $"'{value}' is not a valid date format";
        return null;
    }
    
    public string? GetString(object? value)
    {
        if (value is DateTime dateTime)
        {
            return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
        }
        return value?.ToString();
    }
}

// Register in your application
public class CoreApplication : ApplicationDependency
{
    public override void CommandPreparation(ApplicationBuilder applicationBuilder)
    {
        applicationBuilder.AddCommandTypeParser<DateTimeTypeParser>();
    }
}

More complex type parser example:

[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public class LogLevelTypeParser : ICommandTypeParser
{
    public Type Type => typeof(LogLevel);
    
    public object? Parse(string? value, out string? validateError)
    {
        validateError = null;
        
        if (string.IsNullOrWhiteSpace(value))
        {
            validateError = "Log level cannot be empty";
            return null;
        }
        
        if (Enum.TryParse<LogLevel>(value, true, out var logLevel))
        {
            return logLevel;
        }
        
        var validValues = string.Join(", ", Enum.GetNames(typeof(LogLevel)));
        validateError = $"'{value}' is not a valid log level. Valid values are: {validValues}";
        return null;
    }
    
    public string? GetString(object? value)
    {
        return value?.ToString()?.ToLower();
    }
}

// Usage in a command
[Command(description: "Configure logging")]
public class LogCommand : Command
{
    [CommandOption('l', "level", Description = "Set the logging level")]
    public LogLevel Level { get; set; } = LogLevel.Information;
    
    protected override ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cts)
    {
        var logger = applicationHost.Services.GetRequiredService<ILogger<LogCommand>>();
        logger.LogInformation("Logging level set to: {Level}", Level);
        cts.Cancel();
        return ValueTask.CompletedTask;
    }
}

Self-Contained Commands

Commands can be completely self-contained with their own service configuration:

[Command("backup", description: "Backup database")]
public class BackupCommand : Command
{
    [CommandOption('o', "output", Description = "Output file path")]
    public string OutputPath { get; set; } = $"backup_{DateTime.Now:yyyyMMdd_HHmmss}.bak";

    // Register services specific to backup operations
    public override void AddServices(ApplicationHostBuilder applicationBuilder, IServiceCollection services)
    {
        services.AddSingleton<IBackupService, BackupService>();
        services.AddSingleton<ICompressionService, CompressionService>();
        services.AddSingleton<ICloudStorageService, AzureStorageService>();
        
        // Add Azure Storage client
        services.AddAzureClients(clientBuilder =>
        {
            clientBuilder.AddBlobServiceClient(applicationBuilder.Configuration["Azure:StorageConnection"]);
        });
    }

    public override void AddConfigurations(ApplicationHostBuilder applicationBuilder, IConfiguration configuration)
    {
        // Bind backup-specific configuration
        applicationBuilder.Services.Configure<BackupOptions>(
            configuration.GetSection("Backup"));
    }

    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cancellationTokenSource)
    {
        var backupService = applicationHost.Services.GetRequiredService<IBackupService>();
        var cloudStorage = applicationHost.Services.GetRequiredService<ICloudStorageService>();
        var logger = applicationHost.Services.GetRequiredService<ILogger<BackupCommand>>();
        
        logger.LogInformation("Creating backup to {OutputPath}", OutputPath);
        var backupFile = await backupService.CreateBackupAsync(OutputPath);
        
        logger.LogInformation("Uploading backup to cloud storage");
        await cloudStorage.UploadAsync(backupFile);
        
        logger.LogInformation("Backup completed successfully");
        cancellationTokenSource.Cancel();
    }
}

Sub-Commands

Create hierarchical command structures using space-separated command names:

// Main deploy command
[Command("deploy", description: "Deployment commands")]
public class DeployCommand : Command
{
    protected override ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cts)
    {
        Console.WriteLine("Please specify a deployment target. Use --help for available options.");
        cts.Cancel();
        return ValueTask.CompletedTask;
    }
}

// Sub-command: deploy prod
[Command("deploy prod", description: "Deploy to production environment")]
public class DeployProductionCommand : Command
{
    [CommandOption("skip-tests", Description = "Skip running tests before deployment")]
    public bool SkipTests { get; set; }
    
    // Add production-specific services
    public override void AddServices(ApplicationHostBuilder applicationBuilder, IServiceCollection services)
    {
        services.AddSingleton<IDeploymentService, ProductionDeploymentService>();
        services.AddSingleton<IHealthCheckService, HealthCheckService>();
        services.AddSingleton<IRollbackService, RollbackService>();
    }
    
    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cts)
    {
        var deployService = applicationHost.Services.GetRequiredService<IDeploymentService>();
        var healthCheck = applicationHost.Services.GetRequiredService<IHealthCheckService>();
        var logger = applicationHost.Services.GetRequiredService<ILogger<DeployProductionCommand>>();
        
        logger.LogInformation("Deploying to production environment...");
        
        if (!SkipTests)
        {
            logger.LogInformation("Running pre-deployment tests...");
            // Run tests
        }
        
        await deployService.DeployAsync();
        await healthCheck.VerifyDeploymentAsync();
        
        cts.Cancel();
    }
}

// Sub-command: deploy staging
[Command("deploy staging", description: "Deploy to staging environment")]
public class DeployStagingCommand : Command
{
    // Add staging-specific services
    public override void AddServices(ApplicationHostBuilder applicationBuilder, IServiceCollection services)
    {
        services.AddSingleton<IDeploymentService, StagingDeploymentService>();
    }
    
    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cts)
    {
        var deployService = applicationHost.Services.GetRequiredService<IDeploymentService>();
        var logger = applicationHost.Services.GetRequiredService<ILogger<DeployStagingCommand>>();
        
        logger.LogInformation("Deploying to staging environment...");
        await deployService.DeployAsync();
        cts.Cancel();
    }
}

// Deeper nesting: deploy prod rollback
[Command("deploy prod rollback", description: "Rollback production deployment")]
public class DeployProductionRollbackCommand : Command
{
    [CommandOption("version", Description = "Specific version to rollback to")]
    public string? Version { get; set; }
    
    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cts)
    {
        var deployService = applicationHost.Services.GetRequiredService<IDeploymentService>();
        var logger = applicationHost.Services.GetRequiredService<ILogger<DeployProductionRollbackCommand>>();
        
        logger.LogInformation("Rolling back production to version {Version}...", Version ?? "previous");
        await deployService.RollbackProductionAsync(Version);
        cts.Cancel();
    }
}

Usage examples:

# Main deploy command
myapp deploy

# Deploy to production
myapp deploy prod

# Deploy to staging
myapp deploy staging

# Rollback production
myapp deploy prod rollback --version 1.2.3

Multiple Host Types

ApplicationBuilderHelpers supports different host types:

  • HostApplicationBuilder - For console applications
  • WebApplicationBuilder - For web applications
  • Custom builders implementing IHostApplicationBuilder

Environment-Specific Configuration

public override void AddConfigurations(ApplicationHostBuilder applicationBuilder, IConfiguration configuration)
{
    var environment = applicationBuilder.Environment;
    
    if (environment.IsDevelopment())
    {
        // Development-specific configuration
    }
    else if (environment.IsProduction())
    {
        // Production-specific configuration
    }
}

Architecture

ApplicationBuilderHelpers follows a modular architecture pattern:

┌─────────────────────┐
│  ApplicationBuilder │ ← Entry Point
└──────────┬──────────┘
           │
    ┌──────▼──────┐
    │  Commands   │ ← Command Registration (can also configure services)
    └──────┬──────┘
           │
    ┌──────▼──────────┐
    │  Applications   │ ← Application Modules
    └──────┬──────────┘
           │
    ┌──────▼───────────┐
    │  Host Builder    │ ← Host Configuration
    └──────┬───────────┘
           │
    ┌──────▼──────┐
    │  Services   │ ← Dependency Injection (from both Commands and Applications)
    └──────┬──────┘
           │
    ┌──────▼──────────┐
    │  Middleware     │ ← Request Pipeline
    └──────┬──────────┘
           │
    ┌──────▼──────┐
    │  Execution  │ ← Command Execution
    └─────────────┘

Best Practices

  1. Separation of Concerns - Keep commands focused on coordination, move business logic to services
  2. Use Application Modules - Group related configurations and services in ApplicationDependency classes
  3. Command-Specific Services - Register services in commands when they're only needed for that specific command
  4. Leverage DI - Use dependency injection for better testability and maintainability
  5. Configuration Over Code - Use configuration files for environment-specific settings
  6. Async All The Way - Use async/await patterns for I/O operations
  7. Prefer Service Locator in Commands - When constructor injection isn't available, use applicationHost.Services to access dependencies
  8. Logical Command Hierarchy - Use space-separated command names for intuitive sub-command structures
  9. Validate in Type Parsers - Return meaningful error messages from custom type parsers to help users

Examples

Simple Console Application

// Program.cs
return await ApplicationBuilder.Create()
    .AddCommand<GreetCommand>()
    .RunAsync(args);

// GreetCommand.cs
[Command(description: "Greet someone")]
public class GreetCommand : Command
{
    [CommandArgument(0, Description = "Name to greet")]
    public string Name { get; set; } = "World";
    
    protected override ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cts)
    {
        Console.WriteLine($"Hello, {Name}!");
        cts.Cancel();
        return ValueTask.CompletedTask;
    }
}

Command with Its Own Services

// Program.cs
return await ApplicationBuilder.Create()
    .AddCommand<ReportCommand>()
    .RunAsync(args);

// ReportCommand.cs
[Command("report", description: "Generate reports")]
public class ReportCommand : Command
{
    [CommandOption('f', "format", Description = "Report format (pdf, excel, html)")]
    public string Format { get; set; } = "pdf";
    
    [CommandOption('o', "output", Description = "Output directory")]
    public string OutputDir { get; set; } = "./reports";

    // Register report-specific services
    public override void AddServices(ApplicationHostBuilder applicationBuilder, IServiceCollection services)
    {
        services.AddScoped<IReportGenerator, ReportGenerator>();
        services.AddScoped<IPdfRenderer, PdfRenderer>();
        services.AddScoped<IExcelRenderer, ExcelRenderer>();
        services.AddScoped<IHtmlRenderer, HtmlRenderer>();
        services.AddScoped<IDataRepository, DataRepository>();
        
        // Add logging specifically for report generation
        services.AddLogging(logging => 
        {
            logging.AddConsole();
            logging.AddFile("logs/reports-{Date}.txt");
        });
    }

    public override void AddConfigurations(ApplicationHostBuilder applicationBuilder, IConfiguration configuration)
    {
        // Bind report configuration
        applicationBuilder.Services.Configure<ReportOptions>(
            configuration.GetSection("Reporting"));
    }

    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cts)
    {
        var generator = applicationHost.Services.GetRequiredService<IReportGenerator>();
        var logger = applicationHost.Services.GetRequiredService<ILogger<ReportCommand>>();
        
        logger.LogInformation("Generating {Format} report to {OutputDir}", Format, OutputDir);
        
        var report = await generator.GenerateAsync(Format);
        await report.SaveToAsync(OutputDir);
        
        logger.LogInformation("Report generated successfully");
        cts.Cancel();
    }
}

Complex Application with Command Hierarchy

// Program.cs
return await ApplicationBuilder.Create()
    .AddApplication<CoreApplication>()
    .AddApplication<InfrastructureApplication>()
    .AddCommand<MainCommand>()
    .AddCommand<DbCommand>()
    .AddCommand<DbMigrateCommand>()
    .AddCommand<DbSeedCommand>()
    .AddCommand<DbBackupCommand>()
    .RunAsync(args);

// Database commands hierarchy
[Command("db", description: "Database management commands")]
public class DbCommand : Command
{
    protected override ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cts)
    {
        Console.WriteLine("Database management commands. Use --help for available sub-commands.");
        cts.Cancel();
        return ValueTask.CompletedTask;
    }
}

[Command("db migrate", description: "Run database migrations")]
public class DbMigrateCommand : Command
{
    [CommandOption("connection-string", Description = "Database connection string", EnvironmentVariable = "DB_CONNECTION")]
    public string? ConnectionString { get; set; }
    
    [CommandOption("dry-run", Description = "Preview migrations without applying")]
    public bool DryRun { get; set; }
    
    // Add migration-specific services
    public override void AddServices(ApplicationHostBuilder applicationBuilder, IServiceCollection services)
    {
        services.AddDbContext<AppDbContext>(options =>
        {
            var connectionString = ConnectionString ?? applicationBuilder.Configuration.GetConnectionString("DefaultConnection");
            options.UseSqlServer(connectionString);
        });
        
        services.AddScoped<IDatabaseMigrator, EfCoreMigrator>();
    }
    
    protected override async ValueTask Run(ApplicationHost<HostApplicationBuilder> applicationHost, CancellationTokenSource cancellationTokenSource)
    {
        var logger = applicationHost.Services.GetRequiredService<ILogger<DbMigrateCommand>>();
        var migrator = applicationHost.Services.GetRequiredService<IDatabaseMigrator>();
        
        logger.LogInformation("Starting database migration. Dry run: {DryRun}", DryRun);
        
        if (DryRun)
        {
            var pending = await migrator.GetPendingMigrationsAsync();
            logger.LogInformation("Pending migrations: {Migrations}", string.Join(", ", pending));
        }
        else
        {
            await migrator.MigrateAsync();
            logger.LogInformation("Database migration completed successfully");
        }
        
        cancellationTokenSource.Cancel();
    }
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

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

Support

For issues, questions, or suggestions, please create an issue on the GitHub repository.

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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.25 0 8/22/2025
4.0.24 0 8/21/2025
4.0.23 7 8/20/2025
4.0.22 6 8/20/2025
4.0.21 7 8/18/2025
4.0.20 8 8/16/2025
4.0.19 7 8/15/2025
4.0.18 14 8/12/2025
4.0.17 8 8/11/2025
4.0.16 11 8/9/2025
4.0.15 9 8/8/2025
4.0.14 9 8/8/2025
4.0.13 25 8/7/2025
4.0.12 17 8/7/2025
4.0.11 17 8/7/2025
4.0.10 17 8/7/2025
4.0.9 21 8/7/2025
4.0.8 22 8/7/2025
4.0.7 23 8/7/2025
4.0.6 23 8/7/2025
4.0.5 24 8/7/2025
4.0.2 32 8/6/2025
4.0.1 26 8/6/2025
4.0.0 24 8/6/2025
3.1.4 12 7/30/2025
3.1.3 78 7/29/2025
3.1.2 8 7/29/2025
3.1.1 8 7/28/2025
3.1.0 10 7/28/2025
3.0.0 152 7/15/2025
2.1.6 273 7/4/2025
2.1.5 31 7/4/2025
2.1.3 123 6/29/2025
2.1.2 404 6/5/2025
2.1.1 49 6/5/2025
2.1.0 33 6/4/2025
2.0.22 38 6/4/2025
2.0.21 38 6/4/2025
2.0.20 38 6/4/2025
2.0.19 42 6/4/2025
2.0.18 56 5/27/2025
2.0.17 914 5/23/2025
2.0.16 740 5/5/2025
2.0.15 301 4/29/2025
2.0.14 84 4/28/2025
2.0.13 285 4/24/2025
2.0.12 347 4/16/2025
2.0.11 132 4/15/2025
2.0.10 128 4/11/2025
2.0.9 175 4/4/2025
2.0.8 172 3/28/2025
2.0.7 167 3/28/2025
2.0.6 237 3/24/2025
2.0.5 204 3/24/2025
2.0.4 204 3/19/2025
2.0.3 256 3/8/2025
2.0.2 314 3/7/2025
2.0.1 314 3/7/2025
2.0.0 362 3/5/2025
1.0.62 384 2/13/2025
1.0.61 727 2/12/2025
1.0.60 864 1/16/2025
1.0.59 115 1/15/2025
1.0.58 90 1/14/2025
1.0.57 102 1/10/2025
1.0.56 144 1/1/2025
1.0.55 109 12/27/2024
1.0.54 129 12/26/2024
1.0.53 130 12/18/2024
1.0.52 252 12/6/2024
1.0.51 110 12/5/2024
1.0.50 105 12/5/2024
1.0.49 115 12/4/2024
1.0.48 118 12/3/2024
1.0.47 835 12/3/2024
1.0.46 182 11/26/2024
1.0.45 91 11/25/2024
1.0.44 98 11/22/2024
1.0.43 94 11/22/2024
1.0.42 99 11/22/2024
1.0.41 96 11/21/2024
1.0.40 97 11/20/2024
1.0.39 172 11/14/2024
1.0.38 385 11/13/2024
1.0.37 1,276 11/8/2024
1.0.36 102 11/7/2024
1.0.35 147 11/6/2024
1.0.34 181 11/5/2024
1.0.33 477 10/30/2024
1.0.32 94 10/30/2024
1.0.31 213 10/29/2024
1.0.30 254 10/28/2024
1.0.29 158 10/25/2024
1.0.28 327 10/23/2024
1.0.27 204 10/22/2024
1.0.26 306 10/17/2024
1.0.25 210 10/15/2024
1.0.24 304 10/14/2024
1.0.23 101 10/14/2024
1.0.22 266 10/10/2024
1.0.21 165 10/9/2024
1.0.20 220 10/8/2024
1.0.19 238 10/7/2024
1.0.18 100 10/7/2024
1.0.17 296 10/3/2024
1.0.16 258 9/30/2024
1.0.15 161 9/27/2024
1.0.14 262 9/25/2024
1.0.13 178 9/25/2024
1.0.12 229 9/24/2024
1.0.11 287 9/20/2024
1.0.10 130 9/20/2024
1.0.9 241 9/18/2024
1.0.8 128 9/17/2024
1.0.7 327 9/11/2024
1.0.6 203 9/10/2024
1.0.5 275 9/6/2024
1.0.4 241 9/3/2024
1.0.3 159 9/2/2024
1.0.2 115 9/2/2024
1.0.1 105 9/2/2024
1.0.0 98 9/2/2024
0.2.19 188 8/29/2024
0.2.18 143 8/28/2024
0.2.17 210 8/26/2024
0.2.16 235 8/23/2024
0.2.15 239 8/21/2024
0.2.14 167 8/20/2024
0.2.13 209 8/15/2024
0.2.12 209 8/14/2024
0.2.11 196 8/13/2024
0.2.10 261 8/1/2024
0.2.9 143 7/31/2024
0.2.8 196 7/26/2024
0.2.7 412 7/16/2024
0.2.6 105 7/15/2024
0.2.5 112 7/13/2024
0.2.4 102 7/12/2024
0.2.3 124 7/10/2024
0.2.2 111 7/8/2024
0.2.1 166 7/7/2024
0.2.0 115 7/6/2024
0.1.7 101 7/2/2024
0.1.6 142 7/1/2024
0.1.5 116 6/30/2024
0.1.4 113 6/27/2024
0.1.3 149 5/14/2024
0.1.2 107 5/14/2024
0.1.1 110 5/14/2024
0.1.0 583 3/31/2024