Removing UnityContainer and fixing service loading

This commit is contained in:
Zoe Roux 2021-05-04 01:25:36 +02:00
parent a18f393926
commit 3e8dbc84a8
15 changed files with 159 additions and 207 deletions

View File

@ -62,7 +62,7 @@ namespace Kyoo.Authentication
}
/// <inheritdoc />
public IServiceCollection Configure(IServiceCollection services, ICollection<Type> availableTypes)
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
{
string publicUrl = _configuration.GetValue<string>("public_url");
@ -148,7 +148,6 @@ namespace Kyoo.Authentication
AllowedOrigins = {new Uri(publicUrl).GetLeftPart(UriPartial.Authority)}
};
services.AddSingleton<ICorsPolicyService>(cors);
return services;
}
/// <inheritdoc />

View File

@ -4,7 +4,6 @@ using System.Linq;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Unity;
namespace Kyoo.Controllers
{
@ -59,30 +58,14 @@ namespace Kyoo.Controllers
/// <summary>
/// A configure method that will be run on plugin's startup.
/// </summary>
/// <param name="container">A unity container to register new services.</param>
/// <param name="services">A service container to register new services.</param>
/// <param name="availableTypes">The list of types that are available for this instance. This can be used
/// for conditional type. See <see cref="ProviderCondition.Has(System.Type,System.Collections.Generic.ICollection{System.Type})"/>
/// or <see cref="ProviderCondition.Has(System.Collections.Generic.ICollection{System.Type},System.Collections.Generic.ICollection{System.Type})"/>></param>
void Configure(IUnityContainer container, ICollection<Type> availableTypes) {}
/// or <see cref="ProviderCondition.Has(System.Collections.Generic.ICollection{System.Type},System.Collections.Generic.ICollection{System.Type})"/>>
/// You can't simply check on the service collection because some dependencies might be registered after your plugin.
/// </param>
void Configure(IServiceCollection services, ICollection<Type> availableTypes);
/// <summary>
/// An optional configure method that will be run on plugin's startup.
/// This method may be used instead or with the
/// <see cref="Configure(Unity.IUnityContainer,System.Collections.Generic.ICollection{System.Type})"/> method
/// if you use a library that configure itself with a <see cref="IServiceCollection"/>.
/// Every service put in this container will be registered to the unity container after this method.
/// </summary>
/// <param name="services">An empty service container to register new services.</param>
/// <param name="availableTypes">The list of types that are available for this instance. This can be used
/// for conditional type. See <see cref="ProviderCondition.Has(System.Type,System.Collections.Generic.ICollection{System.Type})"/>
/// or <see cref="ProviderCondition.Has(System.Collections.Generic.ICollection{System.Type},System.Collections.Generic.ICollection{System.Type})"/>></param>
/// <returns>You should return the <see cref="services"/> parameter or another container if you want.
/// This container will be added to Kyoo's unity container.</returns>
IServiceCollection Configure(IServiceCollection services, ICollection<Type> availableTypes)
{
return services;
}
/// <summary>
/// An optional configuration step to allow a plugin to change asp net configurations.
/// WARNING: This is only called on Kyoo's startup so you must restart the app to apply this changes.

View File

@ -1,5 +1,7 @@
using System.Collections.Generic;
using Kyoo.Models.Exceptions;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Controllers
{
@ -29,11 +31,26 @@ namespace Kyoo.Controllers
/// </summary>
/// <returns>All plugins currently loaded.</returns>
public ICollection<IPlugin> GetAllPlugins();
/// <summary>
/// Load plugins and their dependencies from the plugin directory.
/// </summary>
/// <param name="plugins">
/// An initial plugin list to use.
/// You should not try to put plugins from the plugins directory here as they will get automatically loaded.
/// </param>
public void LoadPlugins(ICollection<IPlugin> plugins);
/// <summary>
/// Configure services adding or removing services as the plugins wants.
/// </summary>
/// <param name="services">The service collection to populate</param>
public void ConfigureServices(IServiceCollection services);
/// <summary>
/// Load new plugins from the plugin directory.
/// Configure an asp net application applying plugins policies.
/// </summary>
/// <exception cref="MissingDependencyException">If a plugin can't be loaded because a dependency can't be resolved.</exception>
public void ReloadPlugins();
/// <param name="app">The asp net application to configure</param>
public void ConfigureAspnet(IApplicationBuilder app);
}
}

