【问题标题】:Ninject error in WebAPI 2.1 - Make sure that the controller has a parameterless public constructorWebAPI 2.1 中的 Ninject 错误 - 确保控制器具有无参数的公共构造函数
【发布时间】:2014-08-03 09:55:19
【问题描述】:

我的 WebAPI 项目中安装了以下软件包及其依赖项:

Ninject.Web.WebApi Ninject.Web.WebApi.OwinHost

我纯粹将它作为一个 web-api 项目运行。没有 MVC。

当我运行我的应用程序并向 AccountController 的注册操作发送 POST 时,我收到以下错误返回:

{
"message":"An error has occurred.",
"exceptionMessage":"An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor.",
"exceptionType":"System.InvalidOperationException",
"stackTrace":"   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()",
"innerException":{
"message":"An error has occurred.",
"exceptionMessage":"Type 'RPT.Api.Controllers.AccountController' does not have a default constructor",
"exceptionType":"System.ArgumentException",
"stackTrace":"   at System.Linq.Expressions.Expression.New(Type type)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}

谁能帮助我,因为我在 Google 上能找到的唯一详细信息似乎是 2012 年的。

注意:我也尝试过 AutoFac 而不是 Ninject,但也出现了同样的错误。最令人沮丧。

这是我的 NinjectWebCommon.cs:

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using RPT.Data;
using RPT.Services;
using RPT.Services.Interfaces;

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

namespace RPT.Api
{
    using System;
    using System.Web;

    using Microsoft.Web.Infrastructure.DynamicModuleHelper;

    using Ninject;
    using Ninject.Web.Common;

    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();
            try
            {
                kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

                RegisterServices(kernel);


                return kernel;
            }
            catch
            {
                kernel.Dispose();
                throw;
            }
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(IKernel kernel)
        {
            kernel.Bind<RptContext>().ToSelf();

            kernel.Bind<IUserStore<IdentityUser>>().To<UserStore<IdentityUser>>();
            kernel.Bind<UserManager<IdentityUser>>().ToSelf();

            kernel.Bind<IAccountService>().To<AccountService>();
        }
    }
}

这是我的 AccountController:

using System.Threading.Tasks;
using System.Web.Http;
using System.Web.ModelBinding;
using Microsoft.AspNet.Identity;
using RPT.Api.Models;
using RPT.Services.Interfaces;

namespace RPT.Api.Controllers
{
    [RoutePrefix("api/account")]
    public class AccountController : ApiController
    {
        #region Initialisation

        private readonly IAccountService _accountService;

        public AccountController(IAccountService accountService) : base()
        {
            _accountService = accountService;
        }

        #endregion

        #region Actions

        [AllowAnonymous]
        [Route("register")]
        public async Task<IHttpActionResult> Register(UserRegistrationViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var result = await _accountService.RegisterUser(model.UserName, model.Password);

            var errorResult = GetErrorResult(result);

            return errorResult ?? Ok();
        }

        #endregion

        #region Internal

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _accountService.Dispose();
            }

            base.Dispose(disposing);
        }
        private IHttpActionResult GetErrorResult(IdentityResult result)
        {
            if (result == null)
            {
                return InternalServerError();
            }

            if (result.Succeeded) return null;
            if (result.Errors != null)
            {
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError("", error);
                }
            }

            if (ModelState.IsValid)
            {
                // No ModelState errors are available to send, so just return an empty BadRequest.
                return BadRequest();
            }

            return BadRequest(ModelState);
        }

        #endregion
    }
}

【问题讨论】:

  • 不确定是否使用 WebActivatorEx 进行 IoC,但 web-api 网站上有一个使用 IDependencyResolver 注册容器的示例。也许你可以修改你的代码来实现这个接口? asp.net/web-api/overview/extensibility/…
  • @failedprogramming Ninject.WebApi 包不是像 Ninject.MVC3 包对 MVC 应用程序一样包含依赖解析器吗?
  • 旧线程,但发布以防有人遇到同样的问题。对我来说,这是因为我完成了 kernel.Bind&lt;IDep, ConcreteDep&gt;() 而不是 kernel.Bind&lt;IDep&gt;().To&lt;ConcreteDep&gt;();

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


【解决方案1】:

您是否将 OWIN Startup 类修改为调用 app.UseNinjectWebApiapp.UseNinjectMiddleware 而不是调用 app.UseWebApi

Ninject Web API 示例中的Startup.cs 执行此操作...

