Регистрация компонентов с замком, которые динамически создаются DynamicProxy - PullRequest
0 голосов
/ 28 октября 2010

Так что я некоторое время усердно работал над созданием решения, которое создает определенные компоненты, используя только Castle DynamicProxy (версия 2.2) и перехватчик. Все выглядит отлично, за исключением того, что в конце всего этого я понял, что мне нужно зарегистрировать эти компоненты в контейнере виндзор. Это возможно или моя работа была напрасной?

Я изготовлю 2 конфигурации замка, чтобы объяснить мою проблему. Первый работает, а второй нет.

Первый конфиг (какое-то время он работал отлично):

<castle>
  <facilities>
    <facility
        id="factory.support"
        type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
  </facilities>

  <components>
    <component
        id="Factory"
        service="Foo.IFactory, Foo"
        type="Foo.Local.LocalFactory, Foo.Local" />
    <component
        id="Loader"
        service="Foo.Contracts.ILoader, Foo.Contracts"
        type="Foo.Local.Loader, Foo.Local"
        factoryId="Factory" factoryCreate="GetLoader" />
  </components>
</castle>

Второй конфиг (я не знаю, что добавить в атрибут type, и он не работает без него):

<castle>
  <facilities>
    <facility
        id="factory.support"
        type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
  </facilities>

  <components>
    <component
        id="Factory"
        service="Foo.IFactory, Foo"
        type="Foo.Remote.RemoteFactory, Foo.Remote" />
    <component
        id="Loader"
        service="Foo.Contracts.ILoader, Foo.Contracts"
        type="I DUNNO, WHAT'S THE TYPE?"
        factoryId="Factory" factoryCreate="GetLoader" />
  </components>
</castle>

Итак, мои изготовленные конфиги регистрируют фабрику, затем я регистрирую фабрику, а затем регистрирую свой компонент "ILoader". «LocalFactory» создает фактический тип для компонента ILoader, тогда как «RemoteFactory» создает компонент ILoader, используя динамический прокси, создавая прокси без целей. Т.е. я использую метод ProxyGenerator.CreateInterfaceProxyWithoutTarget, поэтому базовый класс отсутствует.

Итак, есть ли надежда в регистрации компонентов согласно второму конфигу?

EDIT: К сожалению, в настоящее время использование API-интерфейса для быстрой конфигурации недоступно. Итак, чтобы сузить мой вопрос, возможно ли добиться этого с помощью конфигурации XML?

1 Ответ

2 голосов
/ 28 октября 2010

Я считаю, что это возможно с помощью Fluent Registration API и механизма «UsingFactoryMethod». Я попытался воспроизвести ваш сфабрикованный сценарий в приведенном ниже тестовом примере.

UPDATE

Это на самом деле возможно и с конфигурацией XML. Хитрость заключается в том, чтобы просто перечислить сам интерфейс как «тип» в конфигурации (или, что то же самое, указать только «тип», поскольку «сервис» будет установлен на «тип», если он явно не указан). Я обновил тестовый пример ниже, чтобы включить тест «TestXml», который использует конфигурацию xml для достижения желаемого результата. Тест "TestFluent" использует API для быстрой регистрации для достижения этого. К вашему сведению, я использую Castle Windsor 2.0 здесь, так как я предполагаю, что вы используете.

using Castle.DynamicProxy;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using NUnit.Framework;

namespace CastleTests
{
    public interface ILoader
    {
        void Load();
    }

    public interface ILoaderFactory
    {
        ILoader GetLoader();
    }

    public class LoaderFactory : ILoaderFactory
    {
        public ILoader GetLoader()
        {
            return GetLoaderStatic();
        }

        public static ILoader GetLoaderStatic()
        {
            return (ILoader) new ProxyGenerator().CreateInterfaceProxyWithoutTarget(typeof (ILoader));
        }
    }

    [TestFixture]
    public class DynamicFactoryTests
    {
        [Test]
        public void TestFluent()
        {
            using (var container = new WindsorContainer())
            {
                container.AddFacility<FactorySupportFacility>();
                container.Register(
                    Component.For<ILoader>().UsingFactoryMethod(() => LoaderFactory.GetLoaderStatic())
                    );
                var loader = container.Resolve<ILoader>();
                Assert.That(loader.GetType().FullName, Is.EqualTo("Castle.Proxies.ILoaderProxy"));
            }
        }

        [Test]
        public void TestXml()
        {
            using (var container = new WindsorContainer("factory.xml"))
            {
                var loader = container.Resolve<ILoader>();
                Assert.That(loader.GetType().FullName, Is.EqualTo("Castle.Proxies.ILoaderProxy"));
            }
        }
    }
}

Содержимое «factory.xml» выглядит следующим образом:

<castle>
  <facilities>
    <facility
        id="factory.support"
        type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
  </facilities>
  <components>
    <component
        id="foo"
        service="CastleTests.ILoaderFactory, CastleTests"
        type="CastleTests.LoaderFactory, CastleTests" />
    <component
        id="bar"
        type="CastleTests.ILoader, CastleTests"
        factoryId="foo" factoryCreate="GetLoader" />
  </components>
</castle>
...