mirror of
https://github.com/AlexMacocian/WpfExtended.git
synced 2026-07-15 14:59:30 +00:00
Application lifetime interface (#5)
Application lifetime hooks for services Options implementations and resolver Options manager interface to manage options
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
namespace WpfExtended.Tests.Configuration
|
||||
{
|
||||
public sealed class DummyOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using System.Windows.Extensions;
|
||||
using System.Windows.Extensions.Http;
|
||||
using WpfExtended.Test;
|
||||
using WpfExtended.Tests.Http;
|
||||
using WpfExtended.Tests.Services;
|
||||
|
||||
namespace WpfExtended.Tests
|
||||
{
|
||||
@@ -31,6 +32,7 @@ namespace WpfExtended.Tests
|
||||
var logger = sp.GetService(loggerType).As<ILogger>();
|
||||
return new HttpMessageLogger(logger, new HttpClientHandler());
|
||||
}));
|
||||
serviceManager.RegisterOptionsManager();
|
||||
}
|
||||
|
||||
protected override void ApplicationClosing()
|
||||
@@ -48,6 +50,7 @@ namespace WpfExtended.Tests
|
||||
|
||||
protected override void RegisterServices(IServiceProducer serviceProducer)
|
||||
{
|
||||
serviceProducer.RegisterSingleton<IDummyService, DummyService>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Extensions;
|
||||
using System.Windows.Extensions;
|
||||
using WpfExtended.Tests.Configuration;
|
||||
|
||||
namespace WpfExtended.Tests.Services
|
||||
{
|
||||
public sealed class DummyService : IDummyService
|
||||
{
|
||||
private readonly ILogger<DummyService> logger;
|
||||
private readonly IOptions<DummyOptions> dummyOptions;
|
||||
private readonly IUpdateableOptions<DummyOptions> updateableDummyOptions;
|
||||
private readonly ILiveOptions<DummyOptions> liveOptions;
|
||||
private readonly ILiveUpdateableOptions<DummyOptions> liveUpdateableOptions;
|
||||
|
||||
public DummyService(
|
||||
ILogger<DummyService> logger,
|
||||
IOptions<DummyOptions> options,
|
||||
IUpdateableOptions<DummyOptions> updateableOptions,
|
||||
ILiveUpdateableOptions<DummyOptions> liveUpdateableOptions,
|
||||
ILiveOptions<DummyOptions> liveOptions)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
this.dummyOptions = options.ThrowIfNull(nameof(options));
|
||||
this.updateableDummyOptions = updateableOptions.ThrowIfNull(nameof(updateableOptions));
|
||||
this.liveOptions = liveOptions.ThrowIfNull(nameof(liveOptions));
|
||||
this.liveUpdateableOptions = liveUpdateableOptions.ThrowIfNull(nameof(liveUpdateableOptions));
|
||||
}
|
||||
|
||||
public void OnClosing()
|
||||
{
|
||||
this.logger.LogInformation($"Closing {nameof(DummyService)}");
|
||||
}
|
||||
|
||||
public void OnStartup()
|
||||
{
|
||||
this.logger.LogInformation($"Starting {nameof(DummyService)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Windows.Extensions.Services;
|
||||
|
||||
namespace WpfExtended.Tests.Services
|
||||
{
|
||||
public interface IDummyService : IApplicationLifetimeService
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public sealed class DefaultOptionsManager : IOptionsManager
|
||||
{
|
||||
public T GetOptions<T>() where T : class
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public void UpdateOptions<T>(T value) where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public interface ILiveOptions<T> : IOptions<T>
|
||||
where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public interface ILiveUpdateableOptions<T> : ILiveOptions<T>, IUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public interface IOptionsManager
|
||||
{
|
||||
T GetOptions<T>()
|
||||
where T : class;
|
||||
void UpdateOptions<T>(T value)
|
||||
where T : class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public interface IUpdateableOptions<out T> : IOptions<T>
|
||||
where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the configuration with the current value stored in <see cref="IOptions{TOptions}.Value"/>.
|
||||
/// </summary>
|
||||
void UpdateOption();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public sealed class LiveOptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
|
||||
var configurationManager = serviceProvider.GetService<IOptionsManager>();
|
||||
|
||||
return Activator.CreateInstance(typedOptionsType, configurationManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public sealed class LiveUpdateableOptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(LiveUpdateableOptionsWrapper<>);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ILiveUpdateableOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
|
||||
var configurationManager = serviceProvider.GetService<IOptionsManager>();
|
||||
return Activator.CreateInstance(typedOptionsType, configurationManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public sealed class LiveUpdateableOptionsWrapper<T> : ILiveUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
private readonly IOptionsManager configurationManager;
|
||||
|
||||
private T value;
|
||||
|
||||
public T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
this.value = this.configurationManager.GetOptions<T>();
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public LiveUpdateableOptionsWrapper(IOptionsManager configurationManager)
|
||||
{
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
}
|
||||
|
||||
public void UpdateOption()
|
||||
{
|
||||
this.configurationManager.UpdateOptions<T>(this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public sealed class OptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(OptionsWrapper<>);
|
||||
private static readonly Type configurationType = typeof(IOptionsManager);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
|
||||
var configurationManager = serviceProvider.GetService<IOptionsManager>();
|
||||
var optionsValue = configurationType
|
||||
.GetMethod(nameof(IOptionsManager.GetOptions))
|
||||
.MakeGenericMethod(type.GetGenericArguments())
|
||||
.Invoke(configurationManager, Array.Empty<object>());
|
||||
|
||||
return Activator.CreateInstance(typedOptionsType, optionsValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Slim.Resolvers;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public sealed class UpdateableOptionsResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly Type optionsType = typeof(UpdateableOptionsWrapper<>);
|
||||
private static readonly Type configurationType = typeof(IOptionsManager);
|
||||
|
||||
public bool CanResolve(Type type)
|
||||
{
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IUpdateableOptions<>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public object Resolve(Slim.IServiceProvider serviceProvider, Type type)
|
||||
{
|
||||
var typedOptionsType = optionsType.MakeGenericType(type.GetGenericArguments());
|
||||
var configurationManager = serviceProvider.GetService<IOptionsManager>();
|
||||
var optionsValue = configurationType
|
||||
.GetMethod(nameof(IOptionsManager.GetOptions))
|
||||
.MakeGenericMethod(type.GetGenericArguments())
|
||||
.Invoke(configurationManager, Array.Empty<object>());
|
||||
|
||||
return Activator.CreateInstance(typedOptionsType, configurationManager, optionsValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Extensions;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
public sealed class UpdateableOptionsWrapper<T> : IUpdateableOptions<T>
|
||||
where T : class
|
||||
{
|
||||
private readonly IOptionsManager configurationManager;
|
||||
|
||||
public T Value { get; }
|
||||
|
||||
public UpdateableOptionsWrapper(IOptionsManager configurationManager, T options)
|
||||
{
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
this.Value = options;
|
||||
}
|
||||
|
||||
public void UpdateOption()
|
||||
{
|
||||
this.configurationManager.UpdateOptions(this.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Slim;
|
||||
using System.Extensions;
|
||||
using System.Net.Http;
|
||||
@@ -9,15 +10,65 @@ namespace System.Windows.Extensions
|
||||
{
|
||||
public static class ServiceManagerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers a <see cref="IOptionsManager"/> with the default <see cref="DefaultOptionsManager"/>.
|
||||
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
|
||||
public static IServiceManager RegisterOptionsManager(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.RegisterSingleton<IOptionsManager, DefaultOptionsManager>();
|
||||
serviceManager.RegisterOptionsResolver();
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a <see cref="IOptionsManager"/>.
|
||||
/// This call also registers the resolver that resolves <see cref="IUpdateableOptions{T}"/> and <see cref="IOptions{T}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Implementation of <see cref="IOptionsManager"/>.</typeparam>
|
||||
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceManager"/>.</returns>
|
||||
public static IServiceManager RegisterOptionsManager<T>(this IServiceManager serviceManager)
|
||||
where T : IOptionsManager
|
||||
{
|
||||
serviceManager.RegisterSingleton<IOptionsManager, T>();
|
||||
serviceManager.RegisterOptionsResolver();
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers resolvers for <see cref="IOptions{TOptions}"/> and <see cref="IUpdateableOptions{T}"/>.
|
||||
/// Depends on a <see cref="IOptionsManager"/> in order to properly resolve options.
|
||||
/// </summary>
|
||||
/// <param name="serviceManager"><see cref="IServiceManager"/>.</param>
|
||||
/// <returns><see cref="IServiceManager"/>.</returns>
|
||||
public static IServiceManager RegisterOptionsResolver(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterResolver(new OptionsResolver());
|
||||
serviceManager.RegisterResolver(new UpdateableOptionsResolver());
|
||||
serviceManager.RegisterResolver(new LiveOptionsResolver());
|
||||
serviceManager.RegisterResolver(new LiveUpdateableOptionsResolver());
|
||||
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a <see cref="ILogsWriter"/> with the default <see cref="CVLoggerProvider"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
|
||||
/// <param name="serviceManager"><see cref="ServiceManager"/>.</param>
|
||||
/// <returns>Provided <see cref="ServiceManager"/>.</returns>
|
||||
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
|
||||
public static IServiceProducer RegisterLogWriter<TLogsWriter>(this IServiceProducer serviceManager)
|
||||
where TLogsWriter : ILogsWriter
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterSingleton<ILogsWriter, TLogsWriter>();
|
||||
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
|
||||
{
|
||||
@@ -34,12 +85,14 @@ namespace System.Windows.Extensions
|
||||
/// </summary>
|
||||
/// <typeparam name="TILogsWriter">Interface of <see cref="ILogsWriter"/>.</typeparam>
|
||||
/// <typeparam name="TLogsWriter">Implementation of <see cref="ILogsWriter"/>.</typeparam>
|
||||
/// <param name="serviceManager"><see cref="ServiceManager"/>.</param>
|
||||
/// <returns>Provided <see cref="ServiceManager"/>.</returns>
|
||||
/// <param name="serviceManager"><see cref="IServiceProducer"/>.</param>
|
||||
/// <returns>Provided <see cref="IServiceProducer"/>.</returns>
|
||||
public static IServiceProducer RegisterLogWriter<TILogsWriter, TLogsWriter>(this IServiceProducer serviceManager)
|
||||
where TLogsWriter : TILogsWriter
|
||||
where TILogsWriter : class, ILogsWriter
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterSingleton<TILogsWriter, TLogsWriter>();
|
||||
serviceManager.RegisterScoped<ILoggerFactory, LoggerFactory>(sp =>
|
||||
{
|
||||
@@ -53,12 +106,16 @@ namespace System.Windows.Extensions
|
||||
|
||||
public static IServiceManager RegisterLoggerFactory(this IServiceManager serviceManager, Func<Slim.IServiceProvider, ILoggerFactory> loggerFactory)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterSingleton<ILoggerFactory, ILoggerFactory>(loggerFactory);
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
public static IServiceManager RegisterDebugLoggerFactory(this IServiceManager serviceManager)
|
||||
{
|
||||
serviceManager.ThrowIfNull(nameof(serviceManager));
|
||||
|
||||
serviceManager.RegisterLogWriter<ILogsWriter, DebugLogsWriter>();
|
||||
return serviceManager;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Slim;
|
||||
using System.Extensions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Extensions.Logging;
|
||||
using System.Windows.Extensions.Services;
|
||||
|
||||
namespace System.Windows.Extensions
|
||||
{
|
||||
@@ -62,6 +63,11 @@ namespace System.Windows.Extensions
|
||||
protected sealed override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
base.OnExit(e);
|
||||
foreach (var service in this.ServiceManager.GetServicesOfType<IApplicationLifetimeService>())
|
||||
{
|
||||
service.OnClosing();
|
||||
}
|
||||
|
||||
this.ApplicationClosing();
|
||||
}
|
||||
protected sealed override void OnSessionEnding(SessionEndingCancelEventArgs e)
|
||||
@@ -74,6 +80,11 @@ namespace System.Windows.Extensions
|
||||
{
|
||||
var window = this.ServiceManager.GetService<T>();
|
||||
this.ApplicationStarting();
|
||||
foreach(var service in this.ServiceManager.GetServicesOfType<IApplicationLifetimeService>())
|
||||
{
|
||||
service.OnStartup();
|
||||
}
|
||||
|
||||
window.Show();
|
||||
}
|
||||
private void RegisterInternals()
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace System.Windows.Extensions.Services
|
||||
{
|
||||
public interface IApplicationLifetimeService
|
||||
{
|
||||
void OnStartup();
|
||||
void OnClosing();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseFile>License.txt</PackageLicenseFile>
|
||||
<Version>0.4.2</Version>
|
||||
<Version>0.5</Version>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Description>Extension library for Windows Presentation Platform.
|
||||
|
||||
@@ -86,7 +86,7 @@ http://www.java2s.com/Open-Source/CSharp_Free_Code/Windows_Presentation_Foundati
|
||||
<PackageReference Include="Microsoft.CorrelationVector" Version="1.0.42" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="5.0.0" />
|
||||
<PackageReference Include="Slim" Version="1.4.3" />
|
||||
<PackageReference Include="Slim" Version="1.5.0" />
|
||||
<PackageReference Include="SystemExtensions.NetStandard" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
<Import Project="ShaderCompiler.target" />
|
||||
|
||||
Reference in New Issue
Block a user