Deploying dependencies into the Apache Ignite.NET service

While developing various applications that use the popular Castle Windsor library for dependency injection and Apache Ignite.NET as the “key” that opens the door to cloud computing, I was faced with a slight inconvenience: I had no opportunity to introduce dependency into via the so-called service grid.

The reason why this happens is pretty banal. Apache Ignite.NET serializes the service, sends it to one of the available servers, where it is deserialized and started. Since this process has no idea about Castle Windsor in any way, we get what we get.

To solve this problem, we need to create a plug-in for Apache Ignite.NET, which will receive the container responsible for the implementation of dependencies and allow the service to access it in order to receive this or that object.

First of all, we will introduce an additional level of abstraction for a container that provides dependency injection, so that in the future we can easily change its implementation to another one:

publicinterfaceIContainer
{
    T Resolve<T>();
}

publicclassDependencyInjectionContainer : IContainer
{
    protected IKernel Kernel { get; set; }
    publicDependencyInjectionContainer(IKernel kernel)
    {
        Kernel = kernel;
    }
    public T Resolve<T>()
    {
        return Kernel.Resolve<T>();
    }
}

publicclassDependencyInjectionInstaller : IWindsorInstaller
{
    publicvoidInstall(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component
                .For<IContainer>()
                .ImplementedBy<DependencyInjectionContainer>()
        );
    }
}

To create a plug-in, we need to create 3 classes: the class responsible for the configuration of the plug-in, the provider of the plug-in and, directly, the plug-in itself.

publicclassDependencyInjectionPlugin
{
    public IContainer Container { get; set; }
    public T Resolve<T>()
    {
        return Container.Resolve<T>();
    }
}

[PluginProviderType(typeof(DependencyInjectionPluginProvider))]
publicclassDependencyInjectionPluginConfiguration : IPluginConfiguration
{
    publicvoidWriteBinary(IBinaryRawWriter writer)
    {
        // No-op
    }
    publicint? PluginConfigurationClosureFactoryId { get; } = null; // No Java part
}

publicclassDependencyInjectionPluginProvider : IPluginProvider<DependencyInjectionPluginConfiguration>
{
    publicstring Name { get; } = "DependencyInjection";
    publicstring Copyright { get; } = "MIT";
    protected DependencyInjectionPlugin DependencyInjectionPlugin { get; set; }
    public T GetPlugin<T>() where T : class
    {
        return DependencyInjectionPlugin as T;
    }
    publicvoidStart(IPluginContext<DependencyInjectionPluginConfiguration> context)
    {
        DependencyInjectionPlugin = new DependencyInjectionPlugin();
    }
    publicvoidStop(bool cancel)
    {
    }
    publicvoidOnIgniteStart()
    {
    }
    publicvoidOnIgniteStop(bool cancel)
    {
    }
}

Great, it remains to download the plugin in Apache Ignite.NET.

publicclassIgniteInstaller : IWindsorInstaller
{
    publicvoidInstall(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component
                .For<IIgnite>()
                .UsingFactoryMethod(() => Ignition.Start(new IgniteConfiguration
                {
                    PluginConfigurations = new[] {new DependencyInjectionPluginConfiguration()}
                }))
        );
    }
}

When starting the application, we, as usual, initialize the dependency injection container, but now we are ready to transfer it to the plugin we just wrote:

var Done = new ManualResetEventSlim(false);
// Build Windsor containerusing (var container = new WindsorContainer())
{
    // Install DI abstraction layer
    container.Install(new DependencyInjectionInstaller());
    // Install cluster abstraction layer
    container.Install(new IgniteInstaller());
    // Attach DI container to cluster plugin
    container
        .Resolve<IIgnite>()
        .GetPlugin<DependencyInjectionPlugin>("DependencyInjection")
        .Container = container.Resolve<IContainer>();
    // Wait
    Done.Wait();
}

Congratulations, if you have read to the end, then you can get any dependency from your container inside the service. It looks like this:

publicclassClientConnectionService : IClientConnectionService, IService
{
    privatestaticreadonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
    [InstanceResource] private IIgnite Ignite { get; set; }
    publicvoidInit(IServiceContext context)
    {
        Logger.Debug("Initialized");
    }
    publicvoidExecute(IServiceContext context)
    {
        var plugin = Ignite.GetPlugin<DependencyInjectionPlugin>("DependencyInjection");
        var whatever = plugin.Resolve<IWhatever>();
        whatever.DoSomething();
    }
    publicvoidCancel(IServiceContext context)
    {
        Logger.Debug("Canceled");
    }
}

Also popular now: