John Dorean
John Dorean

Reputation: 3874

Returning "429 Too Many Requests" from action attribute

I'm writing a class which I can use as an attribute on my ASP.NET Web API actions which will rate limit users based on their IP address.

The logic of the class works fine, and its basic structure looks like:

public class ThrottleAttribute : ActionFilterAttribute
{

    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        // Do various logic to determine if we should respond with a 429

        base.OnActionExecuting(actionContext);
    }
}

And I'm using it on my controller actions by adding the [Throttle] annotation above the method definition.

Somewhere in the OnActionExecuting method I want to return a response with the 429 HTTP code. From looking at other SO posts (this one for example) it seems I can do that with something like the following:

actionContext.Response = actionContext.Request.CreateResponse(
            HttpStatusCode.Conflict, 
            Message.Replace("{n}", Seconds.ToString())
        );

When I try to use this code I get the following error:

'System.Net.Http.HttpRequestMessage' does not contain a definition for 'CreateResponse' and no extension method 'CreateResponse' accepting a first argument of type 'System.Net.Http.HttpRequestMessage' could be found (are you missing a using directive or an assembly reference?)

Obviously, the CreateResponse method doesn't exist on HttpRequestMessage, but I don't know how else to return a custom response to tell the user they've hit their rate limit. I also tried this:

actionContext.Response.StatusCode = HttpStatusCode.BadRequest;

But that also resulted in an error about an Object reference not being set to an instance of an object.

How do I return a 429 Too Many Requests response from my class, or failing that, just a Bad Request response?

Upvotes: 4

Views: 11865

Answers (2)

Paul Kearney - pk
Paul Kearney - pk

Reputation: 5533

You could throw an HttpResponseException:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    if (TooManyRequests()) {
        throw new HttpResponseException((HttpStatusCode)429);
    }
    base.OnActionExecuting(filterContext);
}

You can cast the 429 to an HttpStatusCode even though that value isn't part of the enum (from C# language specification 5.0).

Upvotes: 7

Stephen
Stephen

Reputation: 411

Try setting the Response of the context's HttpContext.Response property as well as settings the Result property. By settings the result, it will then force no further subsequent filters to get called.

An example would be as follows:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    filterContext.HttpContext.Response.StatusCode = 429; // Too many requests
    filterContext.Result = new ContentResult
    {
        Content = "Too Many Requests"
    };
    base.OnActionExecuting(filterContext);
}

Upvotes: 2

Related Questions