All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
❗ If you are updating from version
1.0.*
, this is a BREAKING change. In such a case, read the2.0.0-RC.1
change log below. -
🌟 All code uses
async
to avoid thread pool starvation in high-load scenarios. Thanks to @dimmy-timmy for implementing it (#47) 🙏. -
🌟The
IdempotentAPI.MinimalAPI
is introduced to useIdempotentAPI
in Minimal APIs. Just add theIdempotentAPIEndpointFilter
in your endpoints. Thank to @hartmark for implementing it (#45) 🙏.-
app.MapPost("/example", ([FromQuery] string yourParam) => { return Results.Ok(new ResponseDTOs()); }) .AddEndpointFilter<IdempotentAPIEndpointFilter>();
-
-
✅ GitHub actions configuration added to run CI build and test on pull requests. Thanks to @dimmy-timmy 💪.
-
✅ Integration Tests are improved to run on CI using
WebApplicationFactory
. Thanks to @dimmy-timmy 💪.
-
✅ There were two cases in which the IdempotentAPI didn't respond as expected. For that reason, we made some corrections and improvements. Thanks to @kvuong for reporting this issue (#37) 💪🙏.
- When the controller returns a non-successful response (4xx, 5xx, etc.), the IdempotentAPI cache the error response. In some cases, maybe we would like this behavior. For that reason, we have added the
CacheOnlySuccessResponses
attribute option to set it per case (default value:True
). - When an exception occurs in the controller, the IdempotentAPI stack is in the in-flight mode by returning a
409 Conflict
response in the subsequent requests. Thus, we have made a fix to remove the in-flight request on exceptions. - However, as long as a request is in inflight mode (running), all other requests will still get a
409 Conflict
response. For that reason, we should be careful when configuring the request timeout.
- When the controller returns a non-successful response (4xx, 5xx, etc.), the IdempotentAPI cache the error response. In some cases, maybe we would like this behavior. For that reason, we have added the
-
✅ There was a bug when a request body was big enough (e.g., 30kb+). The cache couldn't appropriately be fetched because of a different hash string. Thanks, @bernardiego, for taking the time to report and provide a fix for this issue (#38) 🙏❤.
-
✅ Fix a bug in the reconstruction of the
ObjectResult
responses. Thanks to @MohamadTahir for reporting this issue (#39) and providing a workaround 🙏.
-
❗ The
CacheOnlySuccessResponses
attribute option is included (default value:True
) to cache only 2xx HTTP responses. -
🌟 Support idempotency in a Cluster Environment (i.e., a group of multiple server instances) using Distributed Locks. Refactoring has been performed to include additional abstractions and distinguish the Caching (
IIdempotencyCache
), Distributed Locks (IDistributedAccessLockProvider
), and Accessing of them (IIdempotencyAccessCache
). Thanks to @Rast1234 for showing the need for this feature 💪🙏. Currently, we support the following two implementations.- 🌟 The
DistributedLockTimeoutMilli
attribute option is included to configure the time the distributed lock will wait for the lock to be acquired (in milliseconds).
Supported Technologies DI Registration samcook/RedLock.net Redis Redlock services.AddRedLockNetDistributedAccessLock(redisEndpoints);
madelson/DistributedLock Redis, SqlServer, Postgres and many more. services.AddMadelsonDistributedAccessLock();
- 🌟 The
-
❗ IMPORTANT: We should register the IdempotentAPI Core services.
-
services.AddIdempotentAPI();
-
-
❗ IMPORTANT: The
IdempotentAPI.Cache
has been renamed toIdempotentAPI.Cache.Abstractions
. So, you should remove theIdempotentAPI.Cache
NuGet package and use theIdempotentAPI.Cache.Abstractions
when needed. -
Dependency Updates
- Update
Newtonsoft.Json
from12.0.3
to13.0.1
. - Update
Microsoft.Extensions.Caching.Abstractions
from3.1.21
to6.0.0
. - Update
Microsoft.Extensions.DependencyInjection.Abstractions
from3.1.22
to6.0.0
. - Update
ZiggyCreatures.FusionCache
from0.1.7
to0.13.0
. - Update
ZiggyCreatures.FusionCache.Serialization.NewtonsoftJson
from0.1.7
to0.13.0
.
- Update
- Idempotency did not work as expected when the return type on the controller action was a custom object and not an
ActionResult
. (#33) - Thanks to @MohamadTahir for reporting and investigating this issue 🙏.
-
📝 This
CHANGELOG.md
file quickly shows the notable changes we have performed between the project's releases (versions). -
🌟 Support for ASP.NET Core 5.0 and 6.0 by stopping using the obsolete
BinaryFormatter
and using theNewtonsoft JsonSerializer
(recommended action). -
🌟 Define the
IIdempotencyCache
interface to decide which caching implementation is appropriate in each use case. Currently, we support the following two implementations. However, you can use your implementation 😉.Support Concurrent Requests Primary Cache 2nd-Level Cache Advanced features IdempotentAPI.Cache.DistributedCache (Default) ✔️ IDistributedCache ❌ ❌ IdempotentAPI.Cache.FusionCache ✔️ Memory Cache ✔️
(IDistributedCache)✔️ -
🌟 Support the FusionCache, which provides high performance and robust cache with an optional distributed 2nd layer and some advanced features.
FusionCache
also includes some advanced features like a fail-safe mechanism, cache stampede prevention, fine grained soft/hard timeouts with background factory completion, extensive customizable logging, and more.
-
⚙ Configure the logging level of the
IdempotentAPI
logs that we would like to keep. For example, as we can see in the following JSON, we can setIdempotentAPI.Core.Idempotency
in theappsettings.json
.{ "Logging": { "LogLevel": { "Default": "Information", "IdempotentAPI.Core.Idempotency": "Warning" } } }
- The Logger name is changed from
IdempotencyAttributeFilter
toIdempotency
. Thus, in theappsettings.json
file we should configure the logging level using the nameIdempotentAPI.Core.Idempotency
e.g.,"IdempotentAPI.Core.Idempotency": "Information"
. - Dependencies of
IdempotentAPI
:- Remove
Microsoft.AspNetCore (2.2.0)
. - Remove
Microsoft.AspNetCore.Mvc.Abstractions (2.2.0)
. - Remove
Microsoft.Extensions.Caching.Abstractions (2.2.0)
. - Update
Newtonsoft.Json
from12.0.2
to12.0.3
.
- Remove
- 🌟 Prevent concurrent requests in our default caching implementation (IdempotentAPI.Cache.DistributedCache).
- @fjsosa for proposing a workaround to use
IdempotentAPI
in ASP.NET Core 5.0 and 6.0 in the meantime (#17) 🙏. - @william-keller for reporting the #23 and #25 issues 🙏❤.
- Issue: An
Invalid character in chunk size error
occurs on the second request when using the Kestrel server (#21). For that purpose, we are not caching theTransfer-Encoding
in the first request (excluded from cache). - Thanks to @apchenjun and @william-keller for reporting and helping solve this issue 💪🙏.
- Handle inflight (concurrent and long-running) requests. In such cases, the subsequent exact requests will get a
409 Conflict
response.
- Issue: Duplication on concurrent requests with the same key (#19).
- Thanks to @lvzhuye and @RichardGreen-IS2 for reporting and fixing the issue 🙏❤.
- A sample project is added (using .NET Core 3.1).
- Issue: Accessing form data throws an exception when the Content-Type is not supported (#14).
- Thanks to @apchenjun for reporting the issue 🙏.
- Support idempotency by implementing an ASP.NET Core attribute (
[Idempotent()]
) by which any HTTP write operations (POST and PATCH) can have effect only once for the given request data. - Use the
IDistributedCache
to cache the appropriate data. In this way, you can register your implementation, such as Memory Cache, SQL Server cache, Redis cache, etc. - Set different options per controller or/and action method via the
Idempotent
attribute, such as:Enabled
(default: true): Enable or Disable the Idempotent operation on an API Controller's class or method.ExpireHours
(default: 24): The cached idempotent data retention period.HeaderKeyName
(default:IdempotencyKey
): The name of the Idempotency-Key header.DistributedCacheKeysPrefix
(default:IdempAPI_
): A prefix for the key names that we will use in theDistributedCache
.