View File

@ -24,14 +24,8 @@
<PackageReference Include="JetBrains.Annotations" Version="2021.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.0-beta-20204-02" PrivateAssets="All" />
<PackageReference Include="Unity.Abstractions" Version="5.11.7" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
<HintPath>..\..\..\..\..\..\usr\share\dotnet\shared\Microsoft.AspNetCore.App\5.0.5\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -1,6 +1,6 @@
using System;
using Kyoo.Controllers;
using Unity;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo
{
@ -12,55 +12,55 @@ namespace Kyoo
/// <summary>
/// Register a new task to the container.
/// </summary>
/// <param name="container">The container</param>
/// <param name="services">The container</param>
/// <typeparam name="T">The type of the task</typeparam>
/// <returns>The initial container.</returns>
public static IUnityContainer RegisterTask<T>(this IUnityContainer container)
public static IServiceCollection AddTask<T>(this IServiceCollection services)
where T : class, ITask
{
container.RegisterType<ITask, T>();
return container;
services.AddSingleton<ITask, T>();
return services;
}
/// <summary>
/// Register a new repository to the container.
/// </summary>
/// <param name="container">The container</param>
/// <param name="services">The container</param>
/// <param name="lifetime">The lifetime of the repository. The default is scoped.</param>
/// <typeparam name="T">The type of the repository.</typeparam>
/// <remarks>
/// If your repository implements a special interface, please use <see cref="RegisterRepository{T,T}"/>
/// If your repository implements a special interface, please use <see cref="AddRepository{T,T2}"/>
/// </remarks>
/// <returns>The initial container.</returns>
public static IUnityContainer RegisterRepository<T>(this IUnityContainer container)
public static IServiceCollection AddRepository<T>(this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped)
where T : IBaseRepository
{
Type repository = Utility.GetGenericDefinition(typeof(T), typeof(IRepository<>));
if (repository != null)
{
container.RegisterType(repository, typeof(T));
container.RegisterType<IBaseRepository, T>(repository.FriendlyName());
}
else
container.RegisterType<IBaseRepository, T>(typeof(T).FriendlyName());
return container;
services.Add(ServiceDescriptor.Describe(repository, typeof(T), lifetime));
services.Add(ServiceDescriptor.Describe(typeof(IBaseRepository), typeof(T), lifetime));
return services;
}
/// <summary>
/// Register a new repository with a custom mapping to the container.
/// </summary>
/// <param name="container"></param>
/// <param name="services"></param>
/// <param name="lifetime">The lifetime of the repository. The default is scoped.</param>
/// <typeparam name="T">The custom mapping you have for your repository.</typeparam>
/// <typeparam name="T2">The type of the repository.</typeparam>
/// <remarks>
/// If your repository does not implements a special interface, please use <see cref="RegisterRepository{T}"/>
/// If your repository does not implements a special interface, please use <see cref="AddRepository{T}"/>
/// </remarks>
/// <returns>The initial container.</returns>
public static IUnityContainer RegisterRepository<T, T2>(this IUnityContainer container)
public static IServiceCollection AddRepository<T, T2>(this IServiceCollection services,
ServiceLifetime lifetime = ServiceLifetime.Scoped)
where T2 : IBaseRepository, T
{
container.RegisterType<T, T2>();
return container.RegisterRepository<T2>();
services.Add(ServiceDescriptor.Describe(typeof(T), typeof(T2), lifetime));
return services.AddRepository<T2>(lifetime);
}
}
}

