NinjectDependencyResolver не удается привязать ModelValidatorProvider

Я разрабатываю ASP.NET Web Api 2.2 с С#, .NET Framework 4.5.1.

После обновления моего 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);
}

Он проходит дважды. Первый serviceType равен IFilterProvider, а второй раз serviceType равен ModelValidatorProvider, и после этого я получаю исключение.

Это пакеты 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;
    }

И я использую WebContainerManager в классе, который наследуется от ExceptionFilterAttribute:

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, я не получу этот цикл.


person VansFannel    schedule 11.10.2014    source источник
comment
Вы пытались удалить все пакеты ninject и переустановить их? Убедитесь, что у вас действительно самая новая версия?   -  person BatteryBackupUnit    schedule 17.10.2014
comment
Да, я сделал это, и я получил ту же ошибку.   -  person VansFannel    schedule 17.10.2014
comment
можете ли вы загрузить mcve как проект визуальной студии в репозиторий gist/github или что-то в этом роде? Я хотел бы попробовать.   -  person BatteryBackupUnit    schedule 10.11.2014
comment
в качестве примечания: вместо использования WebContainerManager для статического захвата ядра и использования в качестве локатора службы я бы использовал этот подход, который поддерживает внедрение ctor в файл IActionFilter. См. также здесь   -  person BatteryBackupUnit    schedule 10.11.2014


Ответы (10)


У меня были всевозможные проблемы с инициализацией WebApi2 и Ninject после обновления пакетов 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" />
person mips    schedule 10.12.2014
comment
откуда берется «конфигурация» в config.DependencyResolver? - person bigerock; 01.04.2015
comment
@bigerock WebApiConfig.cs будет иметь метод public static void Register (конфигурация HttpConfiguration), в котором должны находиться приведенные выше две строки кода. - person mips; 06.04.2015
comment
Когда у меня не было зависимости Ninject.Web.WebApi.WebHost, она работала локально, но не при публикации. Спасибо! - person Kyle W; 15.06.2018
comment
Вы говорите, что мы вообще не должны устанавливать DependencyResolver? Глядя на ваш я бы удалил эти строки кода и это уже не так. Преобразователь зависимостей устанавливается автоматически или как-то иначе? - person Bennett McElwee; 15.07.2020
comment
Я могу подтвердить, что добавление этих строк привело к возникновению проблемы. С другой стороны, без этих строк внедрение зависимостей даже не работает: owin-web-api/63072330#63072330" title="controller не имеет конструктора по умолчанию ninject owin web api">stackoverflow.com/questions/30958389/. Вы вообще используете Ninject? - person Florian Winter; 24.07.2020

Убедитесь, что в вашей папке bin нет старых Ninject или Ninject.Web.Common.* dll.

У меня была такая же проблема в моем решении после того, как я удалил Ninject.Web.Common, Ninject.Web.Common.WebHost, Ninject.Web.WebApi и Ninject.MVC5 из Nuget и установил WebApiContrib.IoC.Ninject, чтобы использовать GlobalConfiguration.Configuration.DependencyResolver, как в вашем примере. Я сохранил версию Ninject, которую уже установил (которая действительно была 3.2.2).

Ошибка не появлялась, когда я впервые внес свои изменения. Однако после перехода от нескольких веток git к моей текущей работе я увидел ошибку. Код, который работал нормально на прошлой неделе, теперь выдавал точно такую ​​же ошибку.

Кажется, в моей папке bin были ссылки на старые Ninject.* пакеты, которые я удалил. После удаления этих файлов мой проект работал, как и ожидалось.

person Ben Bailey    schedule 05.07.2016
comment
вау, я продолжал возвращаться к этому SO, пока не понял, что при публикации в Azure я не удалял старые DLL! В разделе «Публикация» -> «Настройки» -> «Параметры публикации файлов» необходимо установить флажок «Удалить дополнительные файлы в месте назначения». В противном случае вы обнаружите, что все работает на локальном хосте, но не на Azure, потому что Ninject.Web.* все еще там. - person tofutim; 26.10.2016

Циклическая зависимость находится между классами «NinjectDefaultModelValidatorProvider» и «DefaultModelValidatorProviders». Просто добавьте привязку для «DefaultModelValidatorProviders» при запуске, как показано ниже:

_kernel.Bind<DefaultModelValidatorProviders>().ToConstant(new DefaultModelValidatorProviders(config.Services.GetServices(typeof (ModelValidatorProvider)).Cast<ModelValidatorProvider>()));
person Arindam    schedule 14.09.2015
comment
откуда конфиг? - person Vishal Anand; 17.01.2016
comment
config — это GlobalConfiguration.Configuration. - person Ahmad Zia; 19.07.2018

В моем случае он отлично работал в контексте Owin Selfhost, но не при размещении в IIS. Мое решение состояло в том, чтобы удалить все сборки, связанные с Ninject, из пакетов nuget, кроме самого Ninject.

Затем я написал свой собственный класс DependencyResolver, не стесняйтесь оставлять улучшения в комментариях.

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);
person Arnold Pistorius    schedule 14.06.2017

Я исправил это, добавив следующую строку в Global.asax (где инициализировался мой StandardKernel):

kernel.Bind<DefaultModelValidatorProviders>().ToConstant(new DefaultModelValidatorProviders(GlobalConfiguration.Configuration.Services.GetModelValidatorProviders()));
person Owen Pauling    schedule 10.05.2019

Это то, что сработало для меня.

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», и ошибка снова появилась.

person VivekDev    schedule 06.07.2017

var _surveyBusiness = _kernel.Get<ISurveyBusiness>();
_surveyBusiness.SomeFunc(user.CompanyId, user.UserId);

Это тоже работает.

person Bhanu Bhanot    schedule 14.06.2018
comment
Здравствуйте, добро пожаловать в SO, можете ли вы прояснить логику вашего решения и почему оно работает? - person James Wong; 14.06.2018

Я некоторое время боролся с этим в OWIN и всегда возвращался к предыдущей версии. Но нет ничего лучше, чем проверить пример приложения на их github.

Сначала убедитесь, что вы избавились от любого ручного средства разрешения зависимостей, которое вы можете добавить в конфигурацию, а затем просто выполните следующие действия во время запуска:

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

Это должно работать нормально.

person Juan    schedule 19.12.2019

Я получал ту же ошибку и удалял пакет Ninject.Web.WebApi.WebHost, и ошибка удалялась.

person Anjani Kumar Agarwal    schedule 26.06.2020

Я удалил пакет Ninject.Web.WebApi.WebHost, и ошибка больше не существует или не возникает.

person Anjani Kumar Agarwal    schedule 26.06.2020