Creating an instance using Ninject with additional parameters in the constructor
The With.ConstructorArgument
existed in 1.0 for this purpose. In 2.0, the syntax has changed slightly:-
With.Parameters.ConstructorArgument with ninject 2.0
See Inject value into injected dependency for more details and examples of how to use the context, providers and arguments to pass stuff like this around more correctly.
EDIT: As Steven has elected to pretend my comment is irrelevant, I'd best make clear what I'm saying with some examples (for 2.0):
MyClass m = kernel.Get<MyClass>( new ConstructorArgument( "i", 2) );
which to my eyes is very clear and states exactly what's happening.
If you're in a position where you can determine the parameter in a more global way you can register a provider and do it like this:
class MyClassProvider : SimpleProvider<MyClass>
{
protected override MyClass CreateInstance( IContext context )
{
return new MyClass( context.Kernel.Get<IService>(), CalculateINow() );
}
}
And register it like this:
x => x.Bind<MyClass>().ToProvider( new MyClassProvider() )
NB the CalculateINow()
bit is where you'd put in your logic as in the first answer.
Or make it more complex like this:
class MyClassProviderCustom : SimpleProvider<MyClass>
{
readonly Func<int> _calculateINow;
public MyClassProviderCustom( Func<int> calculateINow )
{
_calculateINow = calculateINow;
}
protected override MyClass CreateInstance( IContext context )
{
return new MyClass( context.Kernel.Get<IService>(), _calculateINow() );
}
}
Which you'd register like so:
x => x.Bind<MyClass>().ToProvider( new MyClassProviderCustom( ( ) => new Random( ).Next( 9 ) ) )
UPDATE: Newer mechanisms which exhibit much improved patterns with less boilerplate than the above are embodied in the Ninject.Extensions.Factory
extension, see:
https://github.com/ninject/ninject.extensions.factory/wiki
As stated earlier, if you need to pass a different parameter each time and you have multiple levels in the dependency graph, you might need to do something like this.
A final consideration is that because you haven't specified a Using<Behavior>
, it's going to default to the default as specified/defaulted in the options for the kernel (TransientBehavior
in the sample) which might render fact that the factory calculates i
on the fly moot [e.g., if it the object was being cached]
Now, to clarify some other points in the comments that are being FUDed and glossed over. Some important things to consider about using DI, be it Ninject or whatever else is to:
Have as much as possible done by constructor injection so you dont need to use container specific attributes and tricks. There's a good blog post on that called Your IoC Container is Showing.
Minimise code going to the container and asking for stuff - otherwise your code is coupled to a) the specific container (which the CSL can minimise) b) the way in which your entire project is laid out. There are good blog posts on that showing that CSL isnt doing what you think it does. This general topic is referred to as Service Location vs Dependency Injection. UPDATE: See http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx for a detailed and complete rationale.
Minimise use of statics and singletons
Don't assume there is only one [global] container and that it's OK to just demand it whenever you need it like a nice global variable. The correct use of multiple modules and
Bind.ToProvider()
gives you a structure to manage this. That way each separate subsystem can work on its own and you wont have low-level components being tied to top-level components, etc.
If someone wants to fill in the links to the blogs I'm referring to, I'd appreciate that (they're all already linked from other posts on SO though, so all of this is just duplication UI've introduced with the aim of avoiding the confusion of a misleading answer.)
Now, if only Joel could come in and really set me straight on what's nice syntax and/or the right way to do this!
UPDATE: While this answer is clearly useful from the number of upvotes it's garnered, I'd like to make the following recommendations:
- The above feels as it's a bit dated and to be honest reflects a lot of incomplete thinking which almost feels embarassing since reading Dependency Injection in .net - Run and buy it now - it's not just about DI, the first half is a complete treatment of all the architecture concerns surrounding it from a man who has spent way too much time here hanging around the dependency injection tag.
- Go read Mark Seemann's top rated posts here on SO right now - you'll learn valuable techniques from every one
Add Constructor Arguments To Ninject Binding
The code in your question is broken. See:
public NinjectControllerFactory()
{
_ninjectKernal = new StandardKernel();
PSCCheckContext m = _ninjectKernal.Get<PSCCheckContext>(new IParameter[]
{ new ConstructorArgument("appNamekey", "Name of Staff Application"),
new ConstructorArgument("serverLocationNameKey", "Location of Application Server") });
AddBindings();
}
Specifically:
PSCCheckContext m = _ninjectKernal.Get<PSCCheckContext>(new IParameter[]
{ new ConstructorArgument("appNamekey", "Name of Staff Application"),
new ConstructorArgument("serverLocationNameKey", "Location of Application Server") });
What's this supposed to be doing? What it actually does is have ninject instanciate one PSCheckContext
instance and then it forget's about it. Unless the ctor of PSCCheckContext
has side effects on the system (which would not be a good programming practice), this code does not have any effect whatsoever (apart from consuming CPU time and memory) (=> notice that PSCCheckContext m
is a local variable, so it can't be reused later).
I guess what you meant to do was:
public NinjectControllerFactory()
{
_ninjectKernal = new StandardKernel();
_ninjectKernal.Bind<IPSCCheckContext>().To<PSCCheckContext>()
.WithConstructorArgument("appNamekey", "Name of Staff Application")
.WithConstructorArgument("serverLocationNameKey", "Location of Application Server");
AddBindings();
}
This binds IPSCCheckContext
with constructor arguments so that from now on it should be injectable into the controller.
Constructor with multiple arguments with Ninject
It's very easy. No matter how many constructor arguments, the binding stays the same:
Bind<IAuthorizationService>().To<MyAuthenticator>();
Let's say MyAuthenticator
had a constructor with one parameter of type IFoo
.
All you got to do is tell ninject how it can resolve/create an IFoo
. Again, very simple:
Bind<IFoo>().To<Foo>();
You don't need WithConstructorArgument
ever, except in case you want to override the default behavior of ninject. Let's say MyAuthenticator
has a parameter of type IFoo
plus another parameter string seed
which you want to configure specifically. All you'd need is:
Bind<IFoo>().To<Foo>();
Bind<IAuthorizationService>().To<MyAuthenticator>()
.WithConstructorArgument("seed", "initialSeedValue");
no need to specify the value of the IFoo
parameter!
Passing Parameters across Classes using Ninject
Ninject 3 provided a convenient function that allows me to pass the parameters across classes. By creating an interface like
public interface IViewPersonViewModelFactory()
{
IViewPersonViewModel CreateViewPersonViewModel([parameterType parameterName..]);
}
and adding the following to the Ninject module to be loaded:
public override void Load()
{
Bind<IMainControllingViewModelFactory>().ToFactory();
... ... //other bindings
}
We can then obtain an instance of the ViewPersonViewModel class (for e.g. in the MainViewModel class)
public class MainViewModel
{
private IViewPersonViewModel _viewModel;
public MainViewModel(IViewPersonViewModelFactory viewModelFactory)
{
_viewModel = viewModelFactory.CreateViewPersonViewModel(parameters..);
}
}
Note that no concrete factory has to be created.
The wiki can be found at: https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface
Ninject dynamically constructor parameters
Ninject can't resolve the dependencies iId
and sId
because they are not available to be bound until your API method is called, but by then it's too late in the binding chain. When you receive a post to the method, an instance of SyncProductController
is instantiated and then Ninject attempts to instantiate a SyncProductsHelper
, but it can't because it doesn't know where or how to find its dependencies at that point.
I would suggest one of two options:
Refactor your implementation to make
SyncProductsHelper
act oniId
andsId
in some other way that would allow you to have a parameterless constructor. Perhaps creating a new class representingiId
andsId
that it acts on as another parameter forChangeSomething
. DoesSyncProductsHelper
need to remember the state of these fields?Consider not using dependency injection at all for this particular class. From your code it looks like
SyncProductsHelper
is purely just working with primitives, so you could simply create a new instance from your Web API methods directly. You can still easily unit test this class because it doesn't have any external dependencies of its own.
NInject: how to pass parameters when GetT()?
You should be able to pass constructor arguments given that your Processor takes those dependencies as arguments in the constructor.
var foo = new Ninject.Parameters.ConstructorArgument("foo", new Foo());
var bar = new Ninject.Parameters.ConstructorArgument("bar", new Bar());
var processor = kernel.Get<IProcessor>(foo, bar);
public Processor (Foo foo, Bar bar){
this.foo = foo;
this.bar = bar;
}
Ninject : Constructor parameter
I'd use the WithConstructorArgument()
method like...
Bind<IRepository<Category>>().To<AzureTableRepository<Category>>()
.WithConstructorArgument("tableName", "categories");
The rest of the repository design is probably another question. IMHO It seems like a big no no to create a table or do any heavy lifting in a ctor.
How to pass parameters down the dependency chain using Ninject
Yannick's answer is a good, however, here's an alternative: create an IAccountService
that has the logic to find and return the AccountId. Then inject that service into your IPhotoService
.
Related Topics
Is Async Await Keyword Equivalent to a Continuewith Lambda
Inject Service into Action Filter
How to Get a List of All Routes in ASP.NET Core
Problem Parsing Currency Text to Decimal Type
What Is the Worst Gotcha in C# or .Net
No Connection String Named 'Myentities' Could Be Found in the Application Config File
404 Error After Adding Web API to an Existing MVC Web Application
Getting Day Suffix When Using Datetime.Tostring()
Httpcontext.Current.Session Is Null When Routing Requests
Error in Process.Start() -- the System Cannot Find the File Specified
Windows Shell Extension with C#
Linq to SQL Using Group by and Count(Distinct)
Parsing CSV Using Oledb Using C#
How to Set the Default Xml Namespace for an Xdocument
C# "Internal" Access Modifier When Doing Unit Testing
Why Is Inserting Entities in Ef 4.1 So Slow Compared to Objectcontext