2015-09-08 2 views
1

У меня есть куча событий, которые обрабатываются с помощью обработчиков событий, таких как следующие:Ninject отображения для общего типа

обработчика событий:

public class DeliveryEventHandlers : 
IConsume<DeliveryCreated>, 
IConsume<DeliveryUpdated>{ 

readonly IDocumentSession _documentSession; 

public DeliveryEventHandlers(IDocumentSession documentSession) 
{ 
    _documentSession = documentSession; 
} 

public void Consume(DeliveryCreated @event) 
{ 
    //... 
} 

public void Consume(DeliveryUpdated @event) 
{ 
    //... 
} 
... 

Событие:

public class DeliveryCreated : IEvent 
{ 
    public Guid DeliveryId { get; set; } 
    ... 
} 

public class DeliveryUpdated : IEvent 
{ 
    public Guid DeliveryId { get; set; } 
    ... 
} 

И я необходимо написать привязку Ninject, которая будет по запросу типа события, дать мне обработчик (ы) события, который использует эти события. Это то, что я придумал:

public void BindEventHandlers(IContext context) { 
     Kernel.Bind(x => 
     { 
      x.FromAssemblyContaining(typeof(DeliveryCreated)) 
      .SelectAllClasses() 
      .InheritedFrom<IEvent>() 
      .BindWith(new EventBindingGenerator()); 
     }); 
    } 

    public class EventBindingGenerator : IBindingGenerator 
    { 
     public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot) 
     { 
      yield return bindingRoot.Bind(x => 
      { 
       x.FromAssemblyContaining(typeof(DeliveryEventHandlers)) 
       .SelectAllClasses() 
       .InheritedFrom(IConsume<typeof(type)>); 
       // This Part^
      }); 
     } 
    } 

, но это не будет компилировать - я врезался в препятствие на линии над комментарием: // Эта часть^

Мне нужно сделать запрос для:

_context.Get<DeliveryCreated>() 

и получать подтверждение о доставке.

Любая помощь была бы оценена!

Спасибо, H

ответ

0

Вы можете вручную сканировать сборку и зарегистрировать все классы, которые реализуют интерфейс IConsumer<>. Как это:

foreach (Type type in assembly.GetTypes().Where(x => x.IsClass)) 
{ 
    foreach (
     var @interface in 
      type.GetInterfaces() 
       .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IConsume<>))) 
    { 
     kernel.Bind(@interface).To(type); 
    } 
} 

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

var single_consumer = kernel.Get<IConsume<DeliveryCreated>>(); 

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

var all_consumers = kernel.GetAll<IConsume<DeliveryCreated>>(); 
+0

Спасибо за ответ так быстро Yacoub, но это решение не работает. Он фактически привязал мои обработчики к интерфейсу IEvent классов Event. – HCdev

+0

Я не понимаю, что вы имеете в виду. Можете ли вы еще раз объяснить, что он сделал? –

1

Это на самом деле может быть решено достаточно легко с функциональностью расширения конвенции:

kernel.Bind(x => x.FromAssemblyContaining(typeof(DeliveryCreated)) 
    .IncludingNonePublicTypes() // may not be needed in your case 
    .SelectAllClasses() 
    .InheritedFrom(typeof(IConsume<>)) 
    .BindAllInterfaces()); 

следующий тест успешно (синтаксис из FluentAssertions):

kernel.Get<IConsume<DeliverCreated>>().Should().BeOfType<DeliveryEventHandlers>(); 
kernel.Get<IConsume<DeliveryUpdated>>().Should().BeOfType<DeliveryEventHandlers>(); 

В качестве альтернативы, если вы хотите, чтобы убедиться, что вы не хотите, чтобы связать IConsume<...> реализациям более типов, чем это необходимо, вы можете заменить BindAllInterfaces заявление следующим образом:

private static IEnumerable<Type> SelectConsumeInterfacesOnly(
    Type type, IEnumerable<Type> baseTypes) 
{ 
    var matchingTypes = baseTypes.Where(t => 
     t.IsGenericType 
     && t.GetGenericTypeDefinition() == typeof (IConsume<>)); 
    return matchingTypes; 
} 

kernel.Bind(x => x.FromThisAssembly() 
    .IncludingNonePublicTypes() 
    .SelectAllClasses() 
    .InheritedFrom(typeof(IConsume<>)) 
    .BindSelection(SelectConsumeInterfacesOnly)); 

Опять же, я проверил, что это на самом деле работает.

+0

Спасибо за ваш ответ BatteryBackupUnit. Это похоже на хорошо продуманный ответ - у меня еще не было возможности его протестировать - просто проверяя, мне нужно запросить вот так: _context.Get () не так: _context.Get >() - будет ли это работать? – HCdev

+0

@ HCdev. Если вы сделаете 'Get ' '' T ', то будет возвращено.Ваш 'DeliveryEventHandlers' не реализует' DeliveryCreated', его невозможно передать в 'DeliveryCreated'. Это соответствует языковой спецификации, и поэтому вы не сможете этого достичь, однако попробуйте. Вам нужно будет выполнить '_context.Get >()'. Можете ли вы предоставить (псевдокод в порядке), что следует делать с помощью 'DeliveryCreatedEventHandler' после его получения? – BatteryBackupUnit

Смежные вопросы