WedX - журнал о программировании и компьютерных науках

Интеграция с Autofac WCF — разрешение зависимостей на основе данных запроса

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

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

[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 является плюсом.
  • Также желательно сохранить неизменной подпись конструктора службы. (см. мой ответ ниже)
20.01.2014

Ответы:


1

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

// 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];
    }
}

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

21.01.2014
  • Спасибо @Александр. Ваш ответ выглядит рабочим, и я предпочитаю его кодированию собственной фабрики. Однако я хотел бы сохранить подпись конструктора как есть, потому что ее изменение нарушит мои тесты. Я добавляю это ограничение к вопросу. И я также не сторонник смешивания логики приложения и разрешения зависимостей в одном классе. Какие еще варианты вы имели в виду? 21.01.2014
  • К сожалению, я не проверил ссылку метаданных. Дай мне сек. 21.01.2014
  • Хорошо, читай, аналогичная концепция. Пока лучшее решение, но мне оно не нравится. 21.01.2014
  • @jdarsie Тогда единственное решение — написать собственную фабрику. 21.01.2014
  • @jdarsie Ваш параметр конструктора неверен с учетом ваших требований. Ваше требование состоит в том, что MyWcfService не будет знать, какая реализация IService ему нужна, пока не будет вызвана Operation. Ваша текущая подпись конструктора подразумевает, что MyWcfService знает, какая единственная реализация ему нужна при создании экземпляра. Вы можете поумничать с большим количеством фреймворков, но на самом деле ваше намерение четко передается с помощью решения Александра. Например, если для первого вызова Operation требуется TypeA, а для второго вызова требуется TypeB,, то этот класс работает неправильно. 22.01.2014
  • @ Джим Болла, это правильно, и требования были скорректированы за несколько минут до вашего комментария. Перепроверьте вопрос и посмотрите на мой ответ. 22.01.2014

  • 2

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

    Поставщик экземпляра Autofac, создающий экземпляр службы, не использует и не передает сообщение операции. Вот последняя реализация метода в 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, вам нужно внедрить зависимость в свой класс с помощью чего-то другого, кроме внедрения конструктора, то есть @решение Александра Никитина. Это разумно, но я согласен с комментарием «не люблю это».

    Вариант 2. Пользовательский IInstanceProvider.

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

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

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

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

    1. Расширяемость WCF — IInstanceProvider - для хорошего фона
    2. Расширяемость WCF — инспекторы сообщений — поиск раздела, который начинается с объектов WCF Message, может быть «использован только один раз». Вам необходимо следовать этим правилам при проверке сообщения.
    21.01.2014
  • Спасибо @ErnieL. Я с вами по варианту 1. И вариант 2 звучит круто, но я не хочу патчить Autofac каждый раз, когда выходит новая версия. Кстати, я нашел решение своей проблемы. Публикация ответа через несколько минут. 22.01.2014
  • Новые материалы

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

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]