【问题标题】:Error with dependency injections依赖注入错误
【发布时间】:2017-10-04 00:47:05
【问题描述】:

我尝试为 ms sql db 创建通用存储库。早些时候我使用过类似的东西,但使用的是 mongo db。我可以编译项目。但是当我尝试发送请求时,我看到错误:“尝试创建'EmployeeController'类型的控制器时发生错误。确保控制器具有无参数的公共构造函数。”有人可以帮帮我吗?

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>();
    }
}

控制器

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);
    }
    }
  }

通用存储库

   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();
    }
}

}

【问题讨论】:

  • 正如错误所说,转到Employee Controller 并确保有public EmployeeController() : base() { }
  • @VovaLeskiv 框架在创建控制器时遇到问题。最有可能与解决依赖关系有关。从设置来看,EmployeeRepository 在初始化时可能缺少依赖项或其他问题,但您没有显示该类
  • 当我尝试添加没有参数的空构造函数时,调试器转到方法但不能使用 _employeeRepository 并显示 argumentNullException
  • @VovaLeskiv 您的依赖解析器也没有从正确的接口继承。您需要在minimal reproducible example 中提供模式详细信息
  • Nkosi,EmployeeRepository 为空,从通用存储库继承两个方法

标签: c# asp.net asp.net-web-api dependency-injection


【解决方案1】:

前段时间我不得不这样做,并记住它不像使用 MVC 那样直接使用 Web API。

我在unit of work example heregithub project here 中发布了详细信息和演示项目。

以下是使用 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());
        }
    }
}

【讨论】:

  • 不客气@VovaLeskiv,如果它对你有用,你能把它标记为答案吗?
【解决方案2】:

默认情况下,ASP.NET 不会向控制器注入任何内容。相反,它会寻找匹配的控制器并只使用new。所以它需要一个控制器,它有一个没有参数的默认构造函数——除非你做一些特殊的事情来添加 DI。

要将依赖注入添加到您的控制器,您需要注册一个自定义控制器工厂。工厂应该使用 Ninject 来实例化控制器,这将自动使用适当的依赖项填充其构造函数参数。这是一个简单的示例(您需要对其进行修改以允许其他控制器类型,以及实现接口的其余部分):

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

您可以在启动时使用如下代码注册它:

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

更多信息可以在here找到。博主准确地向您显示您看到的错误,然后修复它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-31
    • 2022-01-13
    • 2016-06-05
    • 2017-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多