Factories defined with [Factory] for generic types do not work correctly with service names.
msironi opened this issue · 4 comments
The following code sample fails with a ServiceNotFoundException for both IFactory & IFactory{T}. If MyClass{T} is changed to MyClass the sample code works correctly (the factory is called to instantiate the service with "frobozz" as the service name).
[TestClass]
public class Test
{
[TestMethod]
public void TestMethod1()
{
ServiceContainer container = new ServiceContainer();
container.Initialize();
container.LoadFrom(typeof(MyClass<>).Assembly);
// Get ServiceNotFoundException here instead of a service instance.
var service = container.GetService<MyClass<string>>("frobozz");
Console.WriteLine("foo");
}
}
[Factory(typeof(MyClass<string>))]
public class MyFactory :
//IFactory<MyClass<string>>
IFactory
{
public object CreateInstance(IFactoryRequest request)
{
if (string.IsNullOrWhiteSpace(request.ServiceName))
throw new ArgumentNullException("ServiceName");
return new MyClass<string>();
}
//MyClass<string> IFactory<MyClass<string>>.CreateInstance(IFactoryRequest request)
//{
// return (MyClass<string>)CreateInstance(request);
//}
}
public class MyClass<T>
{ }
Have you tried:
[Factory(typeof(MyClass<string>), ServiceName = "frobozz")] on the custom IFactory<T> declaration?
That works but it's not the behavior I wanted. I wanted behavior similar to the sample provided at:
http://www.codeproject.com/KB/cs/LinFu_IOC.aspx
// Tell LinFu.IOC that the factory can create string types
[Factory(typeof(string))]
public class ConfigurationStringFactory : IFactory
{
public object CreateInstance(IFactoryRequest request)
{
// Use the name of the service as the
// key name in the config file
var keyName = request.ServiceName;
// Grab the key value
return ConfigurationManager.AppSettings[keyName];
}
}
// Get the "key1" configuration string.
// NOTE: Notice that the client doesn't even know where the config string comes from
var keyName = "key1";
var keyValue = container.GetService<string>(keyName);
There is of course a workaround (don't use the service name and make the string an argument instead). I'd prefer to use the service name if possible (and based my code on the linked example) but if that is not supported no biggie.
I tracked down the bug to FactoryStorage.cs and it turns out that whenever you ask for a named service and you have an unnamed default IFactory/IFactory instance ready to handle the request, it throws a ServiceNotFoundException because it looks for the factory with the given service name, but it doesn't fall back to the default factory if that factory cannot be found.
The bug has been fixed now, and you can verify it by taking a look at the "ShouldBeAbleToCreateClosedGenericTypeUsingACustomFactoryInstance" test case in FactoryTests.cs under the UnitTests project. I hope that helps. :)
No more reported issues for this item.