I'm building an ASP.NET MVC site where I want to limit how often authenticated users can use some functions of the site.
Although I understand how rate-limiting works fundamentally, I can't visualize how to implement it programatically without creating a major code smell.
Can you point me towards a simple yet powerful solution for approaching such a problem, with C# sample code?
If it matters, all of these functions are currently expressed as Actions that only accept HTTP POST
. I may eventually want to implement rate-limiting for HTTP GET
functions as well, so I'm looking for a solution that works for all such circumstances.
Often rate-limiting is applied at a reverse proxy, API gateway, or load balancer before the request reaches the API, so that it can be applied to all requests arriving at a cluster of servers. By handling this at a proxy server, you also avoid excess load being generated on your application servers.
The term Rate-Limiting refers to the broader concept of restricting the request traffic to an API endpoint at any point in time. Throttling is a particular process of applying rate-limiting to an API endpoint. There are other ways an API endpoint can apply rate-limiting. One such way is the use of Request Queues.
To enforce rate limiting, first understand why it is being applied in this case, and then determine which attributes of the request are best suited to be used as the limiting key (for example, source IP address, user, API key). After you choose a limiting key, a limiting implementation can use it to track usage.
If you are using IIS 7 you could take a look at the Dynamic IP Restrictions Extension. Another possibility is to implement this as an action filter:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class RateLimitAttribute : ActionFilterAttribute
{
public int Seconds { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Using the IP Address here as part of the key but you could modify
// and use the username if you are going to limit only authenticated users
// filterContext.HttpContext.User.Identity.Name
var key = string.Format("{0}-{1}-{2}",
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName,
filterContext.ActionDescriptor.ActionName,
filterContext.HttpContext.Request.UserHostAddress
);
var allowExecute = false;
if (HttpRuntime.Cache[key] == null)
{
HttpRuntime.Cache.Add(key,
true,
null,
DateTime.Now.AddSeconds(Seconds),
Cache.NoSlidingExpiration,
CacheItemPriority.Low,
null);
allowExecute = true;
}
if (!allowExecute)
{
filterContext.Result = new ContentResult
{
Content = string.Format("You can call this every {0} seconds", Seconds)
};
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Conflict;
}
}
}
And then decorate the action that needs to be limited:
[RateLimit(Seconds = 10)]
public ActionResult Index()
{
return View();
}
Have a look at Jarrod's answer on how they do this on SO.
StackOverflow MVC Throttling
Some example code as well as explanation on how it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With