19

I have got a problem with WebApi throwing an exception here in my code:

public class WebApiAuthenticationHandler : DelegatingHandler
    {
        private const string AuthToken = "AUTH-TOKEN";

        protected override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {                  
            var requestAuthTokenList = GetRequestAuthTokens(request);
            if (ValidAuthorization(requestAuthTokenList))
            {
                // EXCEPTION is occuring here!....
                return base.SendAsync(request, cancellationToken);
            }

            /*
            ** This will make the whole API protected by the API token.
            ** To only protect parts of the API then mark controllers/methods
            ** with the Authorize attribute and always return this:
            **
            ** return base.SendAsync(request, cancellationToken);
            */
            return Task<HttpResponseMessage>.Factory.StartNew(
                () =>
                {
                    var resp = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                    {
                        Content = new StringContent("Authorization failed")
                    };

                    //var resp = new HttpResponseMessage(HttpStatusCode.Unauthorized);                                                                                   
                    //resp.Headers.Add(SuppressFormsAuthenticationRedirectModule.SuppressFormsHeaderName,"true");
                    return resp;
                });
        }

The exception is happening on the line:

base.SendAsync(request, cancellationToken);

I haven't a clue how to fix this. I have the following in my route table:

    routes.MapHttpRoute("NoAuthRequiredApi", "api/auth/", new { Controller = "Auth" });
    routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }, null, new WebApiAuthenticationHandler());

The route this happens on is the DefaultApi route. Any help greatly appreciated....

jaffa
  • 26,770
  • 50
  • 178
  • 289

3 Answers3

41

Found the answer here and an example handler here.

You need to set the InnerHandler you want the request passed on to.

Simply add this to your constructor:

public class WebApiAuthenticationHandler : DelegatingHandler
{
    public WebApiAuthenticationHandler(HttpConfiguration httpConfiguration)
    {
        InnerHandler = new HttpControllerDispatcher(httpConfiguration); 
    }

And pass in a reference to GlobalConfiguration when creating a new instance:

routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }, null, WebApiAuthenticationHandler(GlobalConfiguration.Configuration));
c24w
  • 7,421
  • 7
  • 39
  • 47
Mark Jones
  • 12,156
  • 2
  • 50
  • 62
3

Sometimes you should check the RESTful Url you request if it really does exist in your controller. I have ever encountered this kind of exception which was caused by the wrong URL match. thanks.

Joe.wang
  • 11,537
  • 25
  • 103
  • 180
1

As mentioned (by Daniel Roth) in the link from the currently top-voted answer, your chain of handlers must not terminate with a DelegatingHandler.

A DelegatingHandler “delegates” the send call to an inner handler provided using the InnerHandler property. A DelegatingHandler is used to chain together message handlers in a Russian doll model. The error message is saying that the InnerHandler was not provided. Typically on the client you want the inner most handler to be an HttpClientHandler which will put the request on the wire and deal with the response.

The easiest way to resolve the error is to set up the InnerHandler using the constructor overload like this:

public class CustomHandler : DelegatingHandler
{
    public CustomHandler()
        : base(new HttpClientHandler())
    {
    }
}

It is not necessary to pass in an HttpConfiguration and wrap it in an HttpControllerDispatcher.

David Peden
  • 17,596
  • 6
  • 52
  • 72