-
-
Save uhfath/e2936875a4b48524136450a3802a8101 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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