【问题标题】:NinjectDependencyResolver fails binding ModelValidatorProviderNinjectDependencyResolver 绑定 ModelValidatorProvider 失败
【发布时间】:2014-12-06 09:06:26
【问题描述】:

我正在使用 C#、.NET Framework 4.5.1 开发 ASP.NET Web Api 2.2。

将我的 Web.Api 更新到 Ninject 3.2.0 后,我收到此错误:

Error activating ModelValidatorProvider using binding from ModelValidatorProvider to NinjectDefaultModelValidatorProvider
A cyclical dependency was detected between the constructors of two services.

Activation path:
  3) Injection of dependency ModelValidatorProvider into parameter defaultModelValidatorProviders of constructor of type DefaultModelValidatorProviders
  2) Injection of dependency DefaultModelValidatorProviders into parameter defaultModelValidatorProviders of constructor of type NinjectDefaultModelValidatorProvider
  1) Request for ModelValidatorProvider

Suggestions:
  1) Ensure that you have not declared a dependency for ModelValidatorProvider on any implementations of the service.
  2) Consider combining the services into a single one to remove the cycle.
  3) Use property injection instead of constructor injection, and implement IInitializable
     if you need initialization logic to be run after property values have been injected.

我在NinjectWebCommon 中得到了异常:

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)
    {
        var containerConfigurator = new NinjectConfigurator();
        containerConfigurator.Configure(kernel);
    }        
}

NinjectDependencyResolver类:

using Ninject;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;

namespace Matt.SocialNetwork.Web.Common
{
    public class NinjectDependencyResolver : IDependencyResolver
    {
        private readonly IKernel _container;

        public IKernel Container
        {
            get { return _container; }
        }

        public NinjectDependencyResolver(IKernel container)
        {
            _container = container;
        }

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

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

        public IDependencyScope BeginScope()
        {
            return this;
        }

        public void Dispose()
        {
            // noop
        }
    }
}

NinjectConfigurator类:

public class NinjectConfigurator
{
    public void Configure(IKernel container)
    {
        // Add all bindings/dependencies
        AddBindings(container);

        // Use the container and our NinjectDependencyResolver as
        // application's resolver
        var resolver = new NinjectDependencyResolver(container);
        GlobalConfiguration.Configuration.DependencyResolver = resolver;
    }

    // Omitted for brevity.
}

奇怪的是它可以完美地编译和运行,但是更新后它就不起作用了。

我已经更改了这个public class NinjectDependencyResolver : IDependencyResolver, System.Web.Mvc.IDependencyResolver,但它仍然不起作用。

有什么想法吗?

更新

调试中看到NinjectDependencyResolver这里抛出了异常:

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

它运行两次。第一次serviceTypeIFilterProvider,第二次serviceTypeModelValidatorProvider,然后我得到了异常。

这些是我正在使用的 Ninject 包:

<package id="Ninject" version="3.2.2.0" targetFramework="net451" />
<package id="Ninject.MVC5" version="3.2.1.0" targetFramework="net45" />
<package id="Ninject.Web.Common" version="3.2.3.0" targetFramework="net451" />
<package id="Ninject.Web.Common.WebHost" version="3.2.3.0" targetFramework="net451" />
<package id="Ninject.Web.WebApi" version="3.2.2.0" targetFramework="net451" />

这些程序集的先前版本是:

<package id="Ninject" version="3.2.2.0" targetFramework="net45" />
<package id="Ninject.MVC5" version="3.2.1.0" targetFramework="net45" />
<package id="Ninject.Web.Common" version="3.2.2.0" targetFramework="net451" />
<package id="Ninject.Web.Common.WebHost" version="3.2.0.0" targetFramework="net45" />
<package id="Ninject.Web.WebApi" version="3.2.0.0" targetFramework="net451" />

第二次更新

我发现问题出在这个类上:

public static class WebContainerManager
{
    public static IKernel GetContainer()
    {
        var resolver = GlobalConfiguration.Configuration.DependencyResolver as NinjectDependencyResolver;
        if (resolver != null)
        {
            return resolver.Container;
        }

        throw new InvalidOperationException("NinjectDependencyResolver not being used as the MVC dependency resolver");
    }

    public static T Get<T>()
    {
        return GetContainer().Get<T>();
    }
}

我在这里设置Dependency Resolver

