Overriding filters in ASP.NET Web API vNext

· 498 words · 3 minutes to read

One of the more annoying issues in the current version of ASP.NET Web API, is that it’s very difficult to override global/controller scoped filters at action level.

Perhaps you may have logging functionality or authorization filters, that you want to apply globally, and only exclude certain actions from participating in this process.

This problem is remedied in Web API vNext (version 5), and you can try that out with nightly builds.

Getting started 🔗

To be able to follow this article, you need to install Web API from the nightly builds feed.

http://www.myget.org/F/aspnetwebstacknightly/  

Then you simply install the pre release version:

install-package microsoft.aspnet.webapi.selfhost -pre  

This should bring in the following packages and versions:

<?xml version="1.0" encoding="utf-8"?> <packages> <package id="Microsoft.AspNet.WebApi.Client" version="5.0.0-rtm-130616" targetFramework="net45" /> <package id="Microsoft.AspNet.WebApi.Core" version="5.0.0-rtm-130616" targetFramework="net45" /> <package id="Microsoft.AspNet.WebApi.SelfHost" version="5.0.0-rtm-130616" targetFramework="net45" /> <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" /> </packages> ```

The override functionality was added to Web API (and actually, earlier on to MVC too) on March 15 with [this commit][1].

### Overriding filters in ASP.NET Web API

Suppose you have a random filter - it doesn't really matter what it does - for the demo purposes it will just write to debug output:

```csharp
public class MyFilter : ActionFilterAttribute  
{  
public override void OnActionExecuting(HttpActionContext actionContext)  
{  
Debug.WriteLine("Executing My Filter!");  
}  
}  

In vNext you can apply this filter globally (or at controller level), and then exclude a specific action from having this filter participate in its specific pipeline.

For example, in WebApiConfig.cs we register it globally:

config.Filters.Add(new MyFilter());  

Then, in an individual action, we tell he pipeline to ignore all wider-scoped filters by using the new OverrideActionFiltersAttribute:

public class TestController : ApiController  
{  
public string Get()  
{  
return "Hello world!";  
}

[OverrideActionFilters]  
public string Get(int id)  
{  
return "Hello world " + id;  
}  
}  

Overriding comes in four flavours:

    • action filter (IActionFilter), through OverrideActionFiltersAttribute
    • authentication filter (IAuthenticationFilter), through OverrideAuthenticationAttribute
    • authorization filter (IAuthorizationFilter), through OverrideAuthorizationAttribute
    • exception filter (IExceptionFilter), through OverrideExceptionAttribute

Each is rather self explanatory, and allows you to break up the pipeline for a specific type of filter. Unfortunately the mechanism is not extensible, and you cannot override a filter by type name (for example you can override all action filters, but if you have multiple action filters, you cannot target a single filter type only).

What happens internally, is that Web API pipeline will select which filters are applicable to your action by comparing the filters scope and check whether any of the filters implements IOverrideFilter interface, and if that’s the case, which of the four mentioned above filter groups it is relevant for. In case there’s a match, the filters with wider scope are being excluded from processing.

Overall this is a very useful functionality. I have been thinking of porting it to existing, stable Web API version (v4 RTM). However, the new update to Web API should come very soon, so it would be a bit of a wasted effort.

Until then you can always grab the functionality from the nightlies and replace your System.Web.Http.

About


Hi! I'm Filip W., a software architect from Zürich 🇨🇭. I like Toronto Maple Leafs 🇨🇦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁢󠁳󠁣󠁴󠁿.

You can find me on Github, on Mastodon and on Bluesky.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP