Castle Windsor Service Override in XML configuration

374 views Asked by At

I am using xml configuration to set up components in Castle Windsor. I have this config:

  <component id="SurescriptsDatabase"

    service="System.Data.IDbConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
    type="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" lifestyle="transient">
    <parameters>
      <connectionString>REDACTED1</connectionString>
    </parameters>
  </component>
  <component id="Surescriptsv10Database"
    service="System.Data.IDbConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
    type="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" lifestyle="transient">
    <parameters>
      <connectionString>REDACTED2</connectionString>
    </parameters>
  </component>
  <component id="Surescriptsv10StagingDatabase"
    service="System.Data.IDbConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"
    type="System.Data.SqlClient.SqlConnection, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" lifestyle="transient">
    <parameters>
      <connectionString>REDACTED3</connectionString>
    </parameters>
  </component>

  <component id="SurescriptsWatcher" 
             type="PatientFirst.Framework.Services.ScalarQueryWatcher, PatientFirst.Framework.Services">
    <parameters>
      <Database>${SurescriptsDatabase}</Database>
      <Frequency>0.00:01:00</Frequency>
      <CustomMessage>Surescripts v6 is not running</CustomMessage>
      <Query>select count(1) from [SureScripts_Production].[dbo].[ToSureScriptMessagesQueue] where requesttime &lt; dateadd(minute,-1,getdate()) and responsetime is null</Query>
      <MinResult>-1</MinResult>
      <MaxResult>0</MaxResult>
    </parameters>
  </component>
  <component id="Surescriptsv10Watcher" type="PatientFirst.Framework.Services.ScalarQueryWatcher, PatientFirst.Framework.Services">
    <parameters>
      <Database>${Surescriptsv10Database}</Database>
      <Frequency>0.00:01:00</Frequency>
      <CustomMessage>Surescripts v10 is not running</CustomMessage>
      <Query>select count(1) from [SureScripts_v10_Production].[dbo].[ToSureScriptMessagesQueue] where requesttime &lt; dateadd(minute,-1,getdate()) and responsetime is null</Query>
      <MinResult>-1</MinResult>
      <MaxResult>0</MaxResult>
    </parameters>
  </component>
  <component id="Surescriptsv10StagingWatcher" type="PatientFirst.Framework.Services.ScalarQueryWatcher, PatientFirst.Framework.Services">
    <parameters>
      <Database>${Surescriptsv10StagingDatabase}</Database>
      <Frequency>0.00:01:00</Frequency>
      <CustomMessage>Surescripts v10 Staging is not running</CustomMessage>
      <Query>select count(1) from [SureScripts_v10_Staging].[dbo].[ToSureScriptMessagesQueue] where requesttime &lt; dateadd(minute,-1,getdate()) and responsetime is null</Query>
      <MinResult>-1</MinResult>
      <MaxResult>0</MaxResult>
    </parameters>
  </component>

In my constructor for my ScalarQueryWatcher I am always getting the same database connection being injected. If I remove the service= portion of the component definitions for the SQLConections then Windsor complains with:

Castle.MicroKernel.Handlers.HandlerException: Can't create component >'serviceBootstrapper' as it has dependencies to be satisfied.

'SurescriptsWatcher' is waiting for the following dependencies: - Service 'System.Data.IDbConnection' which was not registered. - Component 'Surescriptsv10Watcher' (via override) which was registered but is also waiting for dependencies.

'Surescriptsv10Watcher' is waiting for the following dependencies: - Service 'System.Data.IDbConnection' which was not registered. - Component 'Surescriptsv10StagingWatcher' (via override) which was registered but is also waiting for dependencies.

'Surescriptsv10StagingWatcher' is waiting for the following dependencies: - Service 'System.Data.IDbConnection' which was not registered.

What am I doing wrong here? From reading the documentation I thought that specifying the <Database>${SurescriptsDatabase}</Database> using the id of the component would give me that particular component.


UPDATE Meant to do this earlier, here you go for later posterity. The problem did not lie within the XML configuration, but within the source code:

Public Class ScalarQueryWatcher

Public Sub New(ByVal Query As String,
 ByVal Connection As IDbConnection,
 ByVal Frequency As TimeSpan,
 ByVal MinResult As Integer, ByVal MaxResult As Integer)
    _database = Connection
    'this should get the table we're querying from
    If String.IsNullOrEmpty(Query) Then Throw New ApplicationException("Query cannot be null")
    _queryName = Query.Substring(Query.IndexOf("FROM", StringComparison.CurrentCultureIgnoreCase) + 5)
    If _queryName.Contains(" ") Then _queryName = _queryName.Substring(0, _queryName.IndexOf(" "))
    _query = Query
    _frequency = Frequency
    _minResult = MinResult
    _maxResult = MaxResult
    _range = _maxResult - _minResult
End Sub
1

There are 1 answers

1
BlackICE On BEST ANSWER

Note that the constructor parameter name is Connection, not Database as I had referenced it in the xml configuration. That is the reason it "worked" when the service type was specified, it would grab whatever matched an IDbConnection. When I started using the correct constructor parameter name i got the database I specified by id.

Public Sub New(ByVal Query As String,
 ByVal Connection As IDbConnection,         'Note the name here is Connection
 ByVal Frequency As TimeSpan,
 ByVal MinResult As Integer, ByVal MaxResult As Integer)
    _database = Connection
    'this should get the table we're querying from
    If String.IsNullOrEmpty(Query) Then Throw New ApplicationException("Query cannot be null")
    _queryName = Query.Substring(Query.IndexOf("FROM", StringComparison.CurrentCultureIgnoreCase) + 5)
    If _queryName.Contains(" ") Then _queryName = _queryName.Substring(0, _queryName.IndexOf(" "))
    _query = Query
    _frequency = Frequency
    _minResult = MinResult
    _maxResult = MaxResult
    _range = _maxResult - _minResult
End Sub

  <component id="SurescriptsWatcher" 
             type="PatientFirst.Framework.Services.ScalarQueryWatcher, PatientFirst.Framework.Services">
    <parameters>
      <Database>${SurescriptsDatabase}</Database>  <!--note the parameter here is database, which does not match the constructor parameter -->
      <Frequency>0.00:01:00</Frequency>
      <CustomMessage>Surescripts v6 is not running</CustomMessage>
      <Query>select count(1) from [SureScripts_Production].[dbo].[ToSureScriptMessagesQueue] where requesttime &lt; dateadd(minute,-1,getdate()) and responsetime is null</Query>
      <MinResult>-1</MinResult>
      <MaxResult>0</MaxResult>
    </parameters>
  </component>