Je développe une API Web ASP.NET 2.2 avec C #, .NET Framework 4.5.1.
Après la mise à jour de Web.Api vers Ninject 3.2.0, le message d'erreur suivant s'affiche:
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.
Je reçois l'exception dans 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
class:
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
class:
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.
}
La chose étrange est qu'il compile et fonctionne parfaitement, mais après la mise à jour, il ne fonctionne pas.
J'ai changé ce public class NinjectDependencyResolver : IDependencyResolver, System.Web.Mvc.IDependencyResolver
mais cela ne fonctionne toujours pas.
Une idée?
METTRE &AGRAVE; JOUR
Le débogage, je vois que l'exception est levée dans NinjectDependencyResolver
ici:
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAll(serviceType);
}
Il court deux fois. La première serviceType
est IFilterProvider
et la deuxième fois serviceType
est ModelValidatorProvider
, et ensuite j'obtiens l'exception.
Ce sont les paquets Ninject que j'utilise:
<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" />
La version précédente pour ces assemblées était:
<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" />
SECOND MISE À JOUR
J'ai trouvé que le problème est dans cette classe:
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>();
}
}
J'ai mis Dependency Resolver
ici:
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;
}
Et j'utilise WebContainerManager
dans une classe qui hérite de 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);
}
}
Donc, si je supprime WebContainerManager
, je ne comprends pas ce cycle.
J'avais toutes sortes de problèmes avec l'initialisation de WebApi2 et Ninject après la mise à niveau des packages Ninject (même la désinstallation et la suppression des anciens).
Plus précisément, dans votre cas, je supprimerais ces lignes de code:
// Use the container and our NinjectDependencyResolver as
// application's resolver
var resolver = new NinjectDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
car ils sont probablement à l'origine de l'erreur (les bibliothèques NinjectWebCommon.cs et Ninject traitent maintenant de l'initialisation du résolveur de dépendances).
Pour d'autres qui ont suivi un chemin de mise à niveau similaire à moi. Ce qui a fonctionné pour moi a été le suivant:
Supprimez l'ancien code d'initialisation DependencyResolver (pour moi, cela était à l'origine de l'erreur spécifique que vous avez mentionnée, comme dans les versions précédentes de Ninject/WebApi2, en insérant ces lignes dans la méthode WebApiConfig.cs Register (). est le cas):
var kernel = new StandardKernel();
config.DependencyResolver = new NinjectDependencyResolver(kernel);
Installez le package Ninject.Web.WebApi.WebHost. Cela a installé le fichier NinjectWebCommon.cs. Pour moi, le simple fait d'avoir le Ninject.Web.WebApi et ses dépendances N'a pas créé ce fichier.
Mes paquets Ninject installés et fonctionnels pour référence:
<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" />
Assurez-vous que les anciennes dlls Ninject
ou Ninject.Web.Common.*
ne sont pas présentes dans votre dossier bin.
J'ai eu le même problème dans ma solution après avoir désinstallé Ninject.Web.Common
, Ninject.Web.Common.WebHost
, Ninject.Web.WebApi
et Ninject.MVC5
de Nuget et installé WebApiContrib.IoC.Ninject
afin d'utiliser GlobalConfiguration.Configuration.DependencyResolver
comme dans votre exemple. J'ai conservé la version de Ninject
que j'avais déjà installée (qui était bien 3.2.2 ).
L'erreur ne s'est pas produite lorsque j'ai effectué mes modifications pour la première fois. Cependant, après être passé de quelques branches git à mon travail actuel, j'ai vu l'erreur. Le code qui fonctionnait bien la semaine dernière renvoyait maintenant la même erreur exacte.
Il semble que mon dossier bin contienne des références aux anciens paquets Ninject.*
que j'avais supprimés. Lors de la suppression de ces fichiers, mon projet a fonctionné comme prévu.
La dépendance cyclique se situe entre les classes "NinjectDefaultModelValidatorProvider" et "DefaultModelValidatorProviders". Ajoutez simplement une liaison pour "DefaultModelValidatorProviders" au démarrage, comme ci-dessous:
_ kernel.Bind <DefaultModelValidatorProviders> (). ToConstant (new DefaultModelValidatorProviders (config.Services.GetServices (typeof (ModelValidatorProvider)).
Dans mon cas, cela fonctionnait très bien dans le contexte Owin Selfhost, mais pas lorsque hébergé dans IIS. Ma solution consistait à supprimer tous les assemblys liés à Ninject des paquets Nuget à l'exception de Ninject lui-même.
Ensuite, j'ai écrit ma propre classe DependencyResolver, n'hésitez pas à laisser des améliorations dans les commentaires.
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);
}
}
Et ensuite dans votre méthode de configuration 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);
C'est ce qui a fonctionné pour moi.
uninstall-package Ninject.Web.WebApi.WebHost
La commande ci-dessus a désinstallé la version 'Ninject.Web.WebApi.WebHost 3.2.4.0' et l'erreur a disparu!
Juste reconfirmer, j'ai installé le même paquet en utilisant la commande
install-package Ninject.Web.WebApi.WebHost
et la commande a installé le package 'Ninject.Web.WebApi.WebHost 3.2.4.0' et l'erreur est réapparue.
var _surveyBusiness = _kernel.Get<ISurveyBusiness>();
_surveyBusiness.SomeFunc(user.CompanyId, user.UserId);
Cela fonctionne aussi.