web-dev-qa-db-fra.com

Unity IoC n'injecte pas de dépendance dans Web API Controller

Je connais très peu l’unité sous Unity, mais le problème est que chaque fois que j'appelle mon service Web, une exception indiquant que

"Assurez-vous que le contrôleur a un constructeur public sans paramètre"

J'ai suivi plusieurs tutoriels et j'obtiens toujours le même problème. 

Dans la fonction Register de ma classe WebApiConfig, j'ai 

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

Voici ma classe UnityResolver

using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;

public class UnityResolver : IDependencyResolver
{
    protected IUnityContainer container;

    public UnityResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.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();
    }
}

Je n'ai enregistré aucun contrôleur, car chaque tutoriel affirme que je n'ai pas besoin de le faire. Voici mon contrôleur actuel

public class Controller: ApiController
{
    private IValidator _validator;

    public Controller(IValidator validator)
    {
        this._validator = validator;
    }

    [HttpPost]
    public void ReceiveIPN()
    {

    }
}

Quelqu'un a-t-il une idée de ce que je peux faire de mal? Merci!

EDIT 1: Voici "l'implémentation" de la classe Validator. C'est plutôt vide, car je ne voulais pas introduire de bogue avant d'avoir résolu le problème d'Unity. 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;


public class Validator: IValidator
{
    public bool ValidateIPN(string body)
    {
        throw new NotImplementedException();
    }
}

EDIT 2: Voici toute la réponse d'erreur que je reçois lorsque j'essaie d'appeler la route de l'API Web à l'aide de Fiddler.

{"message": "Une erreur s'est produite.", "exceptionMessage": "Une erreur s'est produite lors de la tentative de création d'un contrôleur de type 'Controller'. Assurez-vous que le contrôleur a un public sans paramètre constructeur. "," exceptionType ":" System.InvalidOperationException "," stackTrace ":" at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (HttpRequestMessage request, HttpControllerDescriptororceptor __. controllerType) à System.Web.Http.Controllers.HttpControllerDescriptor.CreateController (HttpRequestMessage request) à System.Web.Http.Dispatcher.HttpControllerDispatcherDispatcher.Disp. : {"message": "Une erreur s'est produite.", "exceptionMessage": "Type 'Project.Controller' n'a pas de constructeur par défaut", "exceptionType": "System.ArgumentException "," stackTrace ":" à System.Linq.Expressions.Expression.New (Type type) à System.Web.Http.Internal.TypeActivator.Create [TBase] (Type .__ instanc eType) à System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator (HttpRequestMessage Request, Type controllerType, Func`1 & activator) à System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (HttpRequestMessage Request, HttpControllerDescriptor controllerDescriptor, Type ControllerType) "}}

21
Carlos Rodriguez

Ainsi, après des heures passées à me cogner la tête contre un mur, j'ai constaté que cela ne fonctionnait pas car j'avais un cours OWIN/Katana Startup.cs dans mon projet. Maintenant, je ne sais pas exactement ce qui se passe ici, donc toute information supplémentaire serait formidable.

Fondamentalement, puisque j'utilisais OWIN/Katana, j'avais un fichier Startup.cs qui créait un nouvel objet HttpConfiguration et le configurait, de la même manière que dans la classe WebApiConfig.cs. 

private void ConfigureWebApi(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();
    var container = new UnityContainer();
    container.RegisterType<IValidator, Validator>();
    config.DependencyResolver = new UnityDependencyResolver(container);

    var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter().First();
    jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}

Il semble que le code parcourt d'abord la fonction Register de WebApiConfig et THEN substitue cet objet HttpConfiguration à celui généré dans le fichier Startup.cs. Pour que cela fonctionne, je devais déplacer les éléments de configuration du conteneur ici. 

Désolé de ne pas avoir évoqué le sujet OWIN auparavant. C'est assez nouveau pour moi et je n'avais pas réalisé que c'était pertinent. Espérons que cela évite à quelqu'un d'autre la douleur que je viens de traverser. 

26
Carlos Rodriguez

Votre conteneur Unity est probablement en train d'être éliminé car il est uniquement défini dans le cadre de votre méthode WebApiConfig.Register(). Si vous définissez votre conteneur en tant que membre de Global, ce qui conservera votre conteneur pendant toute la durée de vie de l'application, cela devrait fonctionner.

Edit: n'oubliez pas de supprimer le conteneur sur Application_End.

1
moarboilerplate
  • Installez Unity.mvc5 et Unity.WebApi dans un projet via le package Nuget
  • Spécifiez l'espace complet comme indiqué dans la ligne ci-dessous

Exemple:

public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();

        DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));

        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
    }
}
0
Prabhaker Mishra