Помогите с настройкой Castle Windsor XML - PullRequest
1 голос
/ 23 ноября 2010

У меня есть следующие три компонента, определенные в конфигурации XML Caste-Windsor для моего приложения:

<component id="StringFactory"
           service="IStringFactory, MyApp"
           type="DefaultStringFactory, MyApp"
           lifestyle="singleton"
           />

<component id="TheString"
           type="System.String"
           factoryId="StringFactory"
           factoryCreate="CreateString"
           >
  <parameters>
    <name>SomeString</name>
  </parameters>
</component>

<component id="TheTarget"
           service="ITarget, MyApp"
           type="TheTarget, MyApp"
           lifestyle="transient"
           >
  <parameters>
    <aString>${TheString}</aString>
  </parameters>
</component>

И определено следующее средство:

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

Когда я запускаю приложениеи установите точку останова в конструкторе класса TheObject, значение, переданное в качестве параметра aString, равно «$ {TheString}», когда я ожидаю, что оно разрешится до значения компонента с этим именем.

ТакжеУ меня есть точка останова в конструкторе StringFactory и метод CreateString, ни один из которых не ударил.Я знаю, что конфигурация используется, поскольку другие компоненты разрешаются правильно.

Что я здесь упускаю или делаю неправильно?

ОБНОВЛЕНИЕ

В светеиз огромного значения этой темы я реорганизовал приведенный выше код, чтобы удалить все, что связано со строками подключения.Первоначальная цель этого поста заключалась в том, чтобы ввести свойство со значением, возвращаемым методом, для другого объекта.Каким-то образом эта мысль была потеряна в дискуссии о том, почему я использую XML вместо конфигурации на основе кода, и если это хороший способ внедрить строку подключения.

Приведенный выше подход далек от первоначальной идеи, и онбыл извлечен из нескольких других дискуссий на эту тему, и наши требования являются такими, какие они есть.Мне бы хотелось помочь понять, почему конфигурация в том виде, в каком она есть (правильный подход или нет), не работает должным образом.

Я проверил, что первые два компонента были созданы правильно.Когда я вызываю Container.Resolve ("TheString"), я получаю верное значение.По какой-то причине синтаксис параметра работает неправильно.

Есть идеи?

Ответы [ 2 ]

2 голосов
/ 24 ноября 2010

Хотя это и не является окончательным решением того, что мне нужно делать в моем приложении, я считаю, что выяснил, что не так с кодом. Или, по крайней мере, я нашел способ заставить его работать, который намекает на исходную проблему.

Я заменил тип String для TheString на собственный класс. Вот и все. Как только я это сделал, все работало нормально.

Я предполагаю, что это как-то связано с тем, что я пытался использовать ValueType (примитив) в качестве компонента. Я думаю, Касл не поддерживает это.

Итак, зная, что это так, теперь я могу перейти к выяснению, действительно ли этот подход сработает или нам нужно изменить направление.

UPDATE

Ради полноты, я решил пойти дальше и объяснить, что я сделал, чтобы решить мою проблему И удовлетворить мои требования.

Как и раньше, у меня есть доступ к моим параметрам конфигурации через службу IConfigurationService, определенную как:

<component id="ConfigurationService"
           service="MyApp.IConfigurationService, MyApp"
           type="MyApp.RuntimeConfigurationService, MyApp"
           lifestyle="singleton"
           />

Это автоматически внедряется в мою (новую) IConnectionFactory, которая отвечает за генерацию объектов IDbConnection на основе строк подключения, определенных в файле конфигурации приложения. Завод объявлен как:

<component id="ConnectionFactory"
           service="MyApp.Factories.IConnectionFactory, MyApp"
           type="MyApp.Factories.DefaultConnectionFactory, MyApp"
           lifestyle="singleton"
           />

Чтобы определить, какое соединение используется моим репозиторием, я объявляю каждое соединение как компонент, используя ConnectionFactory для создания каждого экземпляра:

<component id="MyDbConnection"
           type="System.Data.IDbConnection,
                 System.Data, Version=2.0.0.0, Culture=neutral,
                 PublicKeyToken=b77a5c561934e089"
           factoryId="ConnectionFactory"
           factoryCreate="CreateConnection"
           lifestyle="transient"
           >
  <parameters>
    <connectionStringName>MyDB</connectionStringName>
  </parameters>
</component>

Обратите внимание на полностью описанную ссылку на System.Data. Я обнаружил, что это необходимо при обращении к сборкам в GAC.

Наконец, мой репозиторий определяется как:

<component id="MyRepository"
           service="MyApp.Repositories.IMyRepository, MyApp"
           type="MyApp.Sql.SqlMyRepository, MyApp.Sql"
           lifestyle="transient"
           >
  <parameters>
    <connection>${MyDbConnection}</connection>
  </parameters>
</component>

Теперь все разрешается правильно, и у меня нет НИКАКИХ жестко закодированных строк, скомпилированных в мой код. Нет имен строк подключения, ключей настройки приложения или чего-либо еще. Приложение полностью реконфигурируемо из файлов XML, что является требованием, которое я должен выполнить. Кроме того, другие разработчики, которые будут работать с решением, могут управлять фактическими строками соединения так, как они привыкли. Беспроигрышный.

Надеюсь, это поможет любому, кто столкнется с подобным сценарием.

1 голос
/ 23 ноября 2010

Вам не нужны здесь XML-регистрации, поскольку вам, вероятно, не нужно менять компоненты или менять используемый метод без перекомпиляции. Написание настраиваемого приложения не означает необходимость использования регистраций XML.

Проблема с этой конкретной регистрацией XML, которую вы опубликовали, состоит в том, что строка подключения имеет значение , но обрабатывается как служба .

Это гораздо проще сделать с помощью регистраций кода, например ::

.
var container = new WindsorContainer();
container.Register(Component.For<IConfigurationService>().ImplementedBy<RuntimeConfigurationService>());
container.Register(Component.For<ITheRepository>().ImplementedBy<TheRepository>()
                            .LifeStyle.Transient
                            .DynamicParameters((k, d) => {
                                var cfg = k.Resolve<IConfigurationService>();
                                d["connectionString"] = cfg.GetConnectionString();
                                k.ReleaseComponent(cfg);
                            }));

Или, если вы не хотите зависеть от IConfigurationService, вы можете сделать что-то вроде:

container.Register(Component.For<ITheRepository>().ImplementedBy<TheRepository>()
                            .LifeStyle.Transient
                            .DependsOn(Property.ForKey("connectionString")                                             
                                               .Is(ConfigurationManager.ConnectionStrings[ConfigurationManager.AppSettings["connName"]].ConnectionString))
...