p1eXu5.Wpf.BootstrapBase
1.0.4
dotnet add package p1eXu5.Wpf.BootstrapBase --version 1.0.4
NuGet\Install-Package p1eXu5.Wpf.BootstrapBase -Version 1.0.4
<PackageReference Include="p1eXu5.Wpf.BootstrapBase" Version="1.0.4" />
<PackageVersion Include="p1eXu5.Wpf.BootstrapBase" Version="1.0.4" />
<PackageReference Include="p1eXu5.Wpf.BootstrapBase" />
paket add p1eXu5.Wpf.BootstrapBase --version 1.0.4
#r "nuget: p1eXu5.Wpf.BootstrapBase, 1.0.4"
#:package p1eXu5.Wpf.BootstrapBase@1.0.4
#addin nuget:?package=p1eXu5.Wpf.BootstrapBase&version=1.0.4
#tool nuget:?package=p1eXu5.Wpf.BootstrapBase&version=1.0.4
p1eXu5 WPF Bootstrap Base
Overview
A comprehensive WPF bootstrap base library that provides essential building blocks for modern WPF applications. This library streamlines the setup of WPF applications with integrated hosting, dependency injection, configuration management, and structured logging.
Features
- Application Hosting: Built on
Microsoft.Extensions.Hostingfor standardized application lifecycle management - Dependency Injection: Full support for dependency injection through the Microsoft.Extensions.DependencyInjection container
- Configuration Management: Integrated configuration support using Microsoft.Extensions.Configuration
- Structured Logging: Serilog integration for comprehensive logging capabilities
- Modern .NET Support: Targets .NET 9.0 and .NET 10.0
Installation
Install the NuGet package:
dotnet add package p1eXu5.Wpf.BootstrapBase
Getting Started
The library provides a BootstrapBase class that serves as the foundation for your WPF application, handling common setup and initialization tasks.
Bootstrap example:
internal sealed class Bootstrap : BootstrapBase
{
protected override void ConfigureServices(HostBuilderContext hostBuilderCtx, IServiceCollection services)
{
base.ConfigureServices(hostBuilderCtx, services);
services.TryAddSingleton<ISettingsManager, SettingsManager>();
AddErrorMessageQueues(services);
}
private static void AddErrorMessageQueues(IServiceCollection services)
{
Func<IServiceProvider, object?, IErrorMessageQueue> errorMessageQueueFactory = ((sp, key) =>
{
ILoggerFactory loggerFactory = sp.GetRequiredService<ILoggerFactory>();
Microsoft.Extensions.Logging.ILogger logger;
if (key is string skey)
{
logger = loggerFactory.CreateLogger(ErrorMessageQueue.TypeFullName + '.' + skey);
}
else
{
logger = loggerFactory.CreateLogger<ErrorMessageQueue>();
}
return new ErrorMessageQueue(logger);
});
services.TryAddKeyedSingleton<IErrorMessageQueue>("main", errorMessageQueueFactory);
services.TryAddKeyedSingleton<IErrorMessageQueue>("dialog", errorMessageQueueFactory);
}
}
App example:
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private Bootstrap? _bootstrap;
private ILogger<App>? _logger;
private IErrorMessageQueue? _errorMessageQueue;
private readonly CancellationTokenSource _cts = new();
public App()
{
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("ru");
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("ru");
CultureInfo ci = CultureInfo.CreateSpecificCulture(CultureInfo.CurrentCulture.Name);
ci.DateTimeFormat.ShortDatePattern = "dd.MM.yyyy";
Thread.CurrentThread.CurrentCulture = ci;
AppDomain.CurrentDomain.UnhandledException += OnDomainUnhandledException;
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
}
private async void Application_Startup(object sender, StartupEventArgs e)
{
await BootstrapApplicationAsync(e);
}
private async Task BootstrapApplicationAsync(StartupEventArgs e)
{
_bootstrap = Bootstrap.Build<Bootstrap>(e.Args);
await _bootstrap.StartHostAsync(_cts.Token);
_errorMessageQueue = _bootstrap.GetRequiredKeyedService<IErrorMessageQueue>("main");
_logger = _bootstrap.GetLogger<App>();
_logger.LogInformation("Bootstrapped.");
string? openningLogFile = null;
if (e.Args.Length == 1 && File.Exists(e.Args[0]))
{
openningLogFile = e.Args[0];
}
var mainWindow = new MainWindow();
ElmishApp.Program.main(
mainWindow,
_errorMessageQueue,
_bootstrap.GetRequiredKeyedService<IErrorMessageQueue>("dialog"),
_bootstrap.GetRequiredService<ISettingsManager>(),
openningLogFile,
_bootstrap.GetRequiredService<ILoggerFactory>()
);
mainWindow.Show();
}
private void Application_Exit(object sender, ExitEventArgs e)
{
_cts.Cancel();
if (_bootstrap is not null)
{
_bootstrap.StopHostAsync(TimeSpan.FromSeconds(5))
.GetAwaiter()
.GetResult();
}
_cts.Dispose();
}
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
_logger?.LogError(e.Exception, "App dispatcher unhandled exception!");
#if DEBUG
_errorMessageQueue?.EnqueueError(e.Exception.Message + Environment.NewLine + e.Exception.StackTrace);
#else
_errorMessageQueue?.EnqueueError("Error!");
#endif
e.Handled = false;
}
private void OnDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
string errorMessage = e.ExceptionObject.ToString() + Environment.NewLine;
_logger?.LogError(errorMessage);
#if DEBUG
_errorMessageQueue?.EnqueueError(errorMessage);
#else
_errorMessageQueue?.EnqueueError("Error!");
#endif
}
private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
{
string errorMessage = e.Exception.InnerExceptions.First().Message + Environment.NewLine + e.Exception.GetType();
_logger?.LogError(errorMessage);
#if DEBUG
_errorMessageQueue?.EnqueueError(errorMessage);
#else
_errorMessageQueue?.EnqueueError("Error!");
#endif
}
}
Requirements
- .NET 9.0 or .NET 10.0
License
© 2025 Vladimir Likhatskiy (p1eXu5). All rights reserved.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- Microsoft.Extensions.Hosting (>= 10.0.6)
- Serilog.Enrichers.Environment (>= 3.0.1)
- Serilog.Enrichers.Process (>= 3.0.0)
- Serilog.Enrichers.Thread (>= 4.0.0)
- Serilog.Expressions (>= 5.0.0)
- Serilog.Extensions.Hosting (>= 10.0.0)
- Serilog.Formatting.Compact (>= 3.0.0)
- Serilog.Settings.Configuration (>= 10.0.0)
- Serilog.Sinks.Console (>= 6.1.1)
- Serilog.Sinks.Debug (>= 3.0.0)
- Serilog.Sinks.File (>= 7.0.0)
-
net9.0
- Microsoft.Extensions.Hosting (>= 10.0.6)
- Serilog.Enrichers.Environment (>= 3.0.1)
- Serilog.Enrichers.Process (>= 3.0.0)
- Serilog.Enrichers.Thread (>= 4.0.0)
- Serilog.Expressions (>= 5.0.0)
- Serilog.Extensions.Hosting (>= 10.0.0)
- Serilog.Formatting.Compact (>= 3.0.0)
- Serilog.Settings.Configuration (>= 10.0.0)
- Serilog.Sinks.Console (>= 6.1.1)
- Serilog.Sinks.Debug (>= 3.0.0)
- Serilog.Sinks.File (>= 7.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
- Added dispose guard.
- Added ServiceProvider property.