View File

@ -3,8 +3,8 @@ using System.Collections.Generic;
using Kyoo.Controllers;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Unity;
namespace Kyoo.Postgresql
{
@ -57,9 +57,9 @@ namespace Kyoo.Postgresql
}
/// <inheritdoc />
public void Configure(IUnityContainer container, ICollection<Type> availableTypes)
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
{
container.RegisterFactory<DatabaseContext>(_ => new PostgresContext(
services.AddScoped<DatabaseContext>(_ => new PostgresContext(
_configuration.GetDatabaseConnection("postgres"),
_environment.IsDevelopment()));
}

View File

@ -5,11 +5,10 @@ using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Kyoo.Models.Exceptions;
using Kyoo.UnityExtensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Unity;
namespace Kyoo.Controllers
{
@ -20,9 +19,9 @@ namespace Kyoo.Controllers
public class PluginManager : IPluginManager
{
/// <summary>
/// The unity container. It is given to the Configure method of plugins.
/// The service provider. It allow plugin's activation.
/// </summary>
private readonly IUnityContainer _container;
private readonly IServiceProvider _provider;
/// <summary>
/// The configuration to get the plugin's directory.
/// </summary>
@ -40,14 +39,14 @@ namespace Kyoo.Controllers
/// <summary>
/// Create a new <see cref="PluginManager"/> instance.
/// </summary>
/// <param name="container">A unity container to allow plugins to register new entries</param>
/// <param name="provider">A service container to allow initialization of plugins</param>
/// <param name="config">The configuration instance, to get the plugin's directory path.</param>
/// <param name="logger">The logger used by this class.</param>
public PluginManager(IUnityContainer container,
public PluginManager(IServiceProvider provider,
IConfiguration config,
ILogger<PluginManager> logger)
{
_container = container;
_provider = provider;
_config = config;
_logger = logger;
}
@ -72,7 +71,7 @@ namespace Kyoo.Controllers
}
/// <inheritdoc />
public void ReloadPlugins()
public void LoadPlugins(ICollection<IPlugin> plugins)
{
string pluginFolder = _config.GetValue<string>("plugins");
if (!Directory.Exists(pluginFolder))
@ -80,7 +79,7 @@ namespace Kyoo.Controllers
_logger.LogTrace("Loading new plugins...");
string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories);
ICollection<IPlugin> newPlugins = pluginsPaths.SelectMany(path =>
plugins = pluginsPaths.SelectMany(path =>
{
path = Path.GetFullPath(path);
try
@ -90,7 +89,7 @@ namespace Kyoo.Controllers
return assembly.GetTypes()
.Where(x => typeof(IPlugin).IsAssignableFrom(x))
.Where(x => _plugins.All(y => y.GetType() != x))
.Select(x => (IPlugin)_container.Resolve(x))
.Select(x => (IPlugin)ActivatorUtilities.CreateInstance(_provider, x))
.ToArray();
}
catch (Exception ex)
@ -98,32 +97,40 @@ namespace Kyoo.Controllers
_logger.LogError(ex, "Could not load the plugin at {Path}", path);
return Array.Empty<IPlugin>();
}
}).ToList();
if (!_plugins.Any())
newPlugins.Add(new CoreModule());
_plugins.AddRange(newPlugins);
}).Concat(plugins).ToList();
ICollection<Type> available = GetProvidedTypes();
foreach (IPlugin plugin in newPlugins)
_plugins.AddRange(plugins.Where(plugin =>
{
Type missing = plugin.Requires.FirstOrDefault(x => available.All(y => !y.IsAssignableTo(x)));
if (missing != null)
{
Exception error = new MissingDependencyException(plugin.Name, missing.Name);
_logger.LogCritical(error, "A plugin's dependency could not be met");
}
else
{
plugin.Configure(_container, available);
_container.AddServices(plugin.Configure(new ServiceCollection(), available));
}
}
if (missing == null)
return true;
Exception error = new MissingDependencyException(plugin.Name, missing.Name);
_logger.LogCritical(error, "A plugin's dependency could not be met");
return false;
}));
if (!_plugins.Any())
_logger.LogInformation("No plugin enabled");
else
_logger.LogInformation("Plugin enabled: {Plugins}", _plugins.Select(x => x.Name));
}
/// <inheritdoc />
public void ConfigureServices(IServiceCollection services)
{
ICollection<Type> available = GetProvidedTypes();
foreach (IPlugin plugin in _plugins)
plugin.Configure(services, available);
}
/// <inheritdoc />
public void ConfigureAspnet(IApplicationBuilder app)
{
foreach (IPlugin plugin in _plugins)
plugin.ConfigureAspNet(app);
}
/// <summary>
/// Get the list of types provided by the currently loaded plugins.

