MVC Web Api e IHttpControllerActivator Dependency Injection

In questi giorni sto lavorando ad un progetto interessante che prevede un massiccio uso di ASP.NET Web API.
Cos√¨, come ormai ad ogni startup di progetto, ci prepariamo ad architettare quel qualcosa ūüôā che ci permetta di iniettare dove necessario le giuste dipendenze allo scopo di semplificare la fase di test dei prodotti finali delle nostre svariate¬†elucubrazioni mentali ūüėÄ …

Dopo una serie di considerazioni fatte, sulle quali non mi dilungher√≤,¬†¬†decidiamo di utilizzare MS Unity come IoC Container e¬†ci lanciamo nell’ormai classica implementazione di un ControllerFactory per intercettare la¬†creazione dei Controller¬†per l’applicazione¬†ASP.NET MVC4 come segue

public class UnityControllerFactory : DefaultControllerFactory
{
    private readonly IUnityContainer _container;

    /// <summary>
    /// Base Constructor
    /// </summary>
    ///Instance of Container.
    public UnityControllerFactory(IUnityContainer container)
    {
        _container = container;
    }

    /// <summary>
    /// Returns a valorized instance of the container.
    /// </summary>
    /// <param name="requestContext">Information about HTTP Request.</param>
    /// <param name="controllerType">Controller Type.</param>
    /// <returns></returns>
    protected override IController GetControllerInstance(RequestContext requestContext,
                                                         Type controllerType)
    {
        Contract.Requires(requestContext != null, "requestContext");
        Contract.Requires(controllerType != null, "controllerType");

        return _container.Resolve(controllerType) as IController;
    }

    /* Ulteriori override di nostra necessità...
     * protected override ...
     * {
     *    ...
     * }
    */
}

Nulla di nuovo quindi e procediamo a registrare il nostro container nel global.asax

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        var container = this.GetContainer("unity");
        var unityControllerFactory = new UnityControllerFactory(container);
        ControllerBuilder.Current.SetControllerFactory(unityControllerFactory);
    }

    public IUnityContainer GetContainer(string name)
    {
        IUnityContainer container = new UnityContainer();

        object section = ConfigurationManager.GetSection(name);
        if (section == null)
            throw new InvalidOperationException("No unity configuration was found, could not instansiate container");

        UnityConfigurationSection unityConfigurationSection = section as UnityConfigurationSection;
        unityConfigurationSection.Configure(container);

        return container; 
    }
         
}

Ma purtroppo ci rendiamo subito conto che l’implementazione del nostro UnityControllerFactory non ci permette di intercettare la creazione degli ApiCotroller e di conseguenza neanche di iniettare le nostre dipendenze in questi ultimi… la soluzione?

Abbiamo bisogno di un UnityHttpControllerActivator (per ulteriori informazioni leggi qui)

Poche righe ancora quindi per intercettare la creazione i nostri WebApiController

public class UnityHttpControllerActivator : IHttpControllerActivator
{
    private readonly IUnityContainer _container;
    private readonly DefaultHttpControllerActivator _defaultActivator;

    public UnityHttpControllerActivator(IUnityContainer container)
    {
        _container = container;
        _defaultActivator = new DefaultHttpControllerActivator();
    }

    public IHttpController Create(System.Net.Http.HttpRequestMessage request, 
                                  HttpControllerDescriptor controllerDescriptor, 
                                  Type controllerType)
    {
        IHttpController httpController = _container.Resolve(controllerType) as IHttpController;
        if (httpController != null)
        {
            return _container.Resolve(controllerType) as IHttpController;
        }
        else
        {
            return _defaultActivator.Create(request, controllerDescriptor, controllerType);
        }
    }
}

a questo punto dobbiamo aggiungere alla funzione Application_Start nel global.asax

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        var container = this.GetContainer("unity");
        var unityControllerFactory = new UnityControllerFactory(container);
        ControllerBuilder.Current.SetControllerFactory(unityControllerFactory);

        var unityHttpControllerActivator = new UnityHttpControllerActivator(container);
        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), 
                                                           unityHttpControllerActivator);
    }
    
    ...
}

Bene! ..ed ora iniettate tutte le dipendenze di cui avete bisogno e buon lavoro! ūüėÄ

Annunci