I try to use Ninject to inject a XmlReader. The problem is that it is created by a factory method insted of a constructor. And I can't add a [Inject]
to code in the .NET Framework. Now I use following binding to create the XmlReader:
Bind<IXmlReader>()
.ToMethod(
x =>
XmlReader.Create(
(string) GetParameter(x, "inputUri"),
(XmlReaderSettings) GetParameter(x, "settings")))
.Named("definition");
private object GetParameter(IContext context, string name)
{
var parameters = (List<IParameter>) context.Parameters;
return (from p in parameters
where p.Name == name
select p.GetValue(context))
.FirstOrDefault();
}
And I use it as following:
var reader = _kernel.Get<IXmlReader>("definition",
new Parameter("inputUri", FilePath, false),
new Parameter("settings", settings, false)))
But this code is horrible. Can I rewrite it in any prettier smarter way?
You're not doing DI, you're doing Service Location.
I dont know your real context but I reckon I'd depend on a Func<string,string,IXmlReader>
and do the Bind as follows:-
Bind<Func<string,string,IXmlReader>>()
.ToMethod( (inputUri,settings) => XmlReader.Create( inputUri,settings))
.Named("definition");
Then you declare the injected item in your constructor args:
[Named("definition")]Func<string,string,IXmlReader> createReader
The fun bit is that There's a built in [Named]
above is my own makey upey attribute and you need to do the conditional aspect at bind time. Have a look at the dojo, it will show you how to do that bit.NamedAttribute
(and has been for ages, no idea what I was thinking).
If something like injecting a factory is useful in your case, the next thing to look at is Ninject.Extensions.Factory. It handles most of these sorts of factory requirements in a clean manner.