2013-07-05 6 views
0

С Castle Windsor 3.2 Мне нужно разрешить реализацию сервиса на лету в зависимости от контекстных параметров. Вот простой пример того, что я хочу сделать:Замок Виндзор, выбрав реализацию сервиса в зависимости от некоторых параметров контекста

У меня есть службы IFoo

public interface IFoo 
{ 
    object GetSomething(); 
} 

Реализовано 2 различных классов Foo1 и Foo2

public class FooBase 
{ 
    public int Number {get; private set;} 

    public FooBase(int number) 
    { 
     Number = number; 
    } 
} 

public class Foo1 : IFoo 
{ 
    public Foo1(int number):base(number) 
    public object GetSomething() 
    { 
     return "Foo1"; 
    } 
} 

public class Foo2 : IFoo 
{ 
    public Foo2(int number):base(number) 
    public object GetSomething() 
    { 
     return "Foo2"; 
    } 
} 

Я хочу, чтобы позвонить в Виндзорский замок разрешить метод с номером в качестве параметра и в зависимости от числа, которое я хочу иметь: Foo1 или Foo2:

var foo1 = container.Resolve<IFoo>(new {number= 1}); 
// foo1 is Foo1 
var foo2 = container.Resolve<IFoo>(new {number= 2}); 
// foo2 is Foo2 

Я пробовал несколько потенциальных решений, но я очень смущен из-за отсутствия документации и примеров Castle Windsor, добавив, что большинство примеров не обновлены и используют устаревший API.

Так что я видел несколько примеров, используя следующие понятия, но ни один из них не казался большим мое требование:

  1. HandlerSelector
  2. типизированного завод объект
  3. UsingFactoryMethod
+0

Можете ли вы предоставить более подробную информацию о вашем сценарии ? Что поставляет значение «число» во время выполнения? Я предполагаю, что есть какой-то объект контекста где-то, где хранятся эта информация? Возможно, есть способ сделать это с фабриками типов и т. Д., Но это пахнет обычной моделью, в которой я использую HandlerSelectors на регулярной основе, но имеет значение владелец «числа». Возможно, вы сможете немного изменить свое желаемое решение и получить гораздо более чистый результат. – kellyb

ответ

1

использовать следующий регистрационный код:

container = new WindsorContainer(); 
     container.AddFacility<TypedFactoryFacility>(); 
     container.Register(
      Component.For<FooSelector>, 
      Component.For<Foo1>(), 
      Component.For<Foo2>(), 
      Component.For<IFooFactory>().AsFactory(c => c.SelectedWith<FooSelector>()) 
     ); 

Создать Foo завод:

public interface IFooFactory 
{ 
    IFoo CreateFoo(int number); 
} 

и селектор:

public class FooSelector : DefaultTypedFactoryComponentSelector 
{ 
    protected override Type GetComponentType(System.Reflection.MethodInfo method, object[] arguments) 
    { 
     var argument = (int) arguments[0]; 
     if (argument == 1) return typeof (Foo1); 
     if (argument == 2) return typeof(Foo2); 
     throw new ApplicationException(); 
    } 
} 

Теперь решить IFooFactory и вызвать создание METHODE со значением, что вы хотите.

С уважением, Marwijn.

+0

Спасибо, но я пробую это решение. Я получаю сообщение об ошибке: Castle.MicroKernel.ComponentNotFoundException: запрошенный компонент с именем 'CreateFoo' не был найден в контейнере. Вы забыли его зарегистрировать? Нет компонентов, поддерживающих запрошенную услугу «... Foo2».Вам необходимо зарегистрировать компоненты, чтобы иметь возможность их использовать. – enenkey

+0

Я разобрался с проблемой, используя GetComponentName вместо GetComponentType и давая имя для каждого зарегистрированного компонента с помощью метода Named («Foo1»). Именованный («Foo2») – enenkey

+0

@enenkey, я забыл, что вы зарегистрировались компонент Foo1 и Foo2 в этом случае. Вы можете увидеть фиксированный регистрационный код выше. Но если вы хотите, вы действительно можете решить назвать свой компонент. – Marwijn

0

Вот код, который работал на меня:

container = new WindsorContainer(); 
     container.AddFacility<TypedFactoryFacility>(); 
     container.Register(
      Component.For<IFoo>().ImplementedBy<Foo1>().Named("Foo1"), 
      Component.For<IFoo>().ImplementedBy<Foo2>().Named("Foo2"), 
      Component.For<IFooFactory>().AsFactory(c => c.SelectedWith<FooSelector>()) 
     ); 

Создать фабрику Foo:

public interface IFooFactory 
{ 
    IFoo CreateFoo(int number); 
} 

и селектор:

public class FooSelector : DefaultTypedFactoryComponentSelector 
{ 
    protected override string GetComponentName(System.Reflection.MethodInfo method, object[] arguments) 
    { 
     var argument = (int) arguments[0]; 
     return string.Format("Foo{0}", argument); 
    } 
}