Search code examples
c#rate-limiting.net-7.0

How to set up a .NET 7 C# rate limiter per user if the user id is stored ONLY in the entity in the request body?


There is an API that accepts an entity with a previously unknown ID. I need to configure the rate limiter so that entities with the same ID get into the queue. I figured out how to create a window and a queue. How to make a separate queue for each ID?

The entity is a JSON file. The ID is inside the file.

The following is written, but this forms one queue:

services.AddRateLimiter(options => options
            .AddFixedWindowLimiter(policyName: "UserPolicy", options =>
            {
                options.PermitLimit = 1;
                options.Window = TimeSpan.FromSeconds(10);
                options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
                options.QueueLimit = 3;
            }));

Solution

  • You can try using PartitionedRateLimiter. Something along these lines (not tested):

    builder.Services.AddRateLimiter(options =>
    {
        options.AddPolicy("myRateLimiter1", context =>
        {
            var request = context.Request;
            var partitionKey = "";
            if (request.Method == HttpMethods.Post && request.ContentLength > 0)
            {
                request.EnableBuffering();
                var buffer = new byte[Convert.ToInt32(request.ContentLength)];
                request.Body.Read(buffer, 0, buffer.Length);
                //get body string here...
                var requestContent = Encoding.UTF8.GetString(buffer);
                // get partition key here... partitionKey = ... 
                request.Body.Position = 0;  //rewinding the stream to 0
            }
            return RateLimitPartition.GetFixedWindowLimiter(
                partitionKey: partitionKey,
                factory: partition => new FixedWindowRateLimiterOptions
                {
                    PermitLimit = 1,
                    Window = TimeSpan.FromSeconds(10),
                    QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                    QueueLimit = 3
                });
        });
    });
    

    Though I would suggest to consider passing Id in some other way (headers) or resolve the limiter on the handler/BL level.