сервисный стек с funq - автоматическое подключение по соглашению

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

К моему удивлению, это не сработало:

container.RegisterAutoWired<IMyDependency>();

Он выдает «System.NullReferenceException».

Это работает, если я делаю это:

container.RegisterAutoWiredAs<MyDependency, IMyDependency>();

Но тогда и это:

container.RegisterAs<MyDependency, IMyDependency>();

Так в чем же разница? Если «автоматическое связывание» не может найти конкретную реализацию, и не имеет значения, могут ли быть разрешены службы, требующие зависимости, то что такое автоматическое связывание?

Предполагается, что Funq сможет найти ваши конкретные реализации по соглашению? Если да, то что это за соглашение, если не одноимённость?

Спасибо.


person Jordan Morris    schedule 26.04.2013    source источник


Ответы (2)


Для таких простых запросов лучше всего просто связаться с источником, например. вот исходный код для RegisterAutoWired:

public IRegistration<T> RegisterAutoWired<T>()
{
    var serviceFactory = GenerateAutoWireFn<T>();
    return this.Register(serviceFactory);
}

Он создает автоматически подключаемую фабрику поверх реализации Concrete. У интерфейса нет реализации, он должен быть конкретным классом.

И исходный код для RegisterAs:

public IRegistration<TAs> RegisterAs<T, TAs>() where T : TAs 
{
    return this.RegisterAutoWiredAs<T, TAs>();
}

Это просто более короткий псевдоним, который вы можете использовать вместо RegisterAutoWiredAs.

person mythz    schedule 26.04.2013
comment
Итак, если я правильно понимаю, я должен делать: container.RegisterAutoWired‹MyDependency›(); Однако, если я делаю только это, во время выполнения (когда я вызываю службу с зависимостью) я получаю Требуемая зависимость типа IMyDependency не может быть разрешена. Поэтому мне все еще неясна цель этого метода, поскольку контейнер, похоже, не может найти интерфейс, соответствующий зарегистрированному конкретному типу. - person Jordan Morris; 26.04.2013
comment
Это довольно просто, он просто введет то, что вы зарегистрируете, если вы Register<MyDependency>, то он введет все MyDependency свойства. Если вы хотите, чтобы он вводил свойства IMyDependency, вам нужно вызвать RegisterAs<MyDependency,IMyDependency>. - person mythz; 26.04.2013
comment
В моем проекте у меня около 200 классов по соглашению: MyClass : IMyClass. Итак, в соответствии с этим каждый раз, когда я реализую новый класс или удаляю, можно ли сделать для него проводку? Unity, Windsor и StructureMap по соглашению используют автосвязь. - person nerijus; 11.03.2015

Вы имеете в виду «как я могу реализовать решение для поиска по сборкам и автоматической регистрации классов в ServiceStack IOC на основе соглашения?»

Если это так, у меня может быть решение для вас:

  1. Создайте интерфейс, который будут реализовывать ваши инъекционные классы.
  2. Пусть ваши классы для инъекций реализуют этот интерфейс.
  3. В загрузочном коде используйте отражение для поиска ваших сборок и получения списка всех классов, реализующих интерфейс с возможностью внедрения.
  4. Используйте отражение, чтобы получить имя класса и интерфейс на основе ваших соглашений.
  5. Вызовите метод IOC ServiceStack RegisterAutoWiredType и передайте класс и интерфейс для их регистрации.

Например, если наше соглашение об именах — ClassName IClassName:

private static void RegisterCustomTypes(Container container)
{
  //Get the Assembly Where the injectable classes are located.
  var assembly = Assembly.GetAssembly(typeof(IInjectable));

  //Get the injectable classes 
  var types =assembly.GetTypes()
    .Where(m => m.IsClass && m.GetInterface("IInjectable") != null);

  //loop through the injectable classes
  foreach (var theType in types)
  {
    //set up the naming convention
    var className = theType.Name;
    var interfaceName = string.Concat("I", className);
    //create the interface based on the naming convention
    var theInterface = theType.GetInterface(interfaceName);
    //register the type with the convention
    container.RegisterAutoWiredType(theType, theInterface);
  }
}

public interface IInjectable
{

}

//This class can be injected
public interface ITestManager : IInjectable
{
    void Execute(int id);
}

public class TestManager : ITestManager
{
    public void Execute(int id)
    {
        throw new System.NotImplementedException();
    }
}
person Ken Burkhardt    schedule 15.10.2013
comment
С момента моего первоначального сообщения я понял, что Func не имеет встроенного поиска по сборке. Если вы реализуете свое собственное отражение, как предлагается здесь, думаете ли вы, что какое-либо преимущество (например, производительность) останется при использовании Func по сравнению с другим решением, таким как Ninject и т. д.? - person Jordan Morris; 17.10.2013
comment
Точно сказать не могу. Может быть, у мифза есть какие-то указания на этот счет? - person Ken Burkhardt; 18.10.2013
comment
@Saber, DI запускается только один раз при запуске веб-приложения. Разницу в производительности можно не учитывать. Windsor или Ninject ... и т. д., все они хороши. Единственная причина, по которой я использую Funq вместо других, заключается в том, что он поставляется с SS, а мне лень поддерживать еще один IoC отдельно от пакета SS. - person Tom; 02.02.2014
comment
@KenBurkhardt: Что, если я использую Стратегию, например? Как в сборке есть более одной реализации интерфейса? - person Vaibhav; 07.07.2016