2

I'm trying to inject a couple of classes in a controller, but I'm failing.

This is what I've done:

  1. Added Ninject.Web.WebApi.WebHost and WebActivatorEx NuGet packages
  2. Created the following class under App_Start:

NinjectWebCommon.cs

using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using Ninject.Web.Common.WebHost;
using MyProject;
using MyProject.Models;
using MyProject.Classes;
using System;
using System.Web;

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(NinjectWebCommon), "Stop")]

namespace MyProject
{
    public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(kernel);
            return kernel;
        }

        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<IMyContext>().ToSelf().InRequestScope();
            kernel.Bind<IErp>().ToSelf().InRequestScope();
        }
    }
}
  1. Created my classes:

MyContext.cs:

using MyProject.Models;
using System;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Threading.Tasks;

namespace MyProject.Models
{
    public interface IMyContext : IDisposable
    {
        DbSet<Operator> Operators { get; set; }
        Task<int> SaveChangesAsync();
    }

    public class MyContext : DbContext, IMyContext
    {
        public MyContext () : base("MyContext ") { }
        public DbSet<Operator> Operators { get; set; }
        public async override Task<int> SaveChangesAsync()
        {
            return await SaveChangesAsync(CancellationToken.None);
        }
    }
}

Erp.cs

public interface IErp
{
    Task ImportListAsync();
}

public class Erp : IErp
{
    private readonly IMyContext _context;
    public Erp(IMyContext context)
    {
        _context = context;
    }

    public async Task ImportListAsync()
    {
        // do something
    }
}
  1. Created a Controller

    using MyProject.Classes;
    using MyProject.Models;
    using System.Data.Entity;
    using System.Threading.Tasks;
    using System.Web.Mvc;
    
    namespace MyProject.Controllers
    {
        public class OperatorsController : Controller
        {
            private readonly IMyContext _context;
            private readonly IErp _erp;
    
            public OperatorsController(IMyContext context, Erp Ierp)
            {
                _context = context;
                _erp = erp;
            }
    
            // GET: Operators
            public async Task<ActionResult> Index()
            {
                return View(await _context.Operators.ToListAsync());
            }
    
            // GET: Operators/Import
            public async Task<ActionResult> Import()
            {
                await _erp.ImportListAsync();
                return View("Index", await _context.Operators.ToListAsync());
            }
        }
    }
    

But when I run the application I still get the infamous error about the missing of parameterless constructor. This says to me that DI is not working.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Mark
  • 4,338
  • 7
  • 58
  • 120
  • By the way I'm not able to fix the format of the last code snippet. – Mark Dec 09 '17 at 00:32
  • 2
    Why would you use the Web API package if you're using MVC? Why wouldn't you use the MVC package? – mason Dec 09 '17 at 00:37
  • I selected a Single Page Application when creating a new project and that's the template it created. – Mark Dec 09 '17 at 09:56
  • So what's your suggestion? Avoid to creating a SPA and restart from scratch using a MVC template? – Mark Dec 09 '17 at 09:56
  • No. I'm saying use the appropriate integration package for the framework you've chosen. If you're doing MVC, use the MVC package. If you're doing Web API, use the Web API package. If you're doing both, use them both. – mason Dec 09 '17 at 16:22

1 Answers1

4

I believe your registration calls in RegisterServices are wrong - you cannot bind an interface .ToSelf() - you need to bind the interface to the concrete class that implements it - something like this:

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IMyContext>().To<MyContext>().InRequestScope();
    kernel.Bind<IErp>().To<Erp>().InRequestScope();
}

With this, you tell the DI container to instantiate an MyContext class whenever in your code you're expecting an IMyContext dependency

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459