MVC 4 Web Api控制器没有默认构造函数?

时间:2013-07-04 05:00:39

标签: c# asp.net-mvc-4 asp.net-web-api inversion-of-control ninject

这是跟踪:

<Error>
   <Message>An error has occurred.</Message>

   <ExceptionMessage>
      Type 'ProjectName.Web.Api.Controllers.ContinentsController' does not have a default constructor
   </ExceptionMessage>

   <ExceptionType>System.ArgumentException</ExceptionType>

   <StackTrace>
      at System.Linq.Expressions.Expression.New(Type type)

      at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)

      at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)

      at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
   </StackTrace>
</Error>

我觉得这很奇怪,因为public class UsersController : ApiController { ... }工作正常。我比较了2个控制器,所有的设置和结构都是相似的。

我正在使用Ninject,我的系统设置类似于Jamie Kurtz Asp.Net Mvc 4 and the Web Api: Building a REST Service from Start to Finish

从堆栈跟踪中,是否有人能够发现问题以及如何解决问题?谢谢!

按要求。

ContinentsController

[LoggingNHibernateSession]
public class ContinentsController : ApiController
{
    private readonly ISession _session;
    private readonly IContinentMapper _continentMapper;
    private readonly IHttpContinentFetcher _httpContinentFetcher;
    private readonly IDateTime _dateTime;

    public ContinentsController(ISession session, IContinentMapper continentMapper, IHttpContinentFetcher continentFetcher, IDateTime dateTime)
    {
        _session = session;
        _continentMapper = continentMapper;
        _httpContinentFetcher = continentFetcher;
        _dateTime = dateTime;
    }

    public IEnumerable<Continent> Get()
    {
        var continents = _session
            .Query<Data.Model.Continent>()
            .Select(_continentMapper.CreateContinent)
            .ToList();

        return continents;
    }

    public Continent Get(long id)
    {
        var modelContinent = _httpContinentFetcher.GetContinent(id);
        var continent = _continentMapper.CreateContinent(modelContinent);

            return continent;
        }
  }

UsersController :工作得很好。

    public class UsersController : ApiController
    {
        private readonly ISession _session;
        private readonly IUserManager _userManager;
        private readonly IUserMapper _userMapper;
        private readonly IHttpUserFetcher _userFetcher;

        public UsersController(
            IUserManager userManager,
            IUserMapper userMapper,
            IHttpUserFetcher userFetcher,
            ISession session)
        {
            _userManager = userManager;
            _userMapper = userMapper;
            _userFetcher = userFetcher;
            _session = session;
        }

        [Queryable]
        public IQueryable<Data.Model.User> Get()
        {
            return _session.Query<Data.Model.User>();
        }

        [LoggingNHibernateSession]
        public User Get(Guid id)
        {
            var user = _userFetcher.GetUser(id);
            return _userMapper.CreateUser(user);
        }
    }

我正在使用NinjectWebCommon.cs并且在其中,我有这个和其他一些默认方法。:

        private static void RegisterServices(IKernel kernel)
        {
            var containerConfigurator = new NinjectConfigurator();
            containerConfigurator.Configure(kernel);

            GlobalConfiguration.Configuration.MessageHandlers.Add(kernel.Get<BasicAuthenticationMessageHandler>());
        }

然后我有NinjectConfigurator.cs

public class NinjectConfigurator
{
    ......
    private void AddBindings(IKernel container)
        {
            .....
            container.Bind<IDateTime>().To<DateTimeAdapter>();
            container.Bind<IDatabaseValueParser>().To<DatabaseValueParser>();

            //HttpFetchers
            container.Bind<IHttpUserFetcher>().To<HttpUserFetcher>();
            container.Bind<IHttpContinentFetcher>().To<HttpContinentFetcher>();                                

            //TypeMappers
            container.Bind<IUserManager>().To<UserManager>();
            container.Bind<IMembershipInfoProvider>().To<MembershipAdapter>();
            container.Bind<IUserMapper>().To<UserMapper>();
            container.Bind<IContinentMapper>().To<ContinentMapper>();    
            .........
        }
     .......
}

NinjectWebCommon.csNinjectConfigurator.cs都位于App_Start文件夹中。

container.Bind<ISession>().ToMethod(CreateSession);NHibernate。它位于NinjectConfigurator.csprivate void ConfigureNHibernate(IKernel container) { ... }

之内

9 个答案:

答案 0 :(得分:16)

如果未在应用程序中设置依赖项解析程序,则此错误是已知错误。 Controller Factory找不到无参数构造函数来创建控制器并执行action方法(或动词方法?)。因此,您必须创建依赖项解析程序类并将其设置为Web应用程序的初始化。它将解决控制器的依赖关系。

使用ninject,你可以尝试这样的事情:

using Ninject; 
using Ninject.Syntax; 
using System; 
using System.Collections.Generic; 
using System.Diagnostics.Contracts; 
using System.Web.Http.Dependencies; 

namespace MyApplication.App_Start 
{     
    public class NinjectDependencyScope : IDependencyScope     
    {         
        private IResolutionRoot resolver;         

        internal NinjectDependencyScope(IResolutionRoot resolver)         
        {             
            Contract.Assert(resolver != null);             
            this.resolver = resolver;         
        }         

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

        public object GetService(Type serviceType)         
        {             
            if (resolver == null)                 
                throw new ObjectDisposedException("this", "This scope has already been disposed");             

            return resolver.TryGet(serviceType);         
        }   

        public IEnumerable GetServices(Type serviceType)         
        {             
            if (resolver == null)                 
                throw new ObjectDisposedException("this", "This scope has already been disposed");             

            return resolver.GetAll(serviceType);         
        }     
    }     

    public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver     
    {         
        private IKernel kernel;         
        public NinjectDependencyResolver(IKernel kernel)             
            : base(kernel)         
        {             
            this.kernel = kernel;         
        }         

        public IDependencyScope BeginScope()         
        {             
            return new NinjectDependencyScope(kernel.BeginBlock());         
        }     
    } 
}

NinjectDependencyResolver类将Ninject StandardKernel对象作为构造函数参数,并且只要对依赖项作用域进行流水线操作,就会使用此引用。 为了使这一切正常,NinjectDependencyResolver类被分配给应用程序的全局配置:

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

    // register all your dependencies on the kernel container
    RegisterServices(kernel);

    // register the dependency resolver passing the kernel container
    GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

    return kernel;
}

在Application_Start事件结束时的Global.asax.cs文件中,调用此CreateKernel方法。

答案 1 :(得分:16)

您需要告诉Ninject如何正确解析Web API依赖项。

您可以使用Felipe Oriani的答案,但如果您愿意,可以使用名为WebApiContrib.IoC.Ninject的NuGet软件包来为您执行此操作。

  1. 在Visual Studio中转到:工具&gt; NuGet包管理器&gt;管理 NuGet解决方案包

  2. 安装 WebApiContrib.IoC.Ninject

  3. 编辑: NinjectWebCommon.cs 并更新 CreateKernel()方法以包含: GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);

    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
    
        try
        {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
    
            RegisterServices(kernel);
    
            //Note: Add the line below:
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
    
            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }
    

答案 2 :(得分:2)

我也遇到了这个相同的错误,但是使用Ninject来自另一个原因。我实际上有依赖解析器和配置正确。事实上,该应用程序运行良好,直到我尝试解决另一个新的依赖项。我有注册设置,所以我无法弄清楚缺少什么。

问题是我意外将接口解析为相同的接口,而不是解析为正确的具体类型。因此,使用OP中的示例,我执行以下操作会导致相同的错误:

container.Bind<IUserManager>().To<IUserManager>();

请注意解析为IUserManager这是一个疏忽,但 会导致OP出现相同的错误。显然,解决方法是解决适当的具体类型。

答案 3 :(得分:1)

接受的回答是从2014年开始。由于很多人都有这个问题,截至2016年已经有了这个问题。这只会增加接受的答案。

我这样做的方法是安装包Ninject.MVC3WebApiContrib.IoC.Ninject。名为NinjectWebCommon的文件会添加到您的App_Start文件夹中。然后,您可以使用内置的NinjectResolver

只需添加此方法:

private static void AddWebApiSupport(StandardKernel kernel)
{
  // Support WebAPI
  GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
  GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider), new NinjectWebApiFilterProvider(kernel));
}

并在致电RegisterServices之前调用它。

答案 4 :(得分:0)

我也有这个问题,但事实证明我的一个接口并没有被任何类实际实现(我忘了将它添加到类声明中)。

答案 5 :(得分:0)

这是一个常见问题,主要发生在使用Ninject Dependency injection Container时。 请按照步骤解决此问题。 的  Make sure you have Installed the following packages.

再次为此而安装此 - enter image description here

现在检查App_start文件夹。您将找到以下内容(NinjectWebcommon.cs)。 enter image description here

现在双击并检查CreateKernel()方法中的以下行,如下所示

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

            RegisterServices(kernel);
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }

然后像这样注册你的依赖

 private static void RegisterServices(IKernel kernel)
    {

        kernel.Bind<IProductDetails>().To<ProductDetails>().InRequestScope();
    }      

我相信这会使您的解决方案有效。

答案 6 :(得分:0)

private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<ICountingKsRepository>().To<CountingKsRepository>();

确保To&lt;&gt; part是具体类而不是接口,因为它也会产生相同的错误!

答案 7 :(得分:0)

如果有任何SimpleInjector用户最终出现在这里...

对我来说,只是因为我忘记将SimpleInjectorInitializer.Initialize();添加到我的Application_Start()方法中。

这几天我通常会在SimpleInjectorInitializer文件夹中创建一个App_Start类,在其中我进行container.Verify()GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);调用;在调用我的GetInitializeContainer()方法之后,该方法正在执行所有类型注册等。

答案 8 :(得分:0)

当我在web.config文件中没有提及依赖项注入的接口和类时,这就是我发生的事情。