2015-01-08 8 views
4

У меня есть следующая проблема.Как передать зависимость классу, который реализует IEventProcessor (Event Hub)

используем Event Hub. В следующем классе мы наследуем от IEventProcessor, и, как вы видите, мы используем Service Locator. Мы не можем заставить его работать с инсталляцией конструктора/свойства. Кажется, что Castle Windsor не может разрешать зависимости, когда класс, который наследует от IEventProcessor. Это известная проблема или есть что-то, что мне нужно сделать, чтобы заставить ее работать?

Ниже приведен код:

public class EventProcessor : IEventProcessor 
{ 
    private readonly IEventService _eventService; 
    private readonly ILogger _logger; 
    private readonly Lazy<RetryPolicy> _retryPolicy; 
    private readonly IConfigurationProvider _configurationProvider; 

    public EventProcessor() 
    { 
     try 
     { 
      _eventService = ContainerProvider.Current.Container.Resolve<IEventService>(); 
      _logger = ContainerProvider.Current.Container.Resolve<ILogger>(); 
      _configurationProvider =  ContainerProvider.Current.Container.Resolve<IConfigurationProvider>(); 

     } 
     catch (Exception exception) 
     { 
      _logger.WriteError(string.Format("Error occured when intializing EventProcessor: '{0}'", exception)); 
     } 
    } 

    public Task OpenAsync(PartitionContext context) 
    { 
     return Task.FromResult(0); 
    } 

    public async Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> events) 
    { 
     var eventsList = events.ToList(); 
     EventData lastEvent = null; 
     foreach (var eventData in eventsList) 
     { 
      _logger.WriteVerbose(string.Format("Consumming {0} events...", eventsList.Count())); 
      _eventService.ProcessEvent(eventData); 
      lastEvent = eventData; 
     } 

     if (lastEvent != null) 
     { 
      await AzureServiceBusRetryPolicy.ExecuteAsync(async() => await context.CheckpointAsync(lastEvent)); 
     } 
    } 

    public async Task CloseAsync(PartitionContext context, CloseReason reason) 
    { 
     _logger.WriteInfo("EventHub processor was closed for this reason: " + reason); 

     if (reason == CloseReason.Shutdown) 
     { 
      await AzureServiceBusRetryPolicy.ExecuteAsync(async() => await context.CheckpointAsync()); 
     } 

    } 


} 

Благодаря

ответ

0

Это не так, чтобы придать dependecies используя Виндзорский замок. Учитывая ваш код ctor-injection будет работать с конструктором, перечисляющим зависимости в качестве параметров. В вашем случае это будет выглядеть sth. например

public EventProcessor(IEventService eventService, ILogger logger, IConfigurationProvider configProvider) 
{ 
    try 
    { 
     this._eventService = eventService; 
     this._logger = logger; // however, i suggest using Property injection for that, see next example 
     this._configurationProvider = configProvider; 

    } 
    catch (Exception exception) 
    { 
     this._logger.WriteError(string.Format("Error occured when intializing EventProcessor: '{0}'", exception)); 
    } 
} 

После этого вы можете разрешить сам EventProcessor, и эти зависимости будут введены.

Впрыск недвижимости работает с объектами общедоступной недвижимости. Вы просто определяете их как номинальные свойства, и их вводят отдельно.

public ILogger Logger {get; set;} 

Рассмотрите возможность использования замка Виндзор способа придать лесоруб (см LoggingFacility in Winsdor docs Может быть, вы хотите использовать NLog или log4net (как я) -.?>, То есть готовое к использованию nugetpackage (Замок WINDOR log4net integraton).

4

Я использую Autofac, но столкнулся с той же проблемой.

Я решил, реализовав IEventProcessorFactory и использовать его при регистрации процессора в EventProcessorHost.

Чтобы дать е Xample, мой EventProcessorHost выглядит примерно так:

public class EventHubProcessorHost 
{ 
    private readonly IEventProcessorFactory _eventProcessorFactory; 
    private readonly string _serviceBusConnectionString; 
    private readonly string _storageConnectionString; 
    private readonly string _eventHubName; 

    public EventHubProcessorHost(IEventProcessorFactory eventProcessorFactory, string serviceBusConnectionString, string storageConnectionString, string eventHubName) 
    { 
     _eventProcessorFactory = eventProcessorFactory; 
     _serviceBusConnectionString = serviceBusConnectionString; 
     _storageConnectionString = storageConnectionString; 
     _eventHubName = eventHubName; 
    } 

    public void Start() 
    { 
     var builder = new ServiceBusConnectionStringBuilder(_serviceBusConnectionString) 
     { 
      TransportType = TransportType.Amqp 
     }; 

     var client = EventHubClient.CreateFromConnectionString(builder.ToString(), _eventHubName); 

     try 
     { 
      var eventProcessorHost = new EventProcessorHost("singleworker", 
       client.Path, client.GetDefaultConsumerGroup().GroupName, builder.ToString(), _storageConnectionString); 

      eventProcessorHost.RegisterEventProcessorFactoryAsync(_eventProcessorFactory); 
     } 
     catch (Exception exp) 
     { 
      Console.WriteLine("Error on send: " + exp.Message); 
     } 
    } 
} 

И завод я прохожу в имеет ссылку на мой контейнер IoC:

public class MyEventProcessorFactory : IEventProcessorFactory 
{ 
    private readonly IComponentContext _componentContext; 

    public MyEventProcessorFactory(IComponentContext componentContext) 
    { 
     _componentContext = componentContext; 
    } 

    public IEventProcessor CreateEventProcessor(PartitionContext context) 
    { 
     return _componentContext.Resolve<IEventProcessor>(); 
    } 
} 

Это позволяет мне использовать инъекции конструктора, как обычно в моем EventProcessor:

public class MyEventProcessor : IEventProcessor 
{ 
    private IFoo _foo; 

    public MyEventProcessor(IFoo foo) 
    { 
     _foo = foo; 
    } 

    public Task OpenAsync(PartitionContext context) 
    { 
     return Task.FromResult<object>(null); 
    } 

    public async Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> events) 
    { 
     foreach (var eventData in events) 
     { 
      // Processing code 
     } 

     await context.CheckpointAsync(); 
    } 

    public async Task CloseAsync(PartitionContext context, CloseReason reason) 
    { 
     if (reason == CloseReason.Shutdown) 
     { 
      await context.CheckpointAsync(); 
     } 
    } 
} 

Тогда я просто провод все вверх, как обычно в контейнере Autofac при пуске:

builder.RegisterType<Foo>().As<IFoo>() 

builder.RegisterType<MyEventProcessor>().As<IEventProcessor>() 

builder.Register(c => new MyEventProcessorFactory(c.Resolve<IComponentContext>())).As<IEventProcessorFactory>(); 

Надеюсь, это поможет.

+0

Не следует вводить IComponentContext, вводить Func eventProcessorFactory, и вы должны иметь возможность вызвать RegisterType (). –