View File

@ -9,7 +9,6 @@ using Kyoo.Models.Exceptions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Unity;
namespace Kyoo.Controllers
{
@ -22,7 +21,7 @@ namespace Kyoo.Controllers
/// <summary>
/// The service provider used to activate
/// </summary>
private readonly IUnityContainer _container;
private readonly IServiceProvider _provider;
/// <summary>
/// The configuration instance used to get schedule information
/// </summary>
@ -54,15 +53,15 @@ namespace Kyoo.Controllers
/// Create a new <see cref="TaskManager"/>.
/// </summary>
/// <param name="tasks">The list of tasks to manage</param>
/// <param name="container">The service provider to request services for tasks</param>
/// <param name="provider">The service provider to request services for tasks</param>
/// <param name="configuration">The configuration to load schedule information.</param>
/// <param name="logger">The logger.</param>
public TaskManager(IEnumerable<ITask> tasks,
IUnityContainer container,
IServiceProvider provider,
IConfiguration configuration,
ILogger<TaskManager> logger)
{
_container = container;
_provider = provider;
_configuration = configuration.GetSection("scheduledTasks");
_logger = logger;
_tasks = tasks.Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList();
@ -173,7 +172,7 @@ namespace Kyoo.Controllers
foreach (PropertyInfo property in properties)
{
object value = _container.Resolve(property.PropertyType);
object value = _provider.GetService(property.PropertyType);
property.SetValue(obj, value);
}
}
@ -244,7 +243,7 @@ namespace Kyoo.Controllers
/// <inheritdoc />
public void ReloadTasks()
{
_tasks = _container.Resolve<IEnumerable<ITask>>().Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList();
// _tasks = _provider.Resolve<IEnumerable<ITask>>().Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList();
EnqueueStartupTasks();
}
}

View File

@ -2,8 +2,7 @@ using System;
using System.Collections.Generic;
using Kyoo.Controllers;
using Kyoo.Tasks;
using Unity;
using Unity.Lifetime;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo
{
@ -52,32 +51,33 @@ namespace Kyoo
public ICollection<Type> Requires => ArraySegment<Type>.Empty;
/// <inheritdoc />
public void Configure(IUnityContainer container, ICollection<Type> availableTypes)
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
{
container.RegisterType<IFileManager, FileManager>(new SingletonLifetimeManager());
container.RegisterType<ITranscoder, Transcoder>(new SingletonLifetimeManager());
container.RegisterType<IThumbnailsManager, ThumbnailsManager>(new SingletonLifetimeManager());
container.RegisterType<IProviderManager, ProviderManager>(new SingletonLifetimeManager());
container.RegisterType<ITaskManager, TaskManager>(new SingletonLifetimeManager());
services.AddSingleton<IFileManager, FileManager>();
services.AddSingleton<ITranscoder, Transcoder>();
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();
services.AddSingleton<IProviderManager, ProviderManager>();
services.AddSingleton<ITaskManager, TaskManager>();
services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager);
container.RegisterType<ILibraryManager, LibraryManager>(new HierarchicalLifetimeManager());
services.AddScoped<ILibraryManager, LibraryManager>();
if (ProviderCondition.Has(typeof(DatabaseContext), availableTypes))
{
container.RegisterRepository<ILibraryRepository, LibraryRepository>();
container.RegisterRepository<ILibraryItemRepository, LibraryItemRepository>();
container.RegisterRepository<ICollectionRepository, CollectionRepository>();
container.RegisterRepository<IShowRepository, ShowRepository>();
container.RegisterRepository<ISeasonRepository, SeasonRepository>();
container.RegisterRepository<IEpisodeRepository, EpisodeRepository>();
container.RegisterRepository<ITrackRepository, TrackRepository>();
container.RegisterRepository<IPeopleRepository, PeopleRepository>();
container.RegisterRepository<IStudioRepository, StudioRepository>();
container.RegisterRepository<IGenreRepository, GenreRepository>();
container.RegisterRepository<IProviderRepository, ProviderRepository>();
services.AddRepository<ILibraryRepository, LibraryRepository>();
services.AddRepository<ILibraryItemRepository, LibraryItemRepository>();
services.AddRepository<ICollectionRepository, CollectionRepository>();
services.AddRepository<IShowRepository, ShowRepository>();
services.AddRepository<ISeasonRepository, SeasonRepository>();
services.AddRepository<IEpisodeRepository, EpisodeRepository>();
services.AddRepository<ITrackRepository, TrackRepository>();
services.AddRepository<IPeopleRepository, PeopleRepository>();
services.AddRepository<IStudioRepository, StudioRepository>();
services.AddRepository<IGenreRepository, GenreRepository>();
services.AddRepository<IProviderRepository, ProviderRepository>();
}
container.RegisterTask<Crawler>();
services.AddTask<Crawler>();
}
}
}

View File

@ -47,8 +47,6 @@
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Unity.Container" Version="5.11.11" />
<PackageReference Include="Unity.Microsoft.DependencyInjection" Version="5.11.5" />
</ItemGroup>
<ItemGroup>

12
Kyoo/Models/LazyDi.cs Normal file
View File

@ -0,0 +1,12 @@
using System;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Models
{
public class LazyDi<T> : Lazy<T>
{
public LazyDi(IServiceProvider provider)
: base(provider.GetRequiredService<T>)
{ }
}
}

View File

@ -1,16 +1,12 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Kyoo.UnityExtensions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Unity;
using Unity.Microsoft.DependencyInjection;
namespace Kyoo
{
/// <summary>
@ -80,9 +76,6 @@ namespace Kyoo
/// <returns>A new web host instance</returns>
private static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
UnityContainer container = new();
container.EnableDebugDiagnostic();
return new WebHostBuilder()
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
.UseConfiguration(SetupConfig(new ConfigurationBuilder(), args).Build())
@ -100,8 +93,6 @@ namespace Kyoo
if (context.HostingEnvironment.IsDevelopment())
StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
})
// .UseUnityProvider(container)
.UseUnityServiceProvider(container)
.ConfigureServices(x => x.AddRouting())
.UseKestrel(options => { options.AddServerHeader = false; })
.UseIIS()

View File

