0

There are two excellent throttling/rate-limiting libraries for ASP.NET. There is the MVC throttling library, MvcThrottle, and the Web API throttling library, WebApiThrottle.

I was using the two together harmoniously until I needed to apply rate limiting to the security token endpoint, which isn't provided by Web API, but by OWIN. Fortunately, WebApiThrottle has a middleware throttler, which throttles anything outside of Web API.

Unfortunately, after I applied the middleware throttler, I started getting InvalidCastException errors after visiting pages on my website. What is going on and how do I fix it?

Kevin Peter
  • 306
  • 2
  • 7

1 Answers1

2

Well, I found that the problem was that the middleware throttler was handling any request to a web page and the MVC throttler was also handling any request to a web page. Each throttler was reading and writing to the same cache, but when they read the value from the cache, one was attempting to cast the object to a WebApiThrottle object and the other was attempting to cast the object to an MvcThrottle object. That was no good.

So I fixed the issue by giving the middleware throttling its own carefully-constructed policy. By default, the policy doesn't throttle anything. Then I add a rule to specifically apply throttling to the security token endpoint.

That way the security token endpoint is still rate limited, but the web page throttling is handled entirely by the MVC throttling attributes. The middleware throttler will ignore anything that isn't overridden in its rules list because the default rate limits are all 0, meaning no throttling. The exception goes away and all is well.

Here's what the middleware throttling policy class looks like:

public class MiddlewareThrottlingPolicy : ThrottlePolicy
{
    /// <summary>
    /// Creates the middleware throttling policy
    /// </summary>
    public MiddlewareThrottlingPolicy()
    {
        //Everything is unthrottled by default. We don't have to do anything to achieve that

        //We're throttling by endpoint
        EndpointThrottling = true;

        //Add the endpoints that get different throttling
        RateLimits policySettings = new RateLimits
        {
            PerSecond = 30,
            PerMinute = 100,
            PerHour = 200,
            PerDay = 500,
            PerWeek = 0
        };

        EndpointRules = new Dictionary<string, RateLimits>
        {
            { "/api/authentication/token", policySettings }
        };
    }
}

In the real application, I load the rate limits from configuration settings, but I simplified it here.

Here's how I apply the middleware throttling policy when starting up the application:

app.Use(typeof(ThrottlingMiddleware),
            new MiddlewareThrottlingPolicy(),
            new PolicyCacheRepository(),
            new CacheRepository(),
            null,
            null);
Kevin Peter
  • 306
  • 2
  • 7
  • 1
    This answer was very helpful and saved me a lot of time. The only thing i would add is if you're using Identity/OWIN with bearer tokens; add the `app.Use(...)` as stated in the answer before the `app.UseOAuthBearerTokens(OAuthOptions);` call otherwise the throttle wont get called. – Morph Jul 24 '18 at 15:51