Vova  Leskiv
Vova Leskiv

Reputation: 31

Error with dependency injections

I trying create generic repository for ms sql db. Earlier i worked with something like this but with mongo db. I can compile project. but when i trying sent request i see error: "An error occurred when trying to create a controller of type 'EmployeeController'. Make sure that the controller has a parameterless public constructor." can anybody help me?

namespace TestTask.Util
{public class NinjectDependencyResolver
{
    private IKernel kernel;

    public NinjectDependencyResolver(IKernel kernelParam)
    {
        kernel = kernelParam;
        AddBindings();
    }

    public object GetService(Type serviceType)
    {
        return kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return kernel.GetAll(serviceType);
    }

    private void AddBindings()
    {
        // repository
        kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
    }
}

controller

namespace TestTask.Controllers
{
[RoutePrefix("api/v1")]
public class EmployeeController : ApiController
{
    private readonly IEmployeeRepository _employeeRepository;

    public EmployeeController(IEmployeeRepository employeeRepository) : base()
    {
        _employeeRepository = employeeRepository;
    }
[HttpGet]
    [Route("getItems")]
    public IHttpActionResult GetItems(int take = 8, int skip = 0)
    {
        if(take<1|| skip < 0)
        {
            ModelState.AddModelError("Error", "Invalid take or skip params.");
            return BadRequest(ModelState);
        }
        var result = _employeeRepository.Find(x => x.Id >= 0, x=>x.Id, take, skip);
        return Ok(result);
    }

     [HttpGet]
    [Route("pageCount")]
    public IHttpActionResult PageCount(int itemsInPage)
    {
        var TotalCount = _employeeRepository.Count(x => x.Id >= 0);
        var result = Math.Ceiling((double)TotalCount / (double)itemsInPage);
        return Ok(result);
    }
    }
  }

generic repository

   using System;
   using System.Collections.Generic;
   using System.Data.Entity;
   using System.Linq;
   using System.Linq.Expressions;
   using System.Threading.Tasks;
   using System.Web;

   namespace TestTask.Context
   {
   public abstract class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    private DefaultConnection context = new DefaultConnection();

    public virtual List<TEntity> Find(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, object>> order, int take =50, int skip=0) //where TEntity : class
    {           
        return context.Set<TEntity>().Where(predicate).OrderBy(order).Skip(skip).Take(take).ToList();
    }

    public virtual int Count(Expression<Func<TEntity, bool>> predicate)
    {
        return context.Set<TEntity>().Where(predicate).Count();
    }
}

}

Upvotes: 0

Views: 127

Answers (2)

Jason Watmore
Jason Watmore

Reputation: 4701

I had to do this a while back and remember it not being as straight forward with Web API as it is with MVC.

I posted details and a demo project as part of a unit of work example here, and github project here.

Below are the pieces for configuring dependency injection with Ninject.

UnitOfWorkExample.WebApi/Controllers/ProductsController.cs

namespace UnitOfWorkExample.WebApi.Controllers
{
    [RoutePrefix("products")]
    public class ProductsController : ApiController
    {
        private IProductService _productService;

        public ProductsController(IProductService productService)
        {
            _productService = productService;
        }

        [Route]
        public IHttpActionResult GetProducts()
        {
            // ensure there are products for the example
            if (!_productService.GetAll().Any())
            {
                _productService.Create(new Product { Name = "Product 1" });
                _productService.Create(new Product { Name = "Product 2" });
                _productService.Create(new Product { Name = "Product 3" });
            }

            return Ok(_productService.GetAll());
        }
    }
}

UnitOfWorkExample.WebApi/App_Start/NinjectWebCommon.cs

namespace UnitOfWorkExample.WebApi.App_Start
{
    using System;
    using System.Web;

    using Microsoft.Web.Infrastructure.DynamicModuleHelper;

    using Ninject;
    using Ninject.Web.Common;
    using Ninject.Extensions.Conventions;
    using System.Web.Http;
    using UnitOfWorkExample.Domain.Helpers;
    using UnitOfWorkExample.Data.Helpers;

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

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            RegisterServices(kernel);

            // Install our Ninject-based IDependencyResolver into the Web API config
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

            return kernel;
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            // unit of work per request
            kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope(); 

            // default binding for everything except unit of work
            kernel.Bind(x => x.FromAssembliesMatching("*").SelectAllClasses().Excluding<UnitOfWork>().BindDefaultInterface());
        }
    }
}

UnitOfWorkExample.WebApi/App_Start/NinjectDependencyResolver.cs

namespace UnitOfWorkExample.WebApi.App_Start
{
    public class NinjectScope : IDependencyScope
    {
        protected IResolutionRoot resolutionRoot;

        public NinjectScope(IResolutionRoot kernel)
        {
            resolutionRoot = kernel;
        }

        public object GetService(Type serviceType)
        {
            IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
            return resolutionRoot.Resolve(request).SingleOrDefault();
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
            return resolutionRoot.Resolve(request).ToList();
        }

        public void Dispose()
        {
            IDisposable disposable = (IDisposable)resolutionRoot;
            if (disposable != null) disposable.Dispose();
            resolutionRoot = null;
        }
    }

    public class NinjectResolver : NinjectScope, IDependencyResolver
    {
        private IKernel _kernel;
        public NinjectResolver(IKernel kernel)
            : base(kernel)
        {
            _kernel = kernel;
        }
        public IDependencyScope BeginScope()
        {
            return new NinjectScope(_kernel.BeginBlock());
        }
    }
}

Upvotes: 1

John Wu
John Wu

Reputation: 52240

ASP.NET does not inject anything into controllers by default. Instead, it looks for a matching controller and just uses new. So it needs a controller that has a default constructor with no parameters-- unless you do something special to add DI.

To add dependency injection to your controllers, you need to register a custom controller factory. The factory should use Ninject to instantiate the controller, which will automatically populate its constructor arguments with the appropriate dependencies. Here is a bare bones example (you will need to modify it to allow other controller types, as well as implement the rest of the interface):

public class CustomControllerFactory : IControllerFactory
{
    public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        return _kernel.Get<EmployeeController>();
    }
} 

You can register it in startup with code like this:

    protected void Application_Start()
    {
        IControllerFactory factory = new CustomControllerFactory();
        ControllerBuilder.Current.SetControllerFactory(factory);
    }

More info can be found here. The blogger shows you exactly the error that you are seeing and then fixes it.

Upvotes: 0

Related Questions