【讨论】:

  • 那看起来它不会使用 NinjectWebCommon.cs。那是对的吗?如果是这样,我在哪里进行绑定?
  • 我不确定 NinjextWebCommon.cs 来自哪里 - 它通常添加到 MVC 项目中吗?您可以在 Startup.cs 中的 CreateKernel 方法中配置内核及其绑定
  • NinjectWebCommon.cs 由 Ninject nuget 包之一添加。我认为它要么是 Ninject.Web.WebApi.OwinHost 要么是 Ninject.Web.WebApi.WebHost ......这可能是我的困惑发芽的地方。
  • 嗯,这对我有用...似乎 WebAPI/OWIN 设置不需要 NinjectWebCommon.cs。非常感谢:)
  • 这个解决方案对我有用!!! :) 当所有 3 个配置设置都到位时观察到错误,即应用程序启动实例中的 UseWebApi()、UseNinjectWebApi() 和 UseNinjectMiddleware()。但是,删除 UseWebApi() 并仅使用其他 2 个设置解决了该问题。我们在应用程序中使用了 Ninject IOC 和 OWIN。希望这些信息可以帮助面临类似问题的人:)
【解决方案2】:

这适用于旧版本的 Ninject,或者如果您没有使用来自 Ninject.Web.WebApi.Webhost 的自动生成的引导代码。

你缺少一个依赖解析器,它是一个非常基本的实现:

public class NinjectHttpDependencyResolver : IDependencyResolver, IDependencyScope
{
    private readonly IKernel _kernel;
    public NinjectHttpDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }
    public IDependencyScope BeginScope()
    {
        return this;
    }

    public void Dispose()
    {
        //Do nothing
    }

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

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

然后在创建内核时注册它:

var httpResolver = new NinjectHttpDependencyResolver(kernel);
GlobalConfiguration.Configuration.DependencyResolver = httpResolver;

【讨论】:

  • 添加 Ninject.WebApi 包不是不需要这个吗?
  • 你从哪里得到内核?
【解决方案3】:

就我而言,原因是解析器找不到映射。也就是说,假设 HomeController 依赖于 IDumb,解析器找不到带有实现 IDumb 的 Dumb 的具体实现。 换句话说就是错误信息

**No parameterless constructor defined for this object
An error occurred when trying to create a controller of type 'ToDoListT1.WebApp.Controllers.HomeController'. Make sure that the controller has a parameterless public constructor**

完全是误导。就我而言,我只是通过添加对 Dumb 类项目的引用来解决。它应该类似于“找不到 IDumb 的映射。”。我不确定问题出在 NInject 或 MS 上。我花了几个小时才发现这一点。

【讨论】:

  • 这对我很有帮助。尝试自己解决依赖关系。你会看到它失败了。似乎 Web API 调用了一个构造函数,只有它可以解析为参数的依赖项并跳过其他的。
  • 有点老了,但我只是花了几个小时在 MVC + WebApi 中修复了这个错误,切换到 Autofac,得到了一个光荣的异常,一个小时后,一切都修复并运行了。
  • 为了将来参考,看看内部异常 - 它显示了问题所在
【解决方案4】:

我的解决方案是在构造函数中添加“public”关键字。

【讨论】:

  • 投票,这也是我的问题。
【解决方案5】:

确保您已注册控制器使用的所有类型,一直到数据库。

在我的例子中,我只添加了控制器本身使用的接口,而不是用于实际查询数据库的接口。

请注意下面的代码中 AddUserMaintenanceProcessor 类如何具有控制器不知道的依赖项。如果你忽略了这些依赖的 Unity(或任何你使用的 IoC 工具)类型映射,控制器构造将失败。

我的解决方案使用 Unity,但我想说的是,您需要为所有依赖项创建类型映射。

Startup.cs

public void Configuration(IAppBuilder app)
{
    var config = new HttpConfiguration();

    // Configure Unity
    var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
    GlobalConfiguration.Configuration.DependencyResolver = resolver;
    config.DependencyResolver = resolver;

    // Do Web API configuration
    WebApiConfig.Register(config);

    app.UseWebApi(config);
}

UnityConfig.cs

public class UnityConfig
{
    private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() =>
    {
        var container = new UnityContainer();
        RegisterTypes(container);
        return container;
    });

    // Gets the configured Unity container
    public static IUnityContainer GetConfiguredContainer()
    {
        return Container.Value;
    }

    // Register type mappings
    public static void RegisterTypes(IUnityContainer container)
    {
        // LogManagerAdapter wrapping e.g. log4net
        container.RegisterType<ILogManager, LogManagerAdapter>();

        // AutoMapperAdapter wrapping e.g. AutoMapper (configuration omitted)
        container.RegisterType<IAutoMapper, AutoMapperAdapter>();

        // Interface for persisting the user
        container.RegisterType<IAddUserQueryProcessor, AddUserQueryProcessor>();

        // Interface for doing application logic in regards to adding a user
        container.RegisterType<IAddUserMaintenanceProcessor, AddUserMaintenanceProcessor>();
    }
}

UsersController.cs

public class UsersController : ApiController
{
    private readonly IAddUserMaintenanceProcessor _addUserProcessor;

    public UsersV1Controller(IAddUserMaintenanceProcessor addUserProcessor)
    {
        _addUserProcessor = addUserProcessor;
    }

