Я разрабатываю 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
, я не получу этот цикл.
WebContainerManager
для статического захвата ядра и использования в качестве локатора службы я бы использовал этот подход, который поддерживает внедрение ctor в файлIActionFilter
. См. также здесь а> - person BatteryBackupUnit   schedule 10.11.2014