Wednesday, July 16, 2008

Castle Windsor RC3 Detests MSTest?: DeserializeElement cannot process element configSections

 

I'm exasperated getting Castle Windsor to work with MSTest.  For once, it's not the other way around :)  Here's the partial code tries to resolve a database provider using Windsor.  The App.config in my MSTest project is copied to a TestResults folder with a *.dll.config extension [I didn't know .Net started allowing .dll.config files.  Well may not be, but that's a topic for another post!). 

Here's my app.config [ThinkFarAhead.WordReporter.Data.UnitTest.dll.config]:

    1 <?xml version="1.0"?>
    2 <configuration>
    3   <configSections>
    4     <section name="castle"
    5         type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
    6 
    7   </configSections>
    8 
    9   <castle>
   10     <components>
   11       <component id="DbTypeSql"
   12             service="ThinkFarAhead.WordReporter.Data.IDbCreator"
   13             type="ThinkFarAhead.WordReporter.Data.SqlDbCreator, ThinkFarAhead.WordReporter.Data">
   14       </component>
   15       <component id="DbTypeOracle"
   16             service="ThinkFarAhead.WordReporter.Data.IDbCreator"
   17             type="ThinkFarAhead.WordReporter.Data.OracleDbCreator, ThinkFarAhead.WordReporter.Data">
   18       </component>
   19       <component id="DbTypeOledb"
   20             service="ThinkFarAhead.WordReporter.Data.IDbCreator"
   21             type="ThinkFarAhead.WordReporter.Data.OleDbDbCreator, ThinkFarAhead.WordReporter.Data">
   22       </component>
   23       <component id="DbTypeOdbc"
   24             service="ThinkFarAhead.WordReporter.Data.IDbCreator"
   25             type="ThinkFarAhead.WordReporter.Data.OdbcDbCreator, ThinkFarAhead.WordReporter.Data">
   26       </component>
   27     </components>
   28   </castle>
   29 </configuration>
Here's the code that tries to inject dependencies:

   37         private static string WindsorConfigFile;
   38         static DbCreatorFactory()
   39         {
   40             WindsorConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; //  set // "Windsor.config"; //string.Format(@"{0}\Windsor.Config", Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase));
   41         }
   42 
   43         //Removed statically typed enum [that cannot be extended at runtime]
   44         //Here at least other clients can pass anything
   45         public static IDbCreator GetDBCreator()
   46         {
   47             WindsorContainer container = new WindsorContainer(WindsorConfigFile);
   48             IDbCreator creator = container.Resolve<IDbCreator>(UserPreferences.Instance.LocalDataStoreChosen);
   49             return creator;
   50         }

Here's my MSTest code:

   69         [TestMethod]
   70         public void CheckObjectCreation()
   71         {
   72             string[] databaseTypes = new string[] { "DbTypeSql", "DbType.Oracle" }; //, "DbType.Oledb", "DbType.Odbc"};
   73             Type [] dbCreators = new Type [] { typeof(SqlDbCreator), typeof(OracleDbCreator)}; //, typeof(OracleDbCreator), typeof(OleDbDbCreator)
   74             for (int i = 0; i < databaseTypes.Length; i++)
   75             {
   76                 UserPreferences.Instance.LocalDataStoreChosen = databaseTypes[i];
   77                 if(!(DbCreatorFactory.GetDBCreator() == dbCreators[i]))
   78                 {
   79                     Assert.Fail(string.Format("Type {0} instantiated incorrectly for key {1}", dbCreators[i].ToString(), databaseTypes[i]));
   80                 }
   81             }
   82         }

It fails with:

CastleWindsor-1

 

Technorati Tags: ,

5 comments:

Roelof said...

When using the app configuration file you should initialize Windsor usin XmlInterpreter, like this:

container = new WindsorContainer(new XmlInterpreter());

Read the conig docs at http://www.castleproject.org/container/gettingstarted/part1/config.html for more background

Vyas Bharghava said...

Thanks! I'll try this and let you know [I'm sure it'd work :)]!

Vyas Bharghava said...

Well, I'm getting a new error now after I changed the line to:

WindsorContainer container = new WindsorContainer(new XmlInterpreter());

and putting my castle config into App.config (instead of separate file as I was trying. If I want to use a different file, I found I need to include it in App.config)

Now the error is:
System.Configuration.ConfigurationErrorsException: The type name ThinkFarAhead.WordReporter.Data.IDbCreator could not be located.

For VS.Net 2008 Unit Tests AppDomain.CurrentDomain.BaseDirectory is:
c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\ide

But Windsor dll and others [inclduing the one that requires to be loaded] are all in some other folder on D drive:
D:\<sourcefolder>\TestResults\Administrator_VYAS-QUAD 2008-07-17 20_43_39\Out

Would this cause a problem?

Roelof said...

You're missing the assemby name on the service="ThinkFarAhead.WordReporter.Data.IDbCreator". Changing it to service="ThinkFarAhead.WordReporter.Data.IDbCreator, ThinkFarAhead.WordReporter.Data" will solve the type load exception.

If you'd like to use a separate config read http://www.castleproject.org/container/documentation/trunk/usersguide/externalconfig.html. Also make sure you set the file property 'copy to output directory' in VS.NET to something else than 'do not copy'.

Vyas Bharghava said...

Great eye!!! Roelof, I can't believe how dumb I've been (didn't mean to sound I think I'm smart :))!!!

Thank you sssssssooooooo much...