Request Filtering for ASP.NET Core applications: Part 4 - Extending the Request Filtering Rules

Request Filtering for ASP.NET Core applications: Part 4 - Extending the Request Filtering Rules

Oct 09, 2016     Viewed 8392 times 0 Comments
Posted in #Request Filtering 

This is the forth and the last post of a series in Request Filtering in ASP.NET Core. Last post I showed you how you can use and integrated the implementation API's with ASP.NET Core pipeline. In this post I illustrate how can we extend the Request Filtering rules.

As we saw in the second post of this series that our APIs is built from ground up to be flexible and extensible, so the extensibility is not a tough task, so I will try to illustrate this by building two new request filters.

IP Address Filtering

In this sample I 'll show you how we can filter the request based on the IP address of the user. This is a common scenario that I have seen many times to restrict the access for certain resources using the IP address. For this filter we only need to define the denied IP addresses as an option for this filter, so the other APIs will use it to filter the request.

public class IPAddressOptions : IRequestFilterOptions
{
     public List IPAddresses { get; set; };
}

Then we can implement IPAddressRequestFilter as the following

public class IPAddressRequestFilter : RequestFilter<IPAddressOptions>
{
    public IPAddressRequestFilter() : this(new IPAddressOptions())
    {

    }

    public IPAddressRequestFilter(IPAddressOptions options)
    {
        Options = options;
    }

    public override IPAddressOptions Options { get; }

    public override void ApplyFilter(RequestFilteringContext context)
    {
        var connection = context.HttpContext.Features.Get();
            
        intinue,
    StopFilters
}

Also may we need an options for the request filtering to access all the registered filters.

public class RequestFilteringOptions
{
    public IList Filters { get; } = new List();
}

After that need more three classes one is an extensions for the RequestFilteringOptions and two required for the middleware.

public static class RequestFilteringOptionsExtensions
{
    public static RequestFilteringOptions AddRequestFilter(this RequestFilteringOptions requestFilteringOptions, IRequestFilter filter)
    {
        if (filter == null)
        {
            throw new ArgumentNullException(nameof(filter));
        }

        requestFilteringOptions.Filters.Add(filter);
        return requestFilteringOptions;
    }
}
public class RequestFilteringMiddleware
{
    private readonly RequestDelegate _next;
    private readonly RequestFilteringOptions _options;

    public RequestFilteringMiddleware(
        RequestDelegate next,
        RequestFilteringOptions options)
    {
        if (next == null)
        {
            throw new ArgumentNullException(nameof(next));
        }

        if (options == null)
        {
            throw new ArgumentNullException(nameof(options));
        }

        _next = next;
        _options = options;
    }

    public Task Invoke(HttpContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var requestFilteringContext = new RequestFilteringContext
        {
            HttpContext = context,
            Result = RequestFilteringResult.Continue
        };

        foreach (var filter in _options.Filters)
        {
            filter.ApplyFilter(requestFilteringContext);

            switch (requestFilteringContext.Result)
            {
                case RequestFilteringResult.Continue:
                    break;
                case RequestFilteringResult.StopFilters:
                    return Task.FromResult(0);
                default:
                    throw new ArgumentOutOfRangeException($"Invalid filter termination {requestFilteringContext.Result}");
            }
         }

         return _next(context);
    }
}
public static class RequestFilteringMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestFiltering(this IApplicationBuilder app, RequestFilteringOptions options)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        if (options == null)
        {
            throw new ArgumentNullException(nameof(options));
        }

        return app.UseMiddleware(options);
    }
}

The middleware classes is straightforward for those who writing ASP.NET middleware before, the idea for our middleware is simple, iterate over all the request filtering that have been registered an calling the ApplyFilter which execute the actual filter, after that we gathering the result from each filter and check the Result property in the context to know if we need to go further to the next filter, or the actual filter is applied and no need to keep filtering.

Implementation APIs

Now we are ready to implement the basic request filtering techniques that are available in the IIS. FYI I will dig only into the essentials classes for each type.

Filter based on File Extensions

As we saw in the previous post that file extensions filter have AllowUnlisted, FileExtension and Allowed properties, so we can use our abstraction to define a set of options as the following:

public class FileExtensionsOptions : IRequestFilterOptions
{
     public bool AllowUnlisted { get; set; } = true;

     public IList FileExtens
    
    


Leave a Comment