Core/UI - Move from Ninject to DryIoc (#754)

This commit is contained in:
RobertBeekman authored and GitHub committed 2023-01-30 21:00:10 +01:00
1 parent 166cb888c1
commit b7e723b7e9
121 files changed
+1175 -980

No files matched your search

@@ -1,9 +1,7 @@
using System;
using System.IO;
using System.Linq;
using Ninject;
using RGB.NET.Core;
using Serilog;
namespace Artemis.Core.DeviceProviders;
@@ -26,14 +24,7 @@ public abstract class DeviceProvider : PluginFeature
/// The RGB.NET device provider backing this Artemis device provider
/// </summary>
public IRGBDeviceProvider RgbDeviceProvider { get; }
/// <summary>
/// TODO: Make internal while still injecting.
/// A logger used by the device provider internally, ignore this
/// </summary>
[Inject]
public ILogger? Logger { get; set; }
/// <summary>
/// A boolean indicating whether this device provider detects the physical layout of connected keyboards.
/// <para>
@@ -1,6 +1,5 @@
using System;
using Artemis.Storage.Entities.Profile;
using Ninject;
namespace Artemis.Core.LayerBrushes;
@@ -63,7 +62,7 @@ public class LayerBrushDescriptor
if (layer == null)
throw new ArgumentNullException(nameof(layer));
BaseLayerBrush brush = (BaseLayerBrush) Provider.Plugin.Kernel!.Get(LayerBrushType);
BaseLayerBrush brush = (BaseLayerBrush) Provider.Plugin.Resolve(LayerBrushType);
brush.Layer = layer;
brush.Descriptor = this;
brush.LayerBrushEntity = entity ?? new LayerBrushEntity {ProviderId = Provider.Id, BrushType = LayerBrushType.FullName};
@@ -1,7 +1,6 @@
using System;
using Artemis.Core.LayerEffects.Placeholder;
using Artemis.Storage.Entities.Profile;
using Ninject;
namespace Artemis.Core.LayerEffects;
@@ -80,7 +79,7 @@ public class LayerEffectDescriptor
if (LayerEffectType == null)
throw new ArtemisCoreException("Cannot create an instance of a layer effect because this descriptor is not a placeholder but is still missing its LayerEffectType");
BaseLayerEffect effect = (BaseLayerEffect) Provider.Plugin.Kernel!.Get(LayerEffectType);
BaseLayerEffect effect = (BaseLayerEffect) Provider.Plugin.Resolve(LayerEffectType);
effect.ProfileElement = renderElement;
effect.Descriptor = this;
if (entity != null)
+82 -10
View File
@@ -7,8 +7,8 @@ using System.Linq;
using System.Reflection;
using Artemis.Core.DeviceProviders;
using Artemis.Storage.Entities.Plugins;
using DryIoc;
using McMaster.NETCore.Plugins;
using Ninject;
namespace Artemis.Core;
@@ -88,9 +88,9 @@ public class Plugin : CorePropertyChanged, IDisposable
public PluginBootstrapper? Bootstrapper { get; internal set; }
/// <summary>
/// The Ninject kernel of the plugin
/// Gets the IOC container of the plugin, only use this for advanced IOC operations, otherwise see <see cref="Resolve"/> and <see cref="Resolve{T}"/>
/// </summary>
public IKernel? Kernel { get; internal set; }
public IContainer? Container { get; internal set; }
/// <summary>
/// The PluginLoader backing this plugin
@@ -165,16 +165,66 @@ public class Plugin : CorePropertyChanged, IDisposable
}
/// <summary>
/// Gets an instance of the specified service using the plugins dependency injection container.
/// <para>Note: To use parameters reference Ninject and use <see cref="Kernel" /> directly.</para>
/// Gets an instance of the specified service using the plugins dependency injection container.
/// </summary>
/// <param name="arguments">Arguments to supply to the service.</param>
/// <typeparam name="T">The service to resolve.</typeparam>
/// <returns>An instance of the service.</returns>
public T Get<T>()
/// <seealso cref="Resolve"/>
public T Resolve<T>(params object?[] arguments)
{
if (Kernel == null)
throw new ArtemisPluginException("Cannot use Get<T> before the plugin finished loading");
return Kernel.Get<T>();
if (Container == null)
throw new ArtemisPluginException("Cannot use Resolve<T> before the plugin finished loading");
return Container.Resolve<T>(args: arguments);
}
/// <summary>
/// Gets an instance of the specified service using the plugins dependency injection container.
/// </summary>
/// <param name="type">The type of service to resolve.</param>
/// <param name="arguments">Arguments to supply to the service.</param>
/// <returns>An instance of the service.</returns>
/// <seealso cref="Resolve{T}"/>
public object Resolve(Type type, params object?[] arguments)
{
if (Container == null)
throw new ArtemisPluginException("Cannot use Resolve before the plugin finished loading");
return Container.Resolve(type, args: arguments);
}
/// <summary>
/// Registers service of <typeparamref name="TService" /> type implemented by <typeparamref name="TImplementation" /> type.
/// </summary>
/// <param name="scope">The scope in which the service should live, if you are not sure leave it on singleton.</param>
/// <typeparam name="TService">The service to register.</typeparam>
/// <typeparam name="TImplementation">The implementation of the service to register.</typeparam>
public void Register<TService, TImplementation>(PluginServiceScope scope = PluginServiceScope.Singleton) where TImplementation : TService
{
IReuse reuse = scope switch
{
PluginServiceScope.Transient => Reuse.Transient,
PluginServiceScope.Singleton => Reuse.Singleton,
PluginServiceScope.Scoped => Reuse.Scoped,
_ => throw new ArgumentOutOfRangeException(nameof(scope), scope, null)
};
Container.Register<TService, TImplementation>(reuse);
}
/// <summary>
/// Registers implementation type <typeparamref name="TImplementation" /> with itself as service type.
/// </summary>
/// <param name="scope">The scope in which the service should live, if you are not sure leave it on singleton.</param>
/// <typeparam name="TImplementation">The implementation of the service to register.</typeparam>
public void Register<TImplementation>(PluginServiceScope scope = PluginServiceScope.Singleton)
{
IReuse reuse = scope switch
{
PluginServiceScope.Transient => Reuse.Transient,
PluginServiceScope.Singleton => Reuse.Singleton,
PluginServiceScope.Scoped => Reuse.Scoped,
_ => throw new ArgumentOutOfRangeException(nameof(scope), scope, null)
};
Container.Register<TImplementation>(reuse);
}
/// <inheritdoc />
@@ -218,7 +268,7 @@ public class Plugin : CorePropertyChanged, IDisposable
feature.Instance?.Dispose();
SetEnabled(false);
Kernel?.Dispose();
Container?.Dispose();
PluginLoader?.Dispose();
GC.Collect();
@@ -340,4 +390,26 @@ public class Plugin : CorePropertyChanged, IDisposable
Dispose(true);
GC.SuppressFinalize(this);
}
}
/// <summary>
/// Represents a scope in which a plugin service is injected by the IOC container.
/// </summary>
public enum PluginServiceScope
{
/// <summary>
/// Services in this scope are never reused, a new instance is injected each time.
/// </summary>
Transient,
/// <summary>
/// Services in this scope are reused for as long as the plugin lives, the same instance is injected each time.
/// </summary>
Singleton,
/// <summary>
/// Services in this scope are reused within a container scope, this is an advanced setting you shouldn't need.
/// <para>To learn more see <a href="https://github.com/dadhi/DryIoc/blob/master/docs/DryIoc.Docs/ReuseAndScopes.md#reusescoped">the DryIoc docs</a>.</para>
/// </summary>
Scoped
}
@@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Core.DeviceProviders;
using Artemis.Core.LayerBrushes;
using Artemis.Core.LayerEffects;
using Artemis.Core.Modules;
using Artemis.Storage.Entities.Plugins;
using Humanizer;
using Newtonsoft.Json;
@@ -1,9 +1,8 @@
using System;
using System.Threading.Tasks;
using System.Timers;
using Artemis.Core.DryIoc.Factories;
using Artemis.Core.Modules;
using Artemis.Core.Services;
using Ninject;
using Serilog;
namespace Artemis.Core;
@@ -11,7 +10,7 @@ namespace Artemis.Core;
/// <summary>
/// Represents a registration for a timed plugin update
/// </summary>
public class TimedUpdateRegistration : IDisposable
public sealed class TimedUpdateRegistration : IDisposable
{
private readonly object _lock = new();
private readonly ILogger _logger;
@@ -21,9 +20,7 @@ public class TimedUpdateRegistration : IDisposable
internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Action<double> action, string? name)
{
if (CoreService.Kernel == null)
throw new ArtemisCoreException("Cannot create a TimedUpdateRegistration before initializing the Core");
_logger = CoreService.Kernel.Get<ILogger>();
_logger = LoggerFactory.Logger.ForContext<TimedUpdateRegistration>();
Feature = feature;
Interval = interval;
@@ -38,9 +35,7 @@ public class TimedUpdateRegistration : IDisposable
internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Func<double, Task> asyncAction, string? name)
{
if (CoreService.Kernel == null)
throw new ArtemisCoreException("Cannot create a TimedUpdateRegistration before initializing the Core");
_logger = CoreService.Kernel.Get<ILogger>();
_logger = LoggerFactory.Logger.ForContext<TimedUpdateRegistration>();
Feature = feature;
Interval = interval;
@@ -125,33 +120,13 @@ public class TimedUpdateRegistration : IDisposable
}
/// <inheritdoc />
public sealed override string ToString()
public override string ToString()
{
if (Interval.TotalSeconds >= 1)
return $"{Name} ({Interval.TotalSeconds} sec)";
return $"{Name} ({Interval.TotalMilliseconds} ms)";
}
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Stop();
Feature.Enabled -= FeatureOnEnabled;
Feature.Disabled -= FeatureOnDisabled;
_disposed = true;
}
}
private void TimerOnElapsed(object? sender, ElapsedEventArgs e)
{
if (!Feature.IsEnabled)
@@ -204,9 +179,12 @@ public class TimedUpdateRegistration : IDisposable
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
Feature.Profiler.ClearMeasurements(ToString());
Stop();
GC.SuppressFinalize(this);
Feature.Enabled -= FeatureOnEnabled;
Feature.Disabled -= FeatureOnDisabled;
_disposed = true;
Feature.Profiler.ClearMeasurements(ToString());
}
}