Use factory method in Ninject that I can't add attribute to - ninject

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 [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.There's a built in 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.

Related

meta program fluent validation

I have used fluent validation for hard code validations like this:
RuleFor(customer => customer.CreditLimit).GreaterThan(customer => customer.MinimumCreditLimit);
I guess it would not be a problem to replace MinimumCreditLimit by some (meta) database driven value in the code. Did someone ever attempt this and what would be the best practises in this context (apart from the fact that MinimumCreditLimit could stem from some strategy design pattern). Could one potentially use expression trees against fluent validation to make it even more meta program-ish?
Well, the easiest way would be to add a ctor to your Validation class.
public class EntityValidator : AbstractValidator<Entity> {
public EntityValidator(int minimumCreditLimit) {
Rulefor(customer => customer.CreditLimit).GreaterThan(minimumCreditLimit);
}
}
now you could use it like that (if you don't use the "attributes" way).
var minimumCreditLimit = <GetTheLimitFromDbWithAnyMethod>();
var validator = new EntityValidator(minimumCreditLimit);
<yourEntityInstance>.ValidateAndThrow(validator);
Another (similar) way would be to pass some way to get data from db to your validator (in ctor for example), and create a custom validator / extension method to use this.

Ninject Factory - "new" object being passed in instead of one called in factory method

I am using the Ninject Factory Extensions so that I can create objects that have services injected plus custom values
so:
public interface IGameOperationsFactory
{
ISpinEvaluator Create(GameArtifact game);
IReelSpinner CreateSpinner(GameArtifact game);
}
Then in module:
Bind<IGameOperationsFactory>().ToFactory().InSingletonScope();
Bind<ISpinEvaluator>().To<DefaultSpinEvaluatorImpl>();
Bind<IReelSpinner>().To<DefaultReelSpinnerImpl>();
The actual factory gets injected in a classes' constructor and is then used like:
_spinner = _factory.CreateSpinner(_artifact);
_spinEval = _factory.Create(_artifact);
Where _artifact is of type GameArtifact
Then in each of the implementation's constructors services plus the passed in objects are injected. The GameArtifact is successfully passed in the first constructor, and in the second one a "new" GameArtifact is passed in, i.e. not a null one but one with just default values as if the framework just called
new GameArtifact()
instead of passing in the already existing one!
The Constructor for the two objects is very similar, but the one that doesn't work looks like:
[Inject]
public DefaultReelSpinnerImpl(GameArtifact ga, IGameOperationsFactory factory, IRandomService serv)
{
_rand = serv;
_ra = ga.Reels;
_mainReels = factory.Create(_ra);
_winLine = ga.Config.WinLine;
}
Where the factory and serv are injected by Ninject and ga is SUPPOSED to be passed in via the factory.
Anyone have a clue why a new "fresh" object is passed in rather than the one I passed in??
I have rewritten you sample a little bit, and it seems to work fine. Could you provide more detailed code sample?
My implementation
I have changed verb Create to Get to match Ninject conventions
public interface IGameOperationsFactory
{
ISpinEvaluator GetSpinEvaluator(GameArtifact gameArtifact);
IReelSpinner GetReelSpinner(GameArtifact gameArtifact);
}
Ninject configuration
I have added named bindings to configure factory
Bind<ISpinEvaluator>()
.To<DefaultSpinEvaluatorImpl>()
.Named("SpinEvaluator");
Bind<IReelSpinner>()
.To<DefaultReelSpinnerImpl>()
.Named("ReelSpinner");
Bind<IGameOperationsFactory>()
.ToFactory();
ps: full sample with tests

Is there anyway to get the class name that an instance is injected into (using ninject)?

I'm injecting my dependencies into my classes fine, but I'm wondering if it's possible to get the class name I'm injecting into?
For example:
Bind<ISomething>.ToMethod(c => new Something([GIVE INJECTING *TO* CLASS NAME]));
So, if I had:
public class Blah{
public Blah(ISomething something) { /**/ }
}
When injecting Ninject would in effect call:
new Blah(new Something("Blah"));
Can this be done?
Yes, it can be done. You use the IContext you're given in the ToMethod method to get the name of the type you're being injected into like this:
Bind<ISomething>().ToMethod(c => new Something(GetParentTypeName(c)));
Which uses this little helper method (which could also be turned into a nice extension method):
private string GetParentTypeName(IContext context)
{
return context.Request.ParentRequest.ParentRequest.Target.Member.DeclaringType.Name;
}
It has probably changed in later versions of Ninject. As for version v3.2.0 the accepted solution didn't work for me.
The following does though:
Bind<ISomething>().ToMethod((ctx)
=> new Something(ctx.Request.Target?.Member?.DeclaringType?.Name ?? ""));

Using WithConstructorArgument and creating bound type

I have a binding that looks like this:
kernel.Bind<IRepository<Holiday>>().To<RepositoryBase<Holiday>>();
The problem is that RepositoryBase takes a contructor paramter of UnitOfWork called context. This is not, in and of itself a problem. Ninject should resolve it. Except for the fact that I have two UnitOfWork implementations, both bound using an attribute discriminator.
kernel.Bind<IUnitOfWork>().To<MS_DevEntities>().WhenTargetHas<MsDataAttribute>()
.InRequestScope();
How can specify that when an IRepository is created, it should be created with MS_DevEntities?
Certainly, i could do something like this:
kernel.Bind<IRepository<Holiday>>().To<RepositoryBase<Holiday>>()
.WithConstructorArgument("context", new MS_DevEntities());
However, I would prefer to have Ninject create the instance, particularly because i'm using the .InRequestScope() lifecycle.
Any suggestions?
EDIT:
Previously, I was using a class that looked like this:
public class HolidayRepository : RepositoryBase<Holiday>, IHolidayRepository
{
public HolidayRepository([MsData]IUnitOfWork context) : base(context){}
}
However, I now find myself with several dozen of these and they don't do much but add extra work when I need to create a new repository. I'd like to just map these directly in the bindings.
EDIT2:
I suppose I could do something like this, but it seems kind of hackish. Is there a better way?
kernel.Bind<MS_DevEntities>().ToSelf().InRequestScope();
kernel.Bind<IRepository<Holiday>>().To<RepositoryBase<Holiday>>()
.WithConstructorArgument("context",
(context) => context.Kernel.Get<MS_DevEntities>());
E.g. Put the attribute to the entity and use something like this:
kernel.Bind(typeof(IRepository<>)).To(typeof(RepositoryBase<>));
kernel.Bind<IUnitOfWork>().To<MS_DevEntities>()
.When(r => EntityHas<MsData>(r));
kernel.Bind<IUnitOfWork>().To<TheOtherOne_DevEntities>()
.When(r => EntityHas<TheOtherData>(r));
bool EntityHas<TAttribute>(IRequest r)
{
return r.Target.Member.ReflectedType.IsGenericType &&
r.Target.Member.ReflectedType.GetGenericArguments()[0]
.GetCustomAttributes(typeof(TAttribute), false).Any();
}
You can do everything using this When condition and take the entity type from r.Target.Member.ReflectedType.GetGenericArguments()[0] to lookup somewhere which UoW that you have to use for this entity type.
2nd approch using config
kernel.Bind<IUnitOfWork>().To<TheOtherOne_DevEntities>()
.When(r => EntityNeedsUoW(r, 1));
bool EntityNeedsUoW(IRequest r, int id)
{
return UoWConfig.GetDbIdForEntity(
r.Target.Member.ReflectedType.GetGenericArguments()[0]) == id;
}

Late binding with Ninject

I'm working on a framework extension which handles dynamic injection using Ninject as the IoC container, but I'm having some trouble trying to work out how to achieve this.
The expectation of my framework is that you'll pass in the IModule(s) so it can easily be used in MVC, WebForms, etc. So I have the class structured like this:
public class NinjectFactory : IFactory, IDisposable {
readonly IKernel kernel;
public NinjectFactory(IModule[] modules) {
kernel = new StandardKernel(modules);
}
}
This is fine, I can create an instance in a Unit Test and pass in a basic implementation of IModule (using the build in InlineModule which seems to be recommended for testing).
The problem is that it's not until runtime that I know the type(s) I need to inject, and they are requested through the framework I'm extending, in a method like this:
public IInterface Create(Type neededType) {
}
And here's where I'm stumped, I'm not sure the best way to check->create (if required)->return, I have this so far:
public IInterface Create(Type neededType) {
if(!kernel.Components.Has(neededType)) {
kernel.Components.Connect(neededType, new StandardBindingFactory());
}
}
This adds it to the components collection, but I can't work out if it's created an instance or how I create an instance and pass in arguments for the .ctor.
Am I going about this the right way, or is Ninject not even meant to be be used that way?
Unless you want to alter or extend the internals of Ninject, you don't need to add anything to the Components collection on the kernel. To determine if a binding is available for a type, you can do something like this:
Type neededType = ...;
IKernel kernel = ...;
var registry = kernel.Components.Get<IBindingRegistry>();
if (registry.Has(neededType)) {
// Ninject can activate the type
}
Very very late answer but Microsoft.Practices.Unity allows Late Binding via App.Config
Just in case someone comes across this question