帮助Castle Windsor XML配置

时间:2010-11-23 15:42:50

标签: castle-windsor

我在我的应用程序的Caste-Windsor XML配置中定义了以下三个组件:

<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 个答案:

答案 0 :(得分:2)

虽然不是我在我的应用程序中需要做的确切解决方案,但我相信我已经弄清楚代码有什么问题。或者至少我找到了一种让它起作用的方法,暗示了原始问题。

我用自定义类替换了TheString的String类型。而已。一旦我这样做,一切正常。

我的猜测是,它与我尝试使用ValueType(原语)作为组件这一事实有关。我猜Castle不支持它。

所以,知道情况就是如此,我现在可以继续研究这种方法是否真的有效,或者我们是否需要改变方向。

<强>更新

为了完整起见,我想我会继续解释我为解决问题所做的工作并满足我的要求。

和以前一样,我可以通过定义为:

的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 :(得分:1)

这里不需要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))