Внедрение зависимостей в сервис Apache Ignite.NET

от автора

Разрабатывая различные приложения, использующие популярную библиотеку Castle Windsor для внедрения зависимостей и Apache Ignite.NET в качестве «ключика», который открывает дверь в «облачные» вычисления, я столкнулся с небольшим неудобством: у меня не было никакой возможности внедрить зависимость в сервис, запускаемый через так называемый Service Grid.

Причина по которой это происходит довольна банальна. Apache Ignite.NET сериализует сервис, отправляет его на один из доступных серверов, где он десериализуется и запускается. Так как этот процесс никаким образом не имеет понятия о Castle Windsor, мы получаем то, что получаем.

Для решения этой проблемы нам необходимо создать плагин для Apache Ignite.NET, который получит контейнер, отвечающий за внедрение зависимостей и предоставить возможность сервису обратиться к нему, для получения того или иного объекта.

Первым делом внедрим дополнительный уровень абстракции для контейнера, обеспечивающего внедрения зависимостей, для того чтобы в будущем мы могли легко сменить его имплементацию на другую:

public interface IContainer {     T Resolve<T>(); } 

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

public class DependencyInjectionInstaller : IWindsorInstaller {     public void Install(IWindsorContainer container, IConfigurationStore store)     {         container.Register(             Component                 .For<IContainer>()                 .ImplementedBy<DependencyInjectionContainer>()         );     } } 

Для создания плагина нам необходимо создать 3 класса: класс, отвечающий за конфигурацию плагина, провайдер плагина и, непосредственно, сам плагин.

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

[PluginProviderType(typeof(DependencyInjectionPluginProvider))] public class DependencyInjectionPluginConfiguration : IPluginConfiguration {     public void WriteBinary(IBinaryRawWriter writer)     {         // No-op     }       public int? PluginConfigurationClosureFactoryId { get; } = null; // No Java part } 

public class DependencyInjectionPluginProvider : IPluginProvider<DependencyInjectionPluginConfiguration> {     public string Name { get; } = "DependencyInjection";       public string Copyright { get; } = "MIT";       protected DependencyInjectionPlugin DependencyInjectionPlugin { get; set; }       public T GetPlugin<T>() where T : class     {         return DependencyInjectionPlugin as T;     }       public void Start(IPluginContext<DependencyInjectionPluginConfiguration> context)     {         DependencyInjectionPlugin = new DependencyInjectionPlugin();     }       public void Stop(bool cancel)     {       }       public void OnIgniteStart()     {       }       public void OnIgniteStop(bool cancel)     {       } } 

Отлично, осталось загрузить плагин в Apache Ignite.NET.

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

При старте приложения мы, как обычно, инициализируем контейнер внедрения зависимостей, однако теперь мы готовы передать его плагину, который только что написали:

var Done = new ManualResetEventSlim(false);   // Build Windsor container using (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(); } 

Поздравляю, если вы дочитали до конца, то вы сможете получить любую зависимость из вашего контейнера внутри сервиса. Выглядит это так:

public class ClientConnectionService : IClientConnectionService, IService {     private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();       [InstanceResource] private IIgnite Ignite { get; set; }       public void Init(IServiceContext context)     {         Logger.Debug("Initialized");     }       public void Execute(IServiceContext context)     {         var plugin = Ignite.GetPlugin<DependencyInjectionPlugin>("DependencyInjection");           var whatever = plugin.Resolve<IWhatever>();         whatever.DoSomething();     }       public void Cancel(IServiceContext context)     {         Logger.Debug("Canceled");     } } 


ссылка на оригинал статьи https://habr.com/post/420479/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *