Reputation: 3874
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
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
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