Files
PLib/src/PLib.Desktop/AppHost.cs
T

83 lines
3.2 KiB
C#

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using PLib.Desktop.Imaging;
using PLib.Desktop.Services;
using PLib.Desktop.Settings;
using PLib.Desktop.ViewModels;
using PLib.Infrastructure;
using PLib.Infrastructure.Storage;
using Serilog;
namespace PLib.Desktop;
/// <summary>
/// Composition root. Everything the application is made of is wired up here and nowhere else.
/// </summary>
internal static class AppHost
{
public static IHost Create(string[] args)
{
// The paths are needed to locate the user settings file, which is itself a
// configuration source — so they are built before the container exists and then
// handed to it as an instance.
var paths = new AppPaths();
// A desktop app is launched from arbitrary working directories, so the content root
// has to be the folder the executable lives in rather than Environment.CurrentDirectory.
var builder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings
{
Args = args,
ContentRootPath = AppContext.BaseDirectory,
});
builder.Configuration.AddJsonFile(
Path.Combine(paths.DataDirectory, "settings.json"),
optional: true,
reloadOnChange: true);
ConfigureLogging(builder, paths);
builder.Services.AddSingleton<IAppPaths>(paths);
builder.Services.AddOptions<AppearanceOptions>()
.Bind(builder.Configuration.GetSection(AppearanceOptions.SectionName));
builder.Services.AddOptions<PlaybackOptions>()
.Bind(builder.Configuration.GetSection(PlaybackOptions.SectionName))
.ValidateDataAnnotations();
builder.Services.AddPLibInfrastructure(builder.Configuration);
builder.Services.AddSingleton<ThumbnailCache>();
builder.Services.AddSingleton<IThumbnailLoader>(sp => sp.GetRequiredService<ThumbnailCache>());
builder.Services.AddSingleton<IAppSettingsStore, JsonAppSettingsStore>();
builder.Services.AddSingleton<IFolderPicker, StorageProviderFolderPicker>();
builder.Services.AddSingleton<ISystemShell, SystemShell>();
builder.Services.AddSingleton<IThemeService, ThemeService>();
builder.Services.AddSingleton<RemoteImageLoader>();
builder.Services.AddSingleton<MainWindowViewModel>();
// Scoped, not singleton: the settings dialog edits a working copy, so each opening
// gets its own model and a cancelled edit never leaks into the next one.
builder.Services.AddScoped<SettingsViewModel>();
return builder.Build();
}
private static void ConfigureLogging(HostApplicationBuilder builder, IAppPaths paths)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File(
Path.Combine(paths.DataDirectory, "logs", "plib-.log"),
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 7)
.CreateLogger();
builder.Logging.ClearProviders();
builder.Logging.AddSerilog(Log.Logger, dispose: true);
}
}