2014-01-20 2 views
3

Как настроить контейнер Autofac, чтобы он разрешал зависимости службы WCF на основе значений свойств параметра-операции (объекта запроса)?Autofac WCF Integration - разрешать зависимости на основе данных запроса

Например, с учетом этого контрактом данных ...

[DataContract] 
public class MyRequest 
{ 
    [DataMember] 
    public bool MyBool { get; set; } 
} 

это WCF сервис ...

public class MyWcfService : IWcfService 
{ 
    private IService m_service; 

    public MyWcfService(IService service) 
    { 
     m_service = service; 
    } 

    public virtual MyResponse Operation(MyRequest request) { } 
} 

и эта зависимость ...

public interface IService { } 
public class TypeA : IService { } 
public class TypeB : IService { } 

Я хотел бы контейнер для разрешения TypeA, если MyBool равен true и TypeB в противном случае. Доступна ли эта функция? Должен ли я относиться к проблеме по-другому?

Ограничения:

  • Избежание пакет Autofac.Extras.Multitenant является плюсом.
  • Также необходимо сохранить подпись конструктора службы без изменений. (см. Мой ответ ниже)

ответ

5

Существует несколько способов достичь этого. Один из способов - использовать IIndex<K,V>. Это встроенная функция «поиска», которая выбирает между реализациями служб на основе ключа. Вы можете найти дополнительную информацию об Autofac's wiki page. Примерный код может выглядеть так:

// Register your dependency with a key, for example a bool flag 
builder.RegisterType<TypeA>().Keyed<IService>(true); 
builder.RegisterType<TypeB>().Keyed<IService>(false); 

// Your service could look like: 
public class MyWcfService 
{ 
    private readonly IIndex<bool, IService> _services; 

    // Inject IIndex<Key,Value> into the constructor, Autofac will handle it automatically 
    public MyWcfService(IIndex<bool, IService> services) 
    { 
     _services = services; 
    } 

    public virtual void Operation(MyRequest request) 
    { 
     // Get the service that you need by the key 
     var service = _services[request.MyBool]; 
    } 
} 

Другой подход заключается в использовании функции метаданных. Дополнительная информация о wiki page.

+0

Спасибо @Alexandr. Ваш ответ выглядит как работающий, и я предпочитаю его кодировать мою собственную фабрику. Тем не менее, я хотел бы сохранить подпись конструктора, так как это связано с тем, что изменение приведет к нарушению моих тестов. Я добавляю это ограничение к вопросу. И я также не поклонник смешивания логики приложений и разрешения зависимостей в одном классе. Каковы другие варианты, которые вы имели в виду? – xdarsie

+0

К сожалению, я не проверял ссылку Метаданные. Дайте мне сек. – xdarsie

+0

Хорошо, прочитайте, аналогичная концепция. Пока лучшее решение, но я не люблю его. – xdarsie

1

Вариант 1 - Использование Autofac:

Провайдер экземпляра Autofac, который создает экземпляр службы не использовать или передавать по сообщению операции. Вот latest implementation of the method в Autofac. Обратите внимание, что параметр message не используется.

public class AutofacInstanceProvider : IInstanceProvider 
{ 
    // lots of code removed... 

    public object GetInstance(InstanceContext instanceContext, Message message) 
    { 
     if (instanceContext == null) 
     { 
      throw new ArgumentNullException("instanceContext"); 
     } 
     var extension = new AutofacInstanceContext(_rootLifetimeScope); 
     instanceContext.Extensions.Add(extension); 
     return extension.Resolve(_serviceData); 
    } 
} 

Таким образом, чтобы получить требуемое поведение с существующим Autofac кода, вам необходимо вводить зависимость в свой класс, используя нечто иное, чем инъекции конструктора, который @Alexandr Nikitin's solution. Это разумно, но я согласен с комментарием «не любя его».

Вариант 2 - Система пользовательского IInstanceProvider:

Написание пользовательского WCF IInstanceProvider является разумным вариантом, но это будет много кода.

Хорошей новостью является то, что code in Autoface.Integration.WCF - хороший пример, и вы можете подключить свою реализацию к Autofac.

Плохая новость заключается в том, что код Autofac.Integration.WCF сам не использует инъекцию зависимости. Например, AutofacDependencyInjectionServiceBehavior напрямую звонит var instanceProvider = new AutofacInstanceProvider(_rootLifetimeScope, _serviceData). В результате вам придется выполнить замену на AutofacInstanceProvider, AutofacDependencyInjectionServiceBehavior, AutofacHostFactory и, возможно, больше.Затем вам нужно создать расширение для AutofacInstanceContext, чтобы содержать информацию, считанную из сообщения. Его много кода.

Если вы собираетесь делать на заказ IInstanceProvider я предлагаю прочитать на блоге Карлоса Фигуейра в:

  1. WCF расширяемости - IInstanceProvider - для хорошего фона
  2. WCF расширяемости - Message Inspectors - поиск на участке, начинающемся с объектами Message WCF могут быть только «потреблены один раз». При проверке сообщения вам необходимо следовать этим правилам.
+0

Спасибо @ErnieL. Я с вами по варианту 1. И вариант 2 звучит круто, но я не хочу исправлять Autofac каждый раз, когда выпущена новая версия. Кстати, я решил решить проблему. Проводя ответ в течение нескольких минут. – xdarsie

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