Monday, 12 July 2010

Just can't plug this in, baby!

I've just lost about half a day fighting with a stupid StructureMap exception:
StructureMap.Exceptions.StructureMapConfigurationException: StructureMap configuration failures:
Error: 104
Source: Registry: StructureMap.ConfigurationExpression,StructureMap
Type Instance 'bf0f9bf6-304d-4d7b-9cd4-59437e94eb10' (Smart Instance for System.Data.SqlClient.SqlClientFactory) cannot be plugged into type System.Data.Common.DbProviderFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-----------------------------------------------------------------------------------------------------

at StructureMap.Diagnostics.GraphLog.AssertFailures()
at StructureMap.Container.Configure(Action`1 configure)
at StructureMap.ObjectFactory.Configure(Action`1 configure)
My actual code was this:
ObjectFactory.Configure(expr =>
{
expr.For<DbProviderFactory>().Use<SqlClientFactory>();
});


What do you mean by "cannot be plugged in", and why Google can't help me here???

So, a couple of hours later (and with a big help from CThru and Reflector), and I find the StructureMap.Graph.TypeRules.CanBeCast method, which is not just about casting, but says no when, among other things, the concrete type (SqlClientFactory in our case) has no default constructor.

Ok, I can understand. StructureMap doesn't know how to create a concrete instance. How about this:
expr.ForRequestedType<DbProviderFactory>().Use(SqlClientFactory.Instance);
Still no luck:
StructureMap.Exceptions.StructureMapConfigurationException: StructureMap configuration failures:
Error: 104
Source: Registry: StructureMap.ConfigurationExpression,StructureMap
Type Instance '42b890e6-54dc-457e-897a-3e8becc7d0fb' (Object: System.Data.SqlClient.SqlClientFactory) cannot be plugged into type System.Data.Common.DbProviderFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
This is more weird, but a look into the code tells me that we still require the target type to have a default constructor (cause we call the same method). Must be a bug in StructureMap. Too bad, since that would be the most clear and logical solution.

Finally this one worked for me:
expr.ForRequestedType<DbProviderFactory>() .AsSingletons(). TheDefault.Is.ConstructedBy (ctx => SqlClientFactory.Instance);

Have fun!