public class NinjectConfigurator
{
    /// <summary>
    /// Entry method used by caller to configure the given 
    /// container with all of this application's 
    /// dependencies. Also configures the container as this
    /// application's dependency resolver.
    /// </summary>
    public void Configure(IKernel container)
    {
        // Add all bindings/dependencies
        AddBindings(container);

        // Use the container and our NinjectDependencyResolver as
        // application's resolver
        var resolver = new NinjectDependencyResolver(container);
        GlobalConfiguration.Configuration.DependencyResolver = resolver;
    }

我在一个继承自ExceptionFilterAttribute的类中使用WebContainerManager

public class UnhandledExceptionFilter : ExceptionFilterAttribute
{
    private readonly IExceptionLogHelper excepLogHelper;

    public UnhandledExceptionFilter()
        : this(WebContainerManager.Get<IExceptionLogHelper>()) {}

    public UnhandledExceptionFilter(IExceptionLogHelper exceptionLogHelper)
    {
        this.excepLogHelper = exceptionLogHelper;
    }

    public override void OnException(HttpActionExecutedContext actionExecutedContext)
    {
        this.excepLogHelper.LogException(actionExecutedContext);
    }
}

所以,如果我删除 WebContainerManager,我不会得到那个循环。

【问题讨论】:

  • 你试过卸载所有的ninject包并重新安装吗?确保您确实获得了最新版本?
  • 是的,我这样做了,我得到了同样的错误。
  • 你能把mcve作为视觉工作室项目上传到gist/github repo或类似的东西上吗?我想试一试。
  • 作为旁注,我不会使用WebContainerManager 静态捕获内核并用作服务定位器,而是使用this approach,它支持将ctor-injection 注入IActionFilter。另见here

标签: c# ninject ninject.web.mvc


【解决方案1】:

在升级 Ninject 包(甚至卸载和删除旧包)后,我对 WebApi2 和 Ninject 初始化感到非常痛苦。

特别是在你的情况下,我会删除这些代码行:

// Use the container and our NinjectDependencyResolver as
// application's resolver
var resolver = new NinjectDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;

因为它们可能是错误的原因(NinjectWebCommon.cs 和 Ninject 库现在处理初始化依赖解析器)。


对于那些遵循与我类似的升级路径的其他人。对我有用的是:

  • 删除旧的 DependencyResolver 初始化代码(对我来说,这导致了您在早期版本的 Ninject/WebApi2 中提到的特定错误,将这些行放在 WebApiConfig.cs Register() 方法中是您初始化 DependencyResolver 的方式...现在不再是这种情况了):

    var kernel = new StandardKernel();
    config.DependencyResolver = new NinjectDependencyResolver(kernel);
    
  • 安装 Ninject.Web.WebApi.WebHost 包。这安装了 NinjectWebCommon.cs 文件。对我来说,只需要 Ninject.Web.WebApi 就可以了 依赖项没有创建此文件。

我安装和工作的 Ninject 包供参考:

<package id="Ninject" version="3.2.2.0" targetFramework="net452" />
<package id="Ninject.Web.Common" version="3.2.3.0" targetFramework="net452" />
<package id="Ninject.Web.Common.WebHost" version="3.2.0.0" targetFramework="net452" />
<package id="Ninject.Web.WebApi" version="3.2.3.0" targetFramework="net452" />
<package id="Ninject.Web.WebApi.WebHost" version="3.2.3.0" targetFramework="net452" />

【讨论】:

  • config.DependencyResolver中的'config'从何而来?
  • @bigerock WebApiConfig.cs 将有一个方法 public static void Register(HttpConfiguration config) 这是上面两行代码应该去的地方。
  • 当我没有 Ninject.Web.WebApi.WebHost 依赖项时,它可以在本地工作,但在我发布时不行。谢谢!
  • 你是说我们根本不应该设置DependencyResolver?查看您的“我将删除这些代码行”“不再是这种情况”。依赖解析器是自动设置还是以其他方式设置?
  • 我可以确认添加这些行会导致问题开始发生。另一方面,如果没有这些行,依赖注入甚至不起作用:stackoverflow.com/questions/30958389/…。你还在用 Ninject 吗?
【解决方案2】:

循环依赖在“NinjectDefaultModelValidatorProvider”和“DefaultModelValidatorProviders”类之间。只需在启动时为“DefaultModelValidatorProviders”添加绑定,如下所示:

_kernel.Bind().ToConstant(new DefaultModelValidatorProviders(config.Services.GetServices(typeof (ModelValidatorProvider)).Cast()));

【讨论】:

