Femur.Hosting 0.0.31

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

Femur.Hosting

A fluent builder framework for console applications with structured lifecycle management, comprehensive error handling, and bootstrap logging support.

Installation

dotnet add package Femur.Hosting

Quick Example

using Femur.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

return await ApplicationBuilder.Create(args)
    .UseDefaultConsoleLogging()
    .ConfigureServices((context, services) =>
    {
        services.AddHostedService<MyService>();
    })
    .RunAsync();

class MyService : IHostedService
{
    private readonly ILogger<MyService> _logger;

    public MyService(ILogger<MyService> logger) => _logger = logger;

    public Task StartAsync(CancellationToken ct)
    {
        _logger.LogInformation("Service started");
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken ct) => Task.CompletedTask;
}

Key Features

Staged Fluent Builder

ApplicationBuilder uses a staged fluent API that guides you through configuration in the correct order:

  1. Initial → Create builder with args
  2. Bootstrap → Set up logging (before host initialization)
  3. Configuration → Load config files, environment variables
  4. Services → Register services in DI container
  5. Executable → Build and run the application

Each stage returns a different interface, ensuring type-safe configuration and preventing incorrect usage.

Comprehensive Error Handling

Handle errors at different lifecycle phases with specific handlers:

await ApplicationBuilder.Create(args)
    .UseDefaultConsoleLogging()
    .ConfigureServices(...)
    .OnBuilderError((ex, logger) => ExitCodes.BuilderCreationFailed)
    .OnBuildError((ex, logger) => ExitCodes.BuildFailed)
    .OnPreStartupError((ex, logger) => ExitCodes.PreStartupError)
    .OnRuntimeError((ex, logger) => ExitCodes.RuntimeError)
    .OnPostShutdownError((ex, logger) => ExitCodes.PostShutdownError)
    .RunAsync();

Exit Codes

Standardized exit codes for operational integration:

Exit Code Constant Meaning
0 Success Application completed successfully
1 BuilderCreationFailed Failed to create ApplicationBuilder
2 BuildFailed Failed during configuration or service registration
3 RuntimeError Unhandled exception during execution
4 PreStartupError Failed during host startup initialization
5 PostShutdownError Error during disposal/cleanup
10 BootstrapLoggerFailed Bootstrap logger initialization failed
125 CommandCancelled User cancelled operation
130 CtrlCInterrupt Ctrl+C interrupt signal

These codes enable Docker, Kubernetes, CI/CD pipelines, and monitoring tools to understand failure reasons.

Bootstrap Logging Integration

Bootstrap logging solves the "blind spot" in .NET Generic Host where logging isn't available during configuration:

await ApplicationBuilder.Create(args)
    .UseDefaultConsoleLogging()  // Creates BootstrapLogger
    .ConfigureConfiguration((context, config) =>
    {
        // Logs: "Loading configuration..."
        config.AddJsonFile("appsettings.json");
    })
    .ConfigureServices((context, services) =>
    {
        // Logs: "Registering services..."
        services.AddHostedService<MyService>();
    })
    .RunAsync();

The same logging providers (console, OpenTelemetry, etc.) receive logs from both bootstrap and runtime phases.

Type Discovery

Automatic discovery of the Program type for logger category naming:

// Logger category automatically resolved to "Program" or entry assembly name
.UseDefaultConsoleLogging()

// Equivalent to:
.UseDefaultConsoleLogging<Program>()

Complete Example

using Femur;
using Femur.Hosting;
using FluentValidation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

return await ApplicationBuilder.Create(args)
    // Stage 1: Bootstrap logging
    // Logs configuration and service registration
    .UseDefaultConsoleLogging()

    // Stage 2: Configuration
    // Load configuration files
    .ConfigureConfiguration((context, config) =>
    {
        config.AddJsonFile("appsettings.json", optional: false);
        config.AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true);
        config.AddEnvironmentVariables();
    })

    // Stage 3: Services
    // Register services with DI container
    .ConfigureServices((context, services) =>
    {
        // Configuration with validation
        services.TryConfigureByConventionWithValidation<AppOptions>();

        // Business logic
        services.AddHostedService<WorkerService>();
    })

    // Error handling for each lifecycle phase
    .OnBuildError((exception, logger) =>
    {
        logger.LogCritical(exception, "Configuration or validation failed");
        return ExitCodes.BuildFailed;
    })
    .OnRuntimeError((exception, logger) =>
    {
        logger.LogCritical(exception, "Unhandled runtime exception");
        return ExitCodes.RuntimeError;
    })

    // Stage 4: Run
    .RunAsync();

