• 0

ActionFilterAttribute for duplicate submits & throttling?


Question

Looking for feedback,

Researched this,

http://stackoverflow.com/questions/33969/best-way-to-implement-request-throttling-in-asp-net-mvc

 

[Throttle(Name="TestThrottle", Message = "You must wait {n} seconds before accessing this url again.", Seconds = 5)]
public ActionResult TestThrottle()
{
    return Content("TestThrottle executed");
}
Which is nice, but you have to specify the name for the key, which gets generated like this,

var key = string.Concat(Name, "-", c.HttpContext.Request.UserHostAddress);
So I modified it so the key is auto generated,

 

        public override void OnActionExecuting(ActionExecutingContext c)
        {
            // Generate Key
            var key = c.RouteData
                .Values
                .Aggregate(
                    new StringBuilder(c.HttpContext.Request.UserHostAddress).Append(';').Append("SimpleThrottle").Append(';'),
                    (sb, x) => sb.Append(x.Value).Append('/'),
                    sb => sb.ToString());

I am wondering if doing this is sane, or is there a chance it can fail?

Next up,

I wanted to prevent duplicate requests to a controller when the data is the same (for example to prevent multiple votes from the same IP for an anonymous internet poll).

This is what I pulled out of my hind quarters,

        private static bool CompareParameters(IDictionary<string, object> one, IDictionary<string, object> two)
        {
            foreach (var kv in one)
            {
                if (two[kv.Key] != kv.Value)
                {
                    return false;
                }
            }

            return true;
        }

        public override void OnActionExecuting(ActionExecutingContext c)
        {
            // Generate Key
            var key = c.RouteData
                .Values
                .Aggregate(
                    new StringBuilder(c.HttpContext.Request.UserHostAddress).Append(';').Append("PreventDuplicateSubmits").Append(';'),
                    (sb, x) => sb.Append(x.Value).Append('/'),
                    sb => sb.ToString());

            // Get Parameters
            var parameters = c.ActionParameters;

            // Get Old Parameters
            var oldParameters = HttpRuntime.Cache[key] as IDictionary<string, object>;

            // Save Old Parameters
            HttpRuntime.Cache.Add(key,
                parameters,
                null,
                DateTime.Now.AddDays(1),
                Cache.NoSlidingExpiration,
                CacheItemPriority.Low,
                null);

            // No Old Parameters -> All OK
            if (oldParameters == null)
            {
                return;
            }

            if (CompareParameters(oldParameters, parameters))
            {
                c.Result = new JsonResult() 
                    {
                        JsonRequestBehavior = System.Web.Mvc.JsonRequestBehavior.AllowGet, 
                        Data = new JsonError() { Error = "You already submitted this once" } 
                    };
            }
        }
I am also thinking about querying the request for a cookie and adding it to the response just for an extra layer of protection.

I am planning on using these two attributes together (most of the time), with Captcha & CRSF, on POST only ActionResults which give back JSON.

Is there any way that route data / request / response / action parameters can be null?

And how would you go onto specifying the parameters that need to be checked (if not all of them)? [PrevetDuplicateRequests(Params = "Foo,Bar")] ?

Edited by _Alexander
Link to comment
Share on other sites

0 answers to this question

Recommended Posts

There have been no answers to this question yet

This topic is now closed to further replies.