C# – Exception : The given filter must implement one or more of the following filter interfaces when implementing custom filter in WebAPI 2

asp.net-web-apic

I am trying to build my custom filter for authentication, but I am running on this problem when I try to run my WebAPI solution:

The given filter instance must implement one or more of the following
filter interfaces: System.Web.Mvc.IAuthorizationFilter,
System.Web.Mvc.IActionFilter, System.Web.Mvc.IResultFilter,
System.Web.Mvc.IExceptionFilter,
System.Web.Mvc.Filters.IAuthenticationFilter.

The error occurs in FilterConfig class:

public class FilterConfig
{
   public static void RegisterGlobalFilters(GlobalFilterCollection filters)
   {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new AuthAttribute());
   }
}

In the line where I am trying to add AuthAttribute to filters.

This is whole AuthAttribute class:

using Examino.Business;
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IdentityModel;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;

namespace Examino.API.Filters
{
    public class AuthAttribute : AuthorizeAttribute
    {
        public ITokenProviderService TokenProviderService { get; set; }

        public override void OnAuthorization(HttpActionContext actionContext)
        {
            SetDependencies(actionContext);

            if (!IsAuthorized(actionContext) && !SkipAuthorization(actionContext))
            {
                if (Authenticate(actionContext) == AuthenticationErrors.UNAUTHORIZED)
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized,
                        new HttpResponseMessage(HttpStatusCode.Unauthorized));
                }
                else if (Authenticate(actionContext) == AuthenticationErrors.TOKEN_EXPIRED)
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized,
                        //token expired status code?
                        new HttpResponseMessage(HttpStatusCode.Unauthorized));
                }
            }
        }

        private void SetDependencies(HttpActionContext actionContext)
        {
            var requestScope = actionContext.Request.GetDependencyScope();

            if (TokenProviderService == null)
            {
                TokenProviderService = requestScope.GetService(typeof(ITokenProviderService)) as ITokenProviderService;
            }
        }

        private AuthenticationErrors Authenticate(HttpActionContext actionContext)
        {
            IEnumerable<string> authHeaderValues;
            actionContext.Request.Headers.TryGetValues("Authorization", out authHeaderValues);

            try
            {
                if (authHeaderValues != null)
                {
                    string bearerToken = authHeaderValues.ElementAt(0);
                    string token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;

                    Thread.CurrentPrincipal = TokenProviderService.ValidateJwtToken(token);
                    if (Thread.CurrentPrincipal != null)
                    {
                        return AuthenticationErrors.AUTHORIZED;
                    }
                }
            }
            catch (SecurityTokenExpiredException)
            {
                return AuthenticationErrors.TOKEN_EXPIRED;
            }
            catch (Exception)
            {
                return AuthenticationErrors.UNAUTHORIZED;
            }

            return AuthenticationErrors.UNAUTHORIZED;
        }

        private bool SkipAuthorization(HttpActionContext actionContext)
        {
            Contract.Assert(actionContext != null);

            return actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any()
                || actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
        }

        private enum AuthenticationErrors
        {
            UNAUTHORIZED,
            TOKEN_EXPIRED,
            AUTHORIZED
        }
    }
}

As you can see it inherits from AuthorizeAttribute class.

Here is a stack trace:

[InvalidOperationException: The given filter instance must implement
one or more of the following filter interfaces:
System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter,
System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter,
System.Web.Mvc.Filters.IAuthenticationFilter.]
System.Web.Mvc.GlobalFilterCollection.ValidateFilterInstance(Object
instance) +403
System.Web.Mvc.GlobalFilterCollection.AddInternal(Object filter,
Nullable`1 order) +26
System.Web.Mvc.GlobalFilterCollection.Add(Object filter) +31
Examino.API.FilterConfig.RegisterGlobalFilters(GlobalFilterCollection
filters) in C:\examino\src\Examino.API\App_Start\FilterConfig.cs:12
Examino.API.WebApiApplication.Application_Start() in
C:\examino\src\Examino.API\Global.asax.cs:22

[HttpException (0x80004005): The given filter instance must implement
one or more of the following filter interfaces:
System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter,
System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter,
System.Web.Mvc.Filters.IAuthenticationFilter.]
System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext
context, HttpApplication app) +540
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr
appContext, HttpContext context, MethodInfo[] handlers) +186
System.Web.HttpApplication.InitSpecial(HttpApplicationState state,
MethodInfo[] handlers, IntPtr appContext, HttpContext context) +172
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr
appContext, HttpContext context) +402
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr
appContext) +343

[HttpException (0x80004005): The given filter instance must implement
one or more of the following filter interfaces:
System.Web.Mvc.IAuthorizationFilter, System.Web.Mvc.IActionFilter,
System.Web.Mvc.IResultFilter, System.Web.Mvc.IExceptionFilter,
System.Web.Mvc.Filters.IAuthenticationFilter.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +539
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context)
+125 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest
wr, HttpContext context) +731

Even if I implement for example IAuthenticationFilter interface same exception is thrown anyhow.

Did someone had a similar exception? I was unable to find something more about this in WebAPI.

Best Answer

Solved: The problem was place of registration of Filter. In MVC you would register filters in FilterConfing class, but in WebAPI you are doing this in Register method of WebApiConfig class like this:

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

Everything works now.

Related Topic