81 votes

Impossible d'injecter des dépendances dans le contrôleur ASP.NET Web API en utilisant Unity

Quelqu'un a-t-il réussi à utiliser un conteneur IoC pour injecter des dépendances dans des contrôleurs WebAPI ASP.NET ? Je ne parviens pas à le faire fonctionner.

C'est ce que je fais maintenant.

Dans mon global.ascx.cs :

    public static void RegisterRoutes(RouteCollection routes)
    {
            // code intentionally omitted 
    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        IUnityContainer container = BuildUnityContainer();

        System.Web.Http.GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
            t =>
            {
                try
                {
                    return container.Resolve(t);
                }
                catch (ResolutionFailedException)
                {
                    return null;
                }
            },
            t =>
            {
                try
                {
                    return container.ResolveAll(t);
                }
                catch (ResolutionFailedException)
                {
                    return new System.Collections.Generic.List<object>();
                }
            });

        System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); 

        BundleTable.Bundles.RegisterTemplateBundles();
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer().LoadConfiguration();

        return container;
    }

Mon usine de contrôle :

public class UnityControllerFactory : DefaultControllerFactory
            {
                private IUnityContainer _container;

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

                public override IController CreateController(System.Web.Routing.RequestContext requestContext,
                                                    string controllerName)
                {
                    Type controllerType = base.GetControllerType(requestContext, controllerName);

                    return (IController)_container.Resolve(controllerType);
                }
            }

Il ne semble jamais regarder dans mon fichier unity pour résoudre les dépendances, et j'obtiens une erreur du genre :

Une erreur s'est produite en essayant de créer un contrôleur de type PersonalShopper.Services.WebApi.Controllers.ShoppingListController'. Assurez-vous que le contrôleur possède un constructeur public sans paramètre.

à l'adresse System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpControllerContext controllerContext, Type controllerType) at System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateInstance(HttpControllerContext controllerContext, HttpControllerDescriptor controllerDescriptor) at System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateController(HttpControllerContext controllerContext, String controllerName) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

Le contrôleur ressemble :

public class ShoppingListController : System.Web.Http.ApiController
    {
        private Repositories.IProductListRepository _ProductListRepository;

        public ShoppingListController(Repositories.IUserRepository userRepository,
            Repositories.IProductListRepository productListRepository)
        {
            _ProductListRepository = productListRepository;
        }
}

Mon fichier unity ressemble à ça :

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <container>
    <register type="PersonalShopper.Repositories.IProductListRepository, PersonalShopper.Repositories" mapTo="PersonalShopper.Implementations.MongoRepositories.ProductListRepository, PersonalShopper.Implementations" />
  </container>
</unity>

Notez que je n'ai pas d'enregistrement pour le contrôleur lui-même, car dans les versions précédentes de mvc, la fabrique du contrôleur se rendait compte que les dépendances devaient être résolues.

Il semble que la fabrique de mon contrôleur ne soit jamais appelée.

42voto

Oved D Points 1566

J'ai compris.

Para Contrôleurs Api MVC 4 utilise un System.Web.Http.Dispatcher.IHttpControllerFactory y System.Web.Http.Dispatcher.IHttpControllerActivator pour créer les contrôleurs. S'il n'existe pas de méthode statique pour enregistrer l'implémentation de ces contrôleurs, lorsqu'ils sont résolus, le cadre mvc recherche les implémentations dans le résolveur de dépendances et, si elles ne sont pas trouvées, utilise les implémentations par défaut.

J'ai réussi à faire fonctionner la résolution d'unité des dépendances du contrôleur en faisant ce qui suit :

Création d'un UnityHttpControllerActivator :

public class UnityHttpControllerActivator : IHttpControllerActivator
{
    private IUnityContainer _container;

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

    public IHttpController Create(HttpControllerContext controllerContext, Type controllerType)
    {
        return (IHttpController)_container.Resolve(controllerType);
    }
}

Enregistré cet activateur de contrôleur comme l'implémentation dans le conteneur unity lui-même :

protected void Application_Start()
{
    // code intentionally omitted

    IUnityContainer container = BuildUnityContainer();
    container.RegisterInstance<IHttpControllerActivator>(new UnityHttpControllerActivator(container));

    ServiceResolver.SetResolver(t =>
       {
         // rest of code is the same as in question above, and is omitted.
       });
}

37voto

CodeKata Points 458

Il existe une meilleure solution qui fonctionne correctement ici

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

23voto

Paul Hiles Points 3887

Vous pouvez consulter le paquet NuGet Unity.WebApi qui résout tous ces problèmes et prend également en charge les composants IDisposable.

voir

http://nuget.org/packages/Unity.WebAPI

ou

http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package

2voto

Malkov Points 455

Le bon article sur la façon d'utiliser Unity avec ASP.NET MVC 4 et WebAPI.

Dans cet article, vous trouverez comment utiliser Unity.Mvc3 et Unity.WebAPI.

2voto

Noogen Points 21

Dans une récente RC, je constate qu'il n'y a plus de méthode SetResolver. Pour activer à la fois IoC pour le contrôleur et webapi, j'utilise Unity.WebApi (NuGet) et le code suivant :

public static class Bootstrapper
{
    public static void Initialise()
    {
        var container = BuildUnityContainer();

        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);

        ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new ControllerActivator()));
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        container.Configure(c => c.Scan(scan =>
        {
            scan.AssembliesInBaseDirectory();
            scan.With<UnityConfiguration.FirstInterfaceConvention>().IgnoreInterfacesOnBaseTypes();
        }));

        return container;
    }
}

public class ControllerActivator : IControllerActivator
{
    IController IControllerActivator.Create(RequestContext requestContext, Type controllerType)
    {
        return GlobalConfiguration.Configuration.DependencyResolver.GetService(controllerType) as IController;
    }
}

J'utilise également UnityConfiguration (également de NuGet) pour la magie IoC ;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X