@ -1,6 +1,7 @@
using System;
using System.IO;
using Kyoo.Controllers;
using Kyoo.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SpaServices.AngularCli;
@ -10,8 +11,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Unity;
using Unity.Lifetime;
namespace Kyoo
{
@ -20,16 +19,38 @@ namespace Kyoo
/// </summary>
public class Startup
{
/// <summary>
/// The configuration context
/// </summary>
private readonly IConfiguration _configuration;
private readonly ILoggerFactory _loggerFactory;
/// <summary>
/// A plugin manager used to load plugins and allow them to configure services / asp net.
/// </summary>
private readonly IPluginManager _plugins;
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory, IServiceProvider provider)
/// <summary>
/// Created from the DI container, those services are needed to load information and instantiate plugins.s
/// </summary>
/// <param name="hostProvider">
/// The ServiceProvider used to create this <see cref="Startup"/> instance.
/// The host provider that contains only well-known services that are Kyoo independent.
/// This is used to instantiate plugins that might need a logger, a configuration or an host environment.
/// </param>
/// <param name="configuration">The configuration context</param>
/// <param name="loggerFactory">A logger factory used to create a logger for the plugin manager.</param>
public Startup(IServiceProvider hostProvider, IConfiguration configuration, ILoggerFactory loggerFactory)
{
_configuration = configuration;
_loggerFactory = loggerFactory;
_plugins = new PluginManager(hostProvider, _configuration, loggerFactory.CreateLogger<PluginManager>());
_plugins.LoadPlugins(new [] {new CoreModule()});
}
/// <summary>
/// Configure the WebApp services context.
/// </summary>
/// <param name="services">The service collection to fill.</param>
public void ConfigureServices(IServiceCollection services)
{
string publicUrl = _configuration.GetValue<string>("public_url");
@ -63,23 +84,18 @@ namespace Kyoo
// });
// });
// services.AddAuthentication()
// container.Resolve<IConfiguration>();
services.AddSingleton<ITaskManager, TaskManager>();
services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager);
}
public void ConfigureContainer(IUnityContainer container)
{
container.RegisterType<IPluginManager, PluginManager>(new SingletonLifetimeManager());
container.RegisterInstance(_configuration);
PluginManager pluginManager = new(container, _configuration, _loggerFactory.CreateLogger<PluginManager>());
pluginManager.ReloadPlugins();
services.AddSingleton(_plugins);
services.AddTransient(typeof(Lazy<>), typeof(LazyDi<>));
_plugins.ConfigureServices(services);
}
public void Configure(IUnityContainer container, IApplicationBuilder app, IWebHostEnvironment env)
/// <summary>
/// Configure the asp net host.
/// </summary>
/// <param name="app">The asp net host to configure</param>
/// <param name="env">The host environment (is the app in development mode?)</param>
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
@ -124,9 +140,7 @@ namespace Kyoo
spa.UseAngularCliServer("start");
});
IPluginManager pluginManager = container.Resolve<IPluginManager>();
foreach (IPlugin plugin in pluginManager.GetAllPlugins())
plugin.ConfigureAspNet(app);
_plugins.ConfigureAspnet(app);
app.UseEndpoints(endpoints =>
{

View File

@ -1,32 +0,0 @@
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Unity;
using Unity.Microsoft.DependencyInjection;
namespace Kyoo.UnityExtensions
{
public static class UnityExtensions
{
public static IWebHostBuilder UseUnityProvider(this IWebHostBuilder host, UnityContainer container)
{
UnityProvider factory = new(container);
return host.ConfigureServices((_, services) =>
{
services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<UnityContainer>>(factory));
services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IUnityContainer>>(factory));
services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>(factory));
});
}
public static IUnityContainer AddServices(this IUnityContainer container, IServiceCollection services)
{
return (IUnityContainer)typeof(ServiceProviderExtensions).Assembly
.GetType("Unity.Microsoft.DependencyInjection.Configuration")
!.GetMethod("AddServices", BindingFlags.Static | BindingFlags.NonPublic)
!.Invoke(null, new object[] {container, services});
}
}
}

View File

@ -1,30 +0,0 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Unity;
using Unity.Microsoft.DependencyInjection;
namespace Kyoo.UnityExtensions
{
public class UnityProvider : ServiceProviderFactory, IServiceProviderFactory<UnityContainer>
{
private readonly UnityContainer _container;
public UnityProvider(UnityContainer container)
: base(container)
{
_container = container;
}
public UnityContainer CreateBuilder(IServiceCollection services)
{
_container.AddServices(services);
return _container;
}
public IServiceProvider CreateServiceProvider(UnityContainer containerBuilder)
{
return CreateServiceProvider(containerBuilder as IUnityContainer);
}
}
}