Wednesday, July 14, 2010

Slow Down Filter for Throttling Requests with ASP.NET MVC




I’ve been looking for a good filter to play with and finally found one today. Basically, I want to slow down requests to prevent people and/or other mechanisms from submitting a form.

I saw a post by the guy’s at stackoverflow.com and ended up using a couple of their ideas in my filter attribute. Stackoverflow’s stops the execution of a request and I only want to slow it down. Generally speaking, I want to deter people/things from attempting to submit multiple times in a row after a specified amount of requests.

So…here’s the filter attribute:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class SlowDownAfterAttribute : ActionFilterAttribute
{
public const string AttemptsExceeded = "AttemptsExceeded";
private readonly int _numberOfAttemptsAllowed;
public string Name { get; set; }

public SlowDownAfterAttribute(int numberOfAttemptsAllowed)
{
_numberOfAttemptsAllowed = numberOfAttemptsAllowed;
}

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData[AttemptsExceeded] =
false;

var key = string.Concat(Name, "-", filterContext.HttpContext.Request.UserHostAddress);
var numberofattempts = Convert.ToInt32(HttpRuntime.Cache[key]);
numberofattempts++;

HttpRuntime.Cache.Insert(key,
numberofattempts,
null,
DateTime.Now.AddMinutes(2),
Cache.NoSlidingExpiration,
CacheItemPriority.Low,
null);

if (numberofattempts <= _numberOfAttemptsAllowed)
return;

filterContext.Controller.ViewData[AttemptsExceeded] =
true;
System.Threading.
Thread.Sleep(numberofattempts * 1000);
}
}

Here’s how you could use it:

[HttpPost, ValidateModel(typeof(Form)), ValidateAntiForgeryToken, SlowDownAfter(5 /*attempts*/)]
public ActionResult Validate(Form form)
{
if (!ModelState.IsValid)
//Display Error

if ((bool)ViewData[SlowDownAfterAttribute.AttemptsExceeded])
//Display Message or something

return View(form);
}

If you want to use the SlowDownAfter() attribute on multiple methods, you’d want to name it like this:

SlowDownAfter(5 /*attempts*/, Name="ValidateForm")

So basically the way this thing works is like this:

  • Sets the AttemptsExceeded flag on the ViewData to false
  • Sets the key (I got the naming convention from the StackOverflow response on stackoverflow.com)
  • Gets the number of attempts from cache
  • Incremements by 1
  • Adds the value to cache with an absolute expiration of now + 2 minutes
  • Checks if number of attempts is less than or equal to the number of attempts allowed
  • If number of attempts allowed was exceeded, it writes the ViewData AttemptsExceeded flag to true and sleeps for the number of attempts in seconds

Let me know what you think. Thanks for reading!


Shout it

kick it on DotNetKicks.com

blog comments powered by Disqus
Related Posts Plugin for WordPress, Blogger...