Skip to content

Instantly share code, notes, and snippets.

@uhfath
Forked from Ilchert/DIPlugins.cs
Created January 12, 2024 07:15
Show Gist options
  • Save uhfath/e2936875a4b48524136450a3802a8101 to your computer and use it in GitHub Desktop.
Save uhfath/e2936875a4b48524136450a3802a8101 to your computer and use it in GitHub Desktop.
static int _idCounter = 0;
interface IService
{
public int Id { get; }
public void Test(string suffix);
}
class RootService : IService
{
public int Id { get; } = ++_idCounter;
public void Test(string suffix) => Console.WriteLine("{0}ROOT_SERVICE: {1}", suffix, Id);
}
class RootInterfaceService : IService
{
public int Id { get; } = ++_idCounter;
public void Test(string suffix) => Console.WriteLine("{0}ROOT_INTERFACE_SERVICE: {1}", suffix, Id);
}
class RootScopedService : IService
{
public int Id { get; } = ++_idCounter;
public void Test(string suffix) => Console.WriteLine("{0}ROOT_SCOPED_SERVICE: {1}", suffix, Id);
}
class PluginRootOverrideService : IService
{
public int Id { get; } = ++_idCounter;
public void Test(string suffix) => Console.WriteLine("{0}PLUGIN_ROOT_OVERRIDE_SERVICE: {1}", suffix, Id);
}
class PluginScopedService : IService
{
public int Id { get; } = ++_idCounter;
public void Test(string suffix) => Console.WriteLine("{0}PLUGIN_SCOPED_SERVICE: {1}", suffix, Id);
}
interface IPlugin
{
public void Test(string suffix);
}
class App : IDisposable
{
private readonly RootService _rootService;
private readonly IService _rootInterfaceService;
private readonly RootScopedService _rootScopedService;
private readonly ServiceProvider _pluginServiceProvider;
public App(
RootService rootService,
IService rootInterfaceService,
RootScopedService rootScopedService,
ServiceCollection serviceCollection,
IServiceProvider serviceProvider)
{
_rootService = rootService;
_rootInterfaceService = rootInterfaceService;
_rootScopedService = rootScopedService;
_pluginServiceProvider = InitPlugin(PluginImplementation.Name, serviceCollection, serviceProvider);
}
public void Test(string suffix)
{
_rootService.Test("HOST -> " + suffix);
_rootInterfaceService.Test("HOST -> " + suffix);
_rootScopedService.Test("HOST -> " + suffix);
using var scope = _pluginServiceProvider.CreateScope();
scope.ServiceProvider.GetRequiredService<IPlugin>().Test("HOST -> ");
}
public void Dispose()
{
_pluginServiceProvider.Dispose();
}
}
class PluginImplementation : IPlugin
{
private readonly IService _pluginOverride;
private readonly PluginScopedService _pluginScopedService;
private readonly RootService _rootService;
private readonly RootScopedService _rootScopedService;
public const string Name = nameof(PluginImplementation);
public static void Configure(ServiceCollection rootServices)
{
rootServices.Configure<PluginRegistration>(Name, o => o.ConfigureServices = static (IServiceProvider sp, ServiceCollection services) =>
{
services.AddScoped<IPlugin, PluginImplementation>(); //main plugin service
services.Replace(ServiceDescriptor.Singleton<IService, PluginRootOverrideService>()); //host's singleton replacement in plugin
services.AddScoped<PluginScopedService>(); //scoped service in pluging
});
}
public PluginImplementation(
IService pluginOverride,
PluginScopedService pluginScopedService,
RootService rootService,
RootScopedService rootScopedService)
{
_pluginOverride = pluginOverride;
_pluginScopedService = pluginScopedService;
_rootService = rootService;
_rootScopedService = rootScopedService;
}
public void Test(string suffix)
{
_rootService.Test("PLUGIN -> " + suffix);
_pluginScopedService.Test("PLUGIN -> " + suffix);
_pluginOverride.Test("PLUGIN -> " + suffix);
_rootScopedService.Test("PLUGIN -> " + suffix);
}
}
class PluginRegistration
{
public Action<IServiceProvider, ServiceCollection> ConfigureServices = delegate { };
}
static ServiceProvider InitPlugin(string pluginName, ServiceCollection rootServices, IServiceProvider serviceProvider)
{
var pluginServices = new ServiceCollection() { rootServices };
var pluginRegistration = serviceProvider.GetRequiredService<IOptionsMonitor<PluginRegistration>>().Get(PluginImplementation.Name);
pluginRegistration.ConfigureServices(serviceProvider, pluginServices);
return pluginServices.BuildServiceProvider(new ServiceProviderOptions
{
ValidateOnBuild = true,
ValidateScopes = true,
});
}
void Main()
{
var services = new ServiceCollection();
services.AddSingleton<RootService>(); //host's singleton service
services.AddSingleton<IService, RootInterfaceService>(); //same as above but by an interface
services.AddScoped<RootScopedService>(); //host's scoped service
services.AddScoped<App>(); //host's scoped application service
services.AddSingleton(services);
PluginImplementation.Configure(services);
using var rootServiceProvider = services.BuildServiceProvider(new ServiceProviderOptions
{
ValidateOnBuild = true,
ValidateScopes = true,
});
using var rootScope_1 = rootServiceProvider.CreateScope();
rootScope_1.ServiceProvider.GetRequiredService<App>().Test("MAIN #1.1 -> ");
// rootScope_1.ServiceProvider.GetRequiredService<App>().Test("MAIN #1.2 -> ");
//
// using var rootScope_2 = rootServiceProvider.CreateScope();
// rootScope_2.ServiceProvider.GetRequiredService<App>().Test("MAIN #2.1 -> ");
// rootScope_2.ServiceProvider.GetRequiredService<App>().Test("MAIN #2.2 -> ");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment