【问题标题】:MVC 4 Web Api Controller does not have a default constructor?MVC 4 Web Api Controller 没有默认构造函数?
【发布时间】:2013-07-04 05:00:38
【问题描述】:

这是踪迹:

<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 KurtzAsp.Net Mvc 4 and the Web Api: Building a REST Service from Start to Finish

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

应要求。

大陆控制器

[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&lt;ISession&gt;().ToMethod(CreateSession);NHibernate。它在NinjectConfigurator.csprivate void ConfigureNHibernate(IKernel container) { ... }

【问题讨论】:

  • 堆栈跟踪不足以找出您的问题,所以请发布您的ContinentsController的代码!
  • 您已将ContinentsController 的代码复制了两次……但无论如何。问题是您的构造函数依赖项之一ISession session, IContinentMapper continentMapper, IHttpContinentFetcher continentFetcher, IDateTime dateTime 未在 Ninject 中注册。确保所有内容都已注册或发布您的内核绑定以让我们了解缺少的内容。而且您的 UserController 工作正常,因为它有一组完全不同的依赖项。
  • @nemesv 我添加了你要求的内容。
  • 您可以检查的另一件事:确保HttpContinentFetcherContinentMapper 的所有构造函数参数也已在contianer 中注册...
  • @nemesv HttpContinentFetcher 具有 ISessionContinentMapper 将接受子对象的映射器。 ISession 已经注册,如果我有一个大陆的孩子,即国家,它将被注册。

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


【解决方案1】:

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

您可以使用 Felipe Oriani 的答案,但如果您愿意,可以使用一个名为 WebApiContrib.IoC.Ninject 的 NuGet 包来为您完成此操作。

  1. 在 Visual Studio 中转到:工具 > NuGet 包管理器 > 管理 用于解决方案的 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;
        }
    }
    

【讨论】:

  • 嘿伙计!谢谢,这在我的 webApi 应用程序中非常有效。 MVC 5.
【解决方案2】:

当您未在应用程序中设置依赖关系解析器时,此错误是一个已知错误。控制器工厂找不到无参数构造函数来创建控制器并执行操作方法(或动词方法?)。因此,您必须创建一个依赖解析器类并将其设置在您的 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 方法。

【讨论】:

  • 我只需将GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel); 添加到我的 NinjectWebCommon,不必调用 global.asax.cs 中的方法。谢谢
  • in the end of Application_Start event -> 这很重要!我使用的是 Unity,而不是 Ninject,但由于太早设置解析器,我遇到了各种异常。将其移动到此处理程序的末尾修复了它。谢谢费利佩!
【解决方案3】:

对我来说,只需添加 Ninject.Web.WebApi.Webhost NuGet 包即可。

对于同时使用 MVC 和 WebApi2 的应用程序,我有以下 Ninject 包:

  • 忍者
  • Ninject.MVC5
  • Ninject.Web.Common
  • Ninject.Web.Common.WebHost
  • Ninject.Web.WebApi
  • Ninject.Web.WebApi.WebHost

【讨论】:

  • 在将 Ninject 3.2.x 更新到 3.3.x 后必须添加 Ninject.Web.Common.WebHost 和 Ninject.Web.WebApi.WebHost 包
【解决方案4】:

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

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

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

注意解析为IUserManager,这是一个疏忽,但它确实会导致来自 OP 的相同错误。显然,解决方法是解决正确的具体类型。

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      接受的答案来自 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之前调用它。

      【讨论】:

        【解决方案7】:

        这是一个常见的问题,主要发生在您使用 Ninject Dependency injection Container 时。 请按照步骤解决此问题。

        再次执行此操作并安装此-

        现在检查 App_start 文件夹。您会发现以下内容(NinjectWebcommon.cs)。

        现在双击并检查 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();
            }      
        

        我相信这将使您的解决方案发挥作用。

        【讨论】:

          【解决方案8】:
          private static void RegisterServices(IKernel kernel)
                  {
                      kernel.Bind<ICountingKsRepository>().To<CountingKsRepository>();
          

          确保 To 部分是具体类而不是接口,因为这也会产生相同的错误!

          【讨论】:

            【解决方案9】:

            万一任何SimpleInjector 用户最终来到这里...

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

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

            【讨论】:

              【解决方案10】:

              当我没有在 web.config 文件中提到依赖注入的接口和类时,我就发生了这种情况。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-09-06
                • 1970-01-01
                • 2012-03-06
                • 2023-03-20
                • 2016-07-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多