-2

I have a viewmodel which extends a base class called BaseModel which in turn has a property of type DbContext.

How do I get ninject to inject the DbContext into the base class when calling the drived class?

coolblue2000
  • 3,796
  • 10
  • 41
  • 62

2 Answers2

2

The most reliable way is to make it a required constructor parameter:

public abstract class BaseModel
{
    private DbContext dbContext;

    protected BaseModel(DbContext dbContext) { this.dbContext = dbContext; }

    protected DbContext DbContext { get { return this.dbContext; } }
}

Then in your view models, simply pass the DbContext into the base class:

public CustomerViewModel : BaseModel
{
    public CustomerViewModel(DbContext dbContext)
        : base(dbContext) { }
}

It sounds like you don't quite understand how to use Ninject properly, for the example I have given, all you need to do is register 1 binding

kernel.Bind<DbContext>().To<MyDbContext>(); // Or whatever your DbContext is called.

Then you can resolve the view model like this:

var viewModel = kernel.Resolve<CustomerViewModel>();

You would only need to register a binding for CustomerViewModel if you needed to resolve that as a dependency for another class.

Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60
  • This would require me to add a binding for every viewmodel though which is what I am trying to get away from. I was hoping to have a single binding for the base class which would be used each time a derived class is instantiated. – coolblue2000 Aug 17 '15 at 21:22
  • No, all you need to do is add a binding for `DbContext` - it sounds like you have a miss understanding of how dependency injection works. – Trevor Pilley Aug 18 '15 at 07:13
  • @TrevorPilley this doesn't work in ninject 3.2.0, it complains about it being a circular dependency – sm_ Jan 16 '16 at 10:03
0

Make sure the base class' property is

  • public and has a public setter:
  • is annotated with the [Ninject.Inject] attribute

For example:

abstract class AbstractFoo
{
    [Ninject.Inject]
    public DbContext DbContext { get; set; }
}

Also see the Ninject Wiki on Property Injection

Required Binding(s)

(For future readers: This is not really in regard to the original question but needs answering because the poster was unaware of when bindings need to be created.)

Also, you will need a binding per type you want to be injected into some other type (or resolved directly from the kernel).

Given the following:

public class DerivedFoo : AbstractFoo
{
}

and some class Service where it should be injected into:

public class Service
{
     public Service(DerivedFoo foo)
     { ... }
}

requires a binding like:

Bind<DerivedFoo>().ToSelf();

Hint: well actually in this exact case the binding is not necessary, since with ninject's default configuration, if the type to resolve - in this case the constructor parameter DerivedFoo foo is a class with accessible constructor (abstract class => would not be accessible!), then ninject behaves as if you would have created the above binding. You can disable this behavior so that ninject only resolves types you've actually created a binding for.

Resolving an Abstract Type

If the service would look slightly different, let's say:

public class Service
{
     public Service(AbstractFoo foo)
     { ... }
}

you would need a binding like

Bind<AbstractFoo>().To<DerivedFoo>();

Resolving an Interface

Also in the following case where an interface is injected instead of a class, you would need a binding:

public class Service
{
     public Service(IFoo foo)
     { ... }
}

Bind<IFoo>().To<DerivedFoo>();

Reducing the amount of "Binding Work" you have to do

In some cases it makes sense to use Ninject.Extensions.Conventions in order to reduce the amount of Bind... code you need to write. Note however, that conventions should be specific and easy to remember, and they should not overlap (overlap = multiple conventions apply to the same type). Also look at this SO question for some more information regarding convention bindings.

Community
  • 1
  • 1
BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • 1
    That will only work if you add the `[Ninject.Inject]` attribute on it - from the link you specified "For a property to be injected it must be annotated with [Inject]" – Trevor Pilley Aug 17 '15 at 21:14
  • it is public and does have a public setter. However I am new to Ninject and non of my bindings are working. I can get the binding to work if I bind directly to the derived class but not the base class. – coolblue2000 Aug 17 '15 at 21:15
  • @coolblue2000 you don't need to have a binding for an `abstract` base class. You always need the binding for the concrete (derived) type. Well actually you need the binding for the type you're injection. For example if there's some other class `Bar` which takes `AbstractFoo` as ctor parameter, then you need a binding like `Bind().To();`. The `To` part must never be an `abstract` type. – BatteryBackupUnit Aug 18 '15 at 05:57
  • So there is no way around having to bind to each view model meaning there could be hundreds of bindings? – coolblue2000 Aug 18 '15 at 07:31
  • @coolblue2000 exactly. You can use [Ninject.Extensions.Conventions](https://github.com/ninject/ninject.extensions.conventions) so you don't have to specifically write a binding for every single type, but the kernel will still need to have a binding for each type which should be resolvable (=> injectable). Small correction, if you're resolving types which can be constructed directly (non abstract class with accessible constructor) technically you don't need a binding because ninject will do the same as if you've done `Bind().ToSelf().InTransientScope()` – BatteryBackupUnit Aug 18 '15 at 13:41
  • @TrevorPilley thanks. I actually wanted to write exactly that but somewhere during the writing process i completely forgot about it (I usually write an answer while waiting for a build to complete.. and so i sometimes pause in between which occasionally leads to me forgetting to include important things...). I've updated the post accordingly. – BatteryBackupUnit Aug 18 '15 at 13:53