web-dev-qa-db-fra.com

Assurez-vous que le contrôleur a une erreur de constructeur public sans paramètre

J'ai suivi ce tutorial qui a très bien fonctionné, jusqu'à ce que je modifie ma DbContext pour avoir un constructeur supplémentaire. J'ai maintenant des problèmes avec la résolution et je ne sais pas quoi faire pour résoudre ce problème. Existe-t-il un moyen simple de le forcer à saisir le constructeur sans paramètre ou l’approche est incorrecte? 

DbContext avec deux constructeurs:

public class DashboardDbContext : DbContext
{
    public DashboardDbContext() : base("DefaultConnection") { }

    public DashboardDbContext(DbConnection dbConnection, bool owns)
        : base(dbConnection, owns) { }
}

SiteController constructeur:

private readonly IDashboardRepository _repo;

public SiteController(IDashboardRepository repo)
{
    _repo = repo;
}

Dépôt:

DashboardDbContext _context;

public DashboardRepository(DashboardDbContext context)
{
    _context = context;
}

UnityResolver code:

public class UnityResolver : IDependencyResolver
{
    private readonly IUnityContainer _container;

    public UnityResolver(IUnityContainer container)
    {
        _container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return _container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return _container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = _container.CreateChildContainer();
        return new UnityResolver(child);
    }

    public void Dispose()
    {
        _container.Dispose();
    }
}

WebApiConfig:

var container = new UnityContainer();
container.RegisterType<IDashboardRepository, DashboardRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);

Erreur de l'appel WebApi:

System.InvalidOperationException: Une erreur s'est produite lors de la tentative de création d'un contrôleur de type 'SiteController'. Assurez-vous que le contrôleur a un constructeur public sans paramètre.

at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) 
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request) 
at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) 
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()

InnerException: System.ArgumentException: le type 'Dashboard.Web.Controllers.SiteController' n'a pas de constructeur par défaut.

at System.Linq.Expressions.Expression.New(Type type) 
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) 
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) 
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)

Le tutoriel était excellent et a bien fonctionné pour moi jusqu'à ce que j'ajoute le second constructeur.

86
scarpacci

Ce qui se passe, c'est que vous êtes piqué par ce problème . En gros, ce qui s'est passé, c'est que vous n'avez pas enregistré vos contrôleurs explicitement dans votre conteneur. Unity essaie de résoudre les types concrets non enregistrés pour vous, mais comme il ne peut pas le résoudre (en raison d'une erreur dans votre configuration), il renvoie null. Il est obligé de renvoyer null, car Web API le force à le faire en raison du contrat IDependencyResolver. Dans la mesure où Unity renvoie la valeur null, Web API essaie de créer le contrôleur lui-même, mais comme elle ne possède pas de constructeur par défaut, elle génère l'exception "Assurez-vous que le contrôleur dispose d'un constructeur public sans paramètre". Ce message d'exception est trompeur et n'explique pas la cause réelle.

Vous auriez vu un message d’exception beaucoup plus clair si vous aviez inscrit vos contrôleurs de manière explicite. C’est pourquoi vous devriez toujours enregistrer explicitement tous les types de racine.

Mais bien sûr, l’erreur de configuration provient de l’ajout du second constructeur à votre DbContext. Unity essaie toujours de choisir le constructeur avec le plus d'arguments, mais il n'a aucune idée de la façon de résoudre ce constructeur en particulier.

La véritable cause est donc que vous essayez d'utiliser les fonctionnalités de câblage automatique de Unity pour créer la variable DbContext. DbContext est un type spécial qui ne devrait pas être câblé automatiquement. Il s’agit d’un type d’infrastructure et vous devriez par conséquent vous en remettre à l’enregistrement en utilisant un délégué d’usine :

container.Register<DashboardDbContext>(
    new InjectionFactory(c => new DashboardDbContext())); 
111
Steven

Dans mon cas, c'était à cause d'une exception dans le constructeur de ma dépendance injectée (dans votre exemple - dans le constructeur DashboardRepository). L'exception a été capturée quelque part dans l'infrastructure MVC. J'ai trouvé cela après avoir ajouté des journaux aux endroits appropriés.

36
Illidan

J'ai eu le même problème et je l'ai résolu en apportant des modifications au fichier UnityConfig.cs. Pour résoudre le problème de dépendance dans le fichier UnityConfig.cs, vous devez ajouter:

public static void RegisterComponents()    
{
    var container = new UnityContainer();
    container.RegisterType<ITestService, TestService>();
    DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
5
user1407955

J'ai eu le même problème. Je l'ai googlé pendant deux jours. Enfin, j’ai accidentellement remarqué que le problème était lié au modificateur d’accès du constructeur du contrôleur ... Je n’ai pas placé la clé public derrière le constructeur du contrôleur.

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

        public MyController(IMyClass myClass)
        {
            _myClass = myClass;
        }
    }

J'ajoute cette expérience comme autre réponse, peut-être que quelqu'un d'autre a commis une erreur similaire.

1
Bobs

J'ai cette erreur lorsque j'ai accidentellement défini une propriété en tant que type d'objet spécifique, au lieu du type d'interface défini dans UnityContainer.

Par exemple:

Définir UnityContainer:

var container = new UnityContainer();
container.RegisterInstance(typeof(IDashboardRepository), DashboardRepository);
config.DependencyResolver = new UnityResolver(container);

SiteController (dans le mauvais sens - notez le type de repo):

private readonly DashboardRepository _repo;

public SiteController(DashboardRepository repo)
{
    _repo = repo;
}

SiteController (dans le bon sens):

private readonly IDashboardRepository _repo;

public SiteController(IDashboardRepository repo)
{
    _repo = repo;
}
0
MasterPiece

Si vous avez une interface dans votre contrôleur

public myController(IXInterface Xinstance){}

Vous devez les enregistrer dans le conteneur d’injection de dépendance.

container.Bind<IXInterface>().To<XClass>().InRequestScope();
0
Ahmet Arslan

Si vous utilisez nityConfig.cs pour conserver les mappages de votre type, comme ci-dessous.

public static void RegisterTypes(IUnityContainer container)
    {
     container.RegisterType<IProductRepository, ProductRepository>();
    }

Vous devez informer le **webApiConfig.cs** du conteneur

config.DependencyResolver = new Unity.AspNet.WebApi.UnityDependencyResolver(UnityConfig.Container);
0
Vinay Patel