  • 配置来自哪里?
  • config 是 GlobalConfiguration.Configuration
【解决方案3】:

确保您的 bin 文件夹中不存在任何旧的 NinjectNinject.Web.Common.* dll。

在我从 Nuget 卸载 Ninject.Web.CommonNinject.Web.Common.WebHostNinject.Web.WebApiNinject.MVC5 并安装 WebApiContrib.IoC.Ninject 以便在您的示例中使用 GlobalConfiguration.Configuration.DependencyResolver 之后,我的解决方案中遇到了同样的问题。我保留了我已经安装的Ninject 的版本(确实是3.2.2)。

我第一次进行更改时没有出现错误。然而,在从几个 git 分支移动并回到我当前的工作之后,我看到了错误。上周运行良好的代码现在抛出了同样的错误。

我的 bin 文件夹似乎引用了我已删除的旧 Ninject.* 包。删除这些文件后,我的项目按预期工作。

【讨论】:

  • 哇,我一直回到这个 SO,直到我意识到在发布到 Azure 时我并没有删除旧的 dll!在 Publish->Settings->File Publish Options 下,您必须选中“Remove additional files at destination”。否则你会发现一切都在 localhost 上运行,但在 Azure 上却不行,因为 Ninject.Web.* 仍然存在。
【解决方案4】:

在我的情况下,它在 Owin Selfhost 上下文中工作得很好,但在 IIS 中托管时却不行。我的解决方案是从 nuget 包中删除所有与 Ninject 相关的程序集,除了 Ninject 本身。

然后我编写了自己的 DependencyResolver 类,随时在 cmets 中留下改进。

public class NinjectDepsolver : IDependencyResolver
{
    private IKernel _kernel;

    public NinjectDepsolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    public void Dispose()
    {
        _kernel = null;
    }

    public object GetService(Type serviceType) => _kernel.TryGet(serviceType);

    public IEnumerable<object> GetServices(Type serviceType) => _kernel.GetAll(serviceType).ToArray();

    public IDependencyScope BeginScope() => new DepScope(this);

    class DepScope : IDependencyScope
    {
        private NinjectDepsolver _depsolver;

        public DepScope(NinjectDepsolver depsolver)
        {
            _depsolver = depsolver;
        }

        public void Dispose()
        {
            _depsolver = null;
        }

        public object GetService(Type serviceType) => _depsolver.GetService(serviceType);

        public IEnumerable<object> GetServices(Type serviceType) => _depsolver.GetServices(serviceType);
    }
}

然后在你的 Owin 配置方法中:

var kernel = new StandardKernel();
kernel.Load(<your module classes>);
var httpConfig = new HttpConfiguration();
var httpConfig.DependencyResolver = new NinjectDepsolver(kernel);
var httpConfig.MapHttpAttributeRoutes();

app.UseWebApi(httpConfig);

【讨论】:

    【解决方案5】:

    这对我有用。

    uninstall-package Ninject.Web.WebApi.WebHost

    上面的命令卸载了'Ninject.Web.WebApi.WebHost 3.2.4.0'这个版本,错误消失了!!

    再次确认,我已经使用命令安装了相同的包

    install-package Ninject.Web.WebApi.WebHost

    并且该命令安装了包'Ninject.Web.WebApi.WebHost 3.2.4.0'并且错误再次出现。

    【讨论】:

      【解决方案6】:
      var _surveyBusiness = _kernel.Get<ISurveyBusiness>();
      _surveyBusiness.SomeFunc(user.CompanyId, user.UserId);
      

      这也有效。

      【讨论】:

      • 您好,欢迎来到 SO,您能澄清一下您的解决方案背后的逻辑以及它为什么有效吗?
      【解决方案7】:

      我通过在 Global.asax(我的 StandardKernel 正在初始化的地方)中添加以下行来解决此问题:

      kernel.Bind<DefaultModelValidatorProviders>().ToConstant(new DefaultModelValidatorProviders(GlobalConfiguration.Configuration.Services.GetModelValidatorProviders()));
      

      【讨论】:

        【解决方案8】:

        我在 OWIN 中为此苦苦挣扎了一段时间,最后总是回到以前的版本。但没有什么比在他们的 github 上查看示例应用程序更有趣了。

        首先确保您摆脱了可能要添加到配置中的任何手动依赖解析器,然后在启动期间执行以下操作:

        appBuilder.UseNinjectMiddleware(() => yourKernel); // or a function that returns your kernel
        appBuilder.UseNinjectWebApi(yourHttConfiguration);
        

        应该没问题。

        【讨论】:

          【解决方案9】:

          我卸载了 Ninject.Web.WebApi.WebHost 包,错误不再存在或发生。

          【讨论】:

            【解决方案10】:

            我遇到了同样的错误并卸载了 Ninject.Web.WebApi.WebHost 包并删除了错误。

            【讨论】:

              猜你喜欢
              • 2012-01-14
              • 2012-02-25
              • 2015-02-02
              • 2013-10-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-08-16
              • 2015-11-30
              相关资源
              最近更新 更多