Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebApi Filter Unity

Environement : Unity and ASP.NET MVC WEBAPI I follow the sample from the webpage http://www.asp.net/mvc/tutorials/hands-on-labs/aspnet-mvc-4-dependency-injection And after to do some modifications, I find a way to inject Filter for Controler.

I used this code in the boostrapper.cs

var container = new UnityContainer();
container.RegisterInstance<IFilterProvider>("FilterProvider", new    FilterProvider(container));
container.RegisterInstance<IActionFilter>("LogActionFilter", new TraceActionFilter());

I add this class FilterProvider

public class FilterProvider : IFilterProvider
{
    private IUnityContainer container;

    public FilterProvider(IUnityContainer container)
    {
        this.container = container;
    }

    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        foreach (IActionFilter actionFilter in this.container.ResolveAll<IActionFilter>())
        {
            yield return new Filter(actionFilter, FilterScope.First, null);
        }
    }
}

So each time a method is called by called a class which implemented Controller, I can see the code called in the class TraceActionFilter.

public class TraceActionFilter : IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        filterContext.HttpContext.Trace.Write("OnActionExecuted");
        filterContext.HttpContext.Trace.Write("Action " + filterContext.ActionDescriptor.ActionName);
        filterContext.HttpContext.Trace.Write("Controller " + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName);
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
                filterContext.HttpContext.Trace.Write("OnActionExecuting");
                filterContext.HttpContext.Trace.Write("Action " + filterContext.ActionDescriptor.ActionName);
                filterContext.HttpContext.Trace.Write("Controller " + filterContext.ActionDescriptor.ControllerDescriptor.ControllerName);
    }
} 

But I don't find on the web, any sample or right way permitting to do the same thing : inject filter for add the same behavior about the WebApi. The only way find is to add manually a filter by using tag, not used the dependency injection. Can you provide any help?

Best regards, Alexandre

[UPDATE AFTER THE FIRST ANSWER] I launch the command Install-Package Unity.AspNet.WebApi to permit to access to UnityConfig. I add in the global.asax

    protected void Application_Start()
    {
        Bootstrapper.Initialise();
        UnityWebApiActivator.Start();
        ConfigureApi(GlobalConfiguration.Configuration); //line added

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

I add in the method ConfigureApi()

    void ConfigureApi(HttpConfiguration config)
    {
        var unity = new UnityContainer();
        unity.RegisterType<ProductsApiController>();
        unity.RegisterType<CategoriesApiController>();

        unity.RegisterType<IProductService, ProductService>(
            new HierarchicalLifetimeManager());
        unity.RegisterType<IProductsDatabase, ProductsDatabase>(
             new HierarchicalLifetimeManager());

        unity.RegisterType<ICategorieService, CategorieService>(
            new HierarchicalLifetimeManager());
        unity.RegisterType<ICategoriesDatabase, CategoriesDatabase>(
             new HierarchicalLifetimeManager());

        unity.RegisterType<ILogProvider, ElmahProvider>(
             new HierarchicalLifetimeManager());

        unity.RegisterType<IRootController, RootController>(
            new HierarchicalLifetimeManager());

        config.DependencyResolver = new IoCContainer(unity);

        //ADDED PARTS
        var providers = GlobalConfiguration.Configuration.Services.GetFilterProviders().ToList();
        config.Services.Add(
            typeof(System.Web.Http.Filters.IFilterProvider),
            new Filter2Provider(UnityConfig.GetConfiguredContainer()));

        var defaultprovider = providers.First(p => p is System.Web.Http.Filters.ActionDescriptorFilterProvider);
        config.Services.Remove(typeof(System.Web.Http.Filters.IFilterProvider), defaultprovider);            
    }

When I call the method ...api/categoriesapi/GetAll The breakPoint in TraceActionFilter is not called.

any idea? I continu to search.

like image 469
user2416437 Avatar asked Aug 24 '26 04:08

user2416437


1 Answers

You will need to create a custom System.Web.Http.Filters.FilterProvider (be aware that MVC has classes with the same names in a different namespace):

public class UnityActionFilterProvider 
    : System.Web.Http.Filters.ActionDescriptorFilterProvider, 
      System.Web.Http.Filters.IFilterProvider
{
    private readonly IUnityContainer container;

    public UnityActionFilterProvider(IUnityContainer container)
    {
        this.container = container;
    }

    public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, 
        HttpActionDescriptor actionDescriptor)
    {
        foreach (IActionFilter actionFilter in container.ResolveAll<IActionFilter>())
        {
            // TODO: Determine correct FilterScope
            yield return new FilterInfo(actionFilter, FilterScope.Global);
        }
    }
}

Then you will need to set the filter provider at startup:

var providers = 
    GlobalConfiguration.Configuration.Services.GetFilterProviders().ToList();

GlobalConfiguration.Configuration.Services.Add(
    typeof(System.Web.Http.Filters.IFilterProvider),
    new UnityActionFilterProvider(UnityConfig.GetConfiguredContainer()));

var defaultprovider = providers.First(p => p is ActionDescriptorFilterProvider);

GlobalConfiguration.Configuration.Services.Remove(
    typeof(System.Web.Http.Filters.IFilterProvider), 
    defaultprovider);

You should use the above with the Unity bootstrapper for ASP.NET Web API

A similar question using attributes: ASP.NET Web API - Inject Dependencies Into ActionFilterAttribute

Since you are using the container to maintain the list of Filters then you could just register the FilterInfo directly instead of IActionFilter.

like image 59
Randy supports Monica Avatar answered Aug 26 '26 20:08

Randy supports Monica



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!