// Configuration with validation
class AppOptions : IStandardOptions<AppOptions>
{
    public static string SectionName => "App";
    public string WorkerName { get; set; } = "";

    public static void SetupValidator(AbstractValidator<AppOptions> validator)
    {
        validator.RuleFor(x => x.WorkerName).NotEmpty();
    }
}

// Worker service
class WorkerService : IHostedService
{
    private readonly AppOptions _options;
    private readonly ILogger<WorkerService> _logger;

    public WorkerService(IOptions<AppOptions> options, ILogger<WorkerService> logger)
    {
        _options = options.Value;
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Worker {Name} started", _options.WorkerName);
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Worker stopped");
        return Task.CompletedTask;
    }
}

Architecture

ApplicationBuilder Stages

The builder enforces a specific configuration order through interface progression:

IInitialApplicationBuilder           Create(args)
    ↓
IBootstrapApplicationBuilder         UseDefaultConsoleLogging()
    ↓
IConfigurationApplicationBuilder     ConfigureConfiguration(...)
    ↓
IServicesApplicationBuilder          ConfigureServices(...)
    ↓
IExecutableApplicationBuilder        OnBuildError(...), OnRuntimeError(...), RunAsync()

Each interface only exposes methods valid for that stage, preventing configuration mistakes.

Error Handling Strategy

Errors are differentiated by lifecycle phase:

  1. Builder Creation → Before ApplicationBuilder exists
  2. Build Phase → During configuration and service registration
  3. Pre-Startup → During host.RunAsync() initialization
  4. Runtime → During normal application execution
  5. Post-Shutdown → During disposal and cleanup

Each phase has a dedicated error handler returning an appropriate exit code.

Use Cases

Console Applications

Build structured console applications with proper lifecycle management:

await ApplicationBuilder.Create(args)
    .UseDefaultConsoleLogging()
    .ConfigureServices(services => services.AddHostedService<ConsoleWorker>())
    .RunAsync();

CLI Tools

Command-line tools with validation and error handling:

await ApplicationBuilder.Create(args)
    .UseDefaultConsoleLogging()
    .ConfigureServices(services =>
    {
        services.TryConfigureByConventionWithValidation<CliOptions>();
        services.AddHostedService<CliExecutor>();
    })
    .OnBuildError((ex, logger) => ExitCodes.BuildFailed)
    .RunAsync();

Scheduled Jobs

Long-running background workers:

await ApplicationBuilder.Create(args)
    .UseDefaultConsoleLogging()
    .ConfigureServices(services =>
    {
        services.AddHostedService<ScheduledJobWorker>();
        services.AddSingleton<IJobScheduler, QuartzScheduler>();
    })
    .RunAsync();

Web Applications

For ASP.NET Core applications, use Femur.Hosting.Web which provides WebApplicationBuilder with similar patterns for web scenarios.

See Also

Package Dependencies

  • Microsoft.Extensions.Hosting - Generic host infrastructure
  • Microsoft.Extensions.Logging - Logging abstractions
  • Microsoft.Extensions.Configuration - Configuration system
  • Microsoft.Extensions.DependencyInjection - DI container

Target Frameworks

  • .NET 8.0 (LTS)
  • .NET 9.0 (STS)
  • .NET 10.0
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 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 is compatible.  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 (1)

Showing the top 1 NuGet packages that depend on Femur.Hosting:

Package Downloads
Femur.Hosting.Web

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.31 157 3/30/2026
0.0.30 221 1/25/2026
0.0.29 172 1/19/2026
0.0.28 224 12/5/2025
0.0.27 710 12/3/2025
0.0.26 737 12/3/2025
0.0.25 710 12/2/2025
0.0.24 711 12/2/2025
0.0.23 706 12/2/2025
0.0.21 710 12/2/2025
0.0.20 237 11/24/2025
0.0.16 374 10/6/2025
0.0.15 242 10/1/2025
0.0.14 255 9/20/2025
0.0.13 265 9/19/2025