    public async Task<UserModel> Post(NewUser user)
    {
        return await _addUserProcessor.AddUserAsync(user);
    }

    // ...
}

AddUserMaintenanceProcessor.cs

public class AddUserMaintenanceProcessor : IAddUserMaintenanceProcessor
{
    private readonly IAddUserQueryProcessor _queryProcessor;
    private readonly ILog _logger;
    private readonly IAutoMapper _mapper;

    public AddUserMaintenanceProcessor(
        IAddUserQueryProcessor queryProcessor,
        ILogManager logManager,
        IAutoMapper mapper)
    {
        _queryProcessor = queryProcessor;
        _logger = logManager.GetLog(typeof(AddUserMaintenanceProcessor));
        _mapper = mapper;
    }

    public async Task<UserModel> AddUserAsync(NewUser newUser)
    {
        _logger.Info($"Adding new user {newUser.UserName}");

        // Map the NewUser object to a User object
        var user = _mapper.Map<User>(newUser);

        // Persist the user to a medium unknown to this class, using the query processor,
        // which in turn returns a User object
        var addedUser = await _queryProcessor.AddUserAsync(user);

        // Map the User object back to UserModel to return to requester
        var userModel = _mapper.Map<UserModel>(addedUser);

        _logger.Info($"User {userModel.UserName} added successfully");

        return userModel;
    }
}

我省略了处理器的接口,因为它们只包含一种方法(策略模式)。日志和自动映射的接口与这个问题无关。

AddUserQueryProcessor 类只是将用户持久化到数据库中。再次与这个问题无关。

【讨论】:

  • 您能否在此答案中扩展一些注册样本或其他内容,以使其成为更完整的答案。谢谢你
【解决方案6】:

对我来说,导致这个错误的原因是我传递给构造函数的接口,我有一个命名绑定,我用错误的名字调用它。正如你在下面看到的,绑定说它被命名为“仓库”,但我把事情搞混了,把“数据仓库”放在了构造函数中。理顺这一点会导致关于无参数构造函数的错误消失。

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IVisitProcessor>().To<VisitProcessor>().InThreadScope();
        kernel.Bind<IPatientProcessor>().To<PatientProcessor>().InThreadScope();
        kernel.Bind<IDbConnectionFactory>().To<SqlConnectionFactory>().Named("Warehouse").WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["DataWarehouse"].ConnectionString);
    }

构造函数:

//WRONG NAME
public VisitProcessor([Named("DataWarehouse")] IDbConnectionFactory connection)
    {
        _database = connection;
    }

【讨论】:

    【解决方案7】:

    对我有用的是添加 NuGet 包 Ninject.Web.WebApi.WebHost,如下所述:https://github.com/ninject/Ninject.Web.WebApi/wiki/Setting-up-an-mvc-webapi-application

    【讨论】:

      【解决方案8】:

      我也试图制作一个“仅 API”的应用,但遇到了类似的问题。就我个人而言,最终归结为选择正确的起始模板。

      尽管只使用 API,但在“创建新的 ASP.NET Web 应用程序”向导中,选择“空”应用程序类型并在“添加文件夹和核心引用”部分中选择 MVC 和 Web API Ninject 工作正常:

      与“Web API”应用程序相反,后者与 Ninject 配合得很好:

      之后就是简单的添加Ninject.Web.WebApi.WebHost包,里面添加了NinjectWebCommon.cs类,开始添加依赖。

      【讨论】:

      • 这可能是因为 Web API 模板已经安装了 DI 容器... Ninject 可能发生冲突。
      【解决方案9】:

      我有一种情况,我有一个服务,并在其中注入了其他服务。其中一个注入服务有另一个注入服务,其中一个没有正确注册依赖注入。

      我在注入控制器的服务的构造函数中设置了一个断点(导致问题的服务之前的服务)。在调试中显示了它无法解决依赖关系的服务。

      【讨论】:

        【解决方案10】:

        正如其他答案所指出的,错误消息可能具有误导性。 Ninject 可能工作正常,但可能由于各种原因无法实例化某些依赖项,例如:

        您没有看到服务器返回的错误中的所有详细信息(这可能是设计使然)。如果您附加调试器,您也可能无法捕获异常,除非您在调试设置中禁用 "Just My Code"。然后您可能能够捕获一个内部 Ninject 异常,该异常可能包含您理解问题所需的所有信息。

        旧版本的 Ninject,或者如果您没有使用 Ninject.Web.WebApi.WebHost,也需要您将 Ninject 注册为依赖关系解析器,如 https://stackoverflow.com/a/24196092/2279059 中所指出的那样。

        【讨论】:

          猜你喜欢
          • 2016-03-31
          • 1970-01-01
          • 1970-01-01
          • 2015-05-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-06-20
          • 1970-01-01
          相关资源
          最近更新 更多