AspNetCoreRateLimit icon indicating copy to clipboard operation
AspNetCoreRateLimit copied to clipboard

Refactor DistributedCacheRateLimitStore to Use System.Text.Json Instead of Newtonsoft.Json

Open jmbryan4 opened this issue 11 months ago • 0 comments

The current implementation of DistributedCacheRateLimitStore uses Newtonsoft.Json for serialization and deserialization: DistributedCacheRateLimitStore.cs

System.Text.Json is faster and more memory-efficient than Newtonsoft.Json and removes reliance on Newtonsoft.Json package, making the project more aligned with .NET’s built-in features.

Proposed Changes:

using System;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;

namespace AspNetCoreRateLimit.Store;

public class DistributedCacheRateLimitStore<T> : IRateLimitStore<T>
{
    private readonly IDistributedCache _cache;

    private static readonly JsonSerializerOptions _jsonOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
    };

    public DistributedCacheRateLimitStore(IDistributedCache cache)
    {
        ArgumentNullException.ThrowIfNull(cache);
        _cache = cache;
    }

    public Task SetAsync(string id, T entry, TimeSpan? expirationTime = null, CancellationToken cancellationToken = default)
    {
        var options = new DistributedCacheEntryOptions();
        if (expirationTime.HasValue)
        {
            options.SetAbsoluteExpiration(expirationTime.Value);
        }

        return _cache.SetStringAsync(id, JsonSerializer.Serialize(entry, _jsonOptions), options, cancellationToken);
    }

    public async Task<bool> ExistsAsync(string id, CancellationToken cancellationToken = default)
    {
        var stored = await _cache.GetStringAsync(id, cancellationToken);
        return !string.IsNullOrEmpty(stored);
    }

    public async Task<T> GetAsync(string id, CancellationToken cancellationToken = default)
    {
        var stored = await _cache.GetStringAsync(id, cancellationToken);
        return !string.IsNullOrEmpty(stored) ? JsonSerializer.Deserialize<T>(stored, _jsonOptions) : default;
    }

    public Task RemoveAsync(string id, CancellationToken cancellationToken = default) => _cache.RemoveAsync(id, cancellationToken);
}

jmbryan4 avatar Feb 27 '25 16:02 jmbryan4