views:

298

answers:

1

Say I setup my app.config to specify a type that my current application knows nothing about. Then I use AppDomain.Load(byte[]) to load the assembly before instantiating an instance of my WindsorContainer.

Can Windsor resolve the type? Here's an example:

Castle config:

<castle>
 <components>
   <component id="test" service="Application.Services.ITestService, Application.Services" type="TestLibrary.TestService, TestLibrary"/>
 </components>
</castle>

Then in my code:

byte[] buffer = File.ReadAllBytes("TestLibrary.dll");
AppDomain.CurrentDomain.Load(buffer);

/* the assembly is now loaded and if I iterate AppDomain.GetAssemblies() is shows there */

WindsorContainer container = new WindsorContainer(new XmlInterpreter());/* here I get  "The type name TestLibrary.TestService, TestLibrary could not be located" */

ITestService resolvedService = container.Resolve<ITestService>("test");

Edit:

I've found that this does work:

Assembly testLibrary = Assembly.LoadFile("TestLibrary.dll");
AppDomain.CurrentDomain.Load(testLibrary.GetName());

WindsorContainer container = new WindsorContainer(new XmlInterpreter());
ITestService service = container.Resolve<ITestService>("test");
+1  A: 

If you load the assembly after registering Windsor components (as I assumed from your original question), it doesn't work since it can't know about those types until their assembly is loaded. You could use the AppDomain.CurrentDomain.AssemblyLoad event and register those types there. Here's a sample:

[Test]
public void AssemblyLoadRegisterFromXml() {
    var container = new WindsorContainer();
    AppDomain.CurrentDomain.AssemblyLoad += (sender, args) => {
        var filename = args.LoadedAssembly.FullName.Split(',')[0] + ".xml";
        container.Install(Configuration.FromXmlFile(filename));
    }; ;
    Assembly.Load("System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
    var ex = container.Resolve(Type.GetType("System.Transactions.TransactionException, System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"));
    Assert.AreEqual("hello world", ex.GetType().GetProperty("Message").GetValue(ex, null));
}

And have a System.Transactions.xml file with the components configuration:

<configuration>
  <components>
    <component id="txex" type="System.Transactions.TransactionException, System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <parameters>
        <message>hello world</message>
      </parameters>
    </component>
  </components>
</configuration>

Now that you state that you're loading the assembly through AppDomain.Current.Load(byte[]) before Windsor initialization, I can say that your problem is actually not with Windsor but with AppDomain.Current.Load(byte[]) semantics, see this for an explanation.

Mauricio Scheffer
You say "it can't know about those types until their assembly is loaded", but I AM loading the assembly first. I posted an example.
scottm
Also, my version of Windsor apparently doesn't expose an Install method
scottm
Get Windsor 2.0, that featured has been included over a year ago ( http://fisheye2.atlassian.com/changelog/castleproject/?cs=4874 ).If it doesn't work with the latest version please file a bug report
Mauricio Scheffer
I swear I downloaded the 2.0 version originally, but I guess I was wrong. In any occasion, I don't think I need the Install method anyway.
scottm
Your problem has actually nothing to do with Windsor. See AppDomain.CurrentDomain.Load behavior here: http://social.msdn.microsoft.com/Forums/en-US/clr/thread/390e7740-c209-49cc-b890-d4c880e82494
Mauricio Scheffer