Part of DKNet.AspCore.Idempotency. Implement IIdempotencyKeyStore directly; the shared relational classes are internal. This example inspects the contract and constructs the identity your store receives:
using DKNet.AspCore.Idempotency.Filtering;
using DKNet.AspCore.Idempotency.Store;
Console.WriteLine(typeof(IIdempotencyKeyStore).GetMethods().Length); // 2
var info = new IdempotentKeyInfo
{
Endpoint = "/ORDERS", Method = "POST", IdempotentKey = "order-1"
};
Console.WriteLine(info.CompositeKey); // :POST:/ORDERS:order-1
| Method | Return type | Required behavior |
|---|---|---|
IsKeyProcessedAsync(IdempotentKeyInfo) |
ValueTask<(bool processed, CachedResponse? response)> |
Atomically reserve before returning (false, null). Return (true, null) while in flight, or (true, response) after completion. |
MarkKeyAsProcessedAsync(IdempotentKeyInfo, CachedResponse) |
ValueTask |
Replace the reservation with completion data and honor the intended retention window. |
Use a bounded in-flight reservation, and make reclaim atomic. All shipped stores use status 102 as the reservation sentinel and SHA-256 over CompositeKey. A separate read followed by an unconditional write admits two winners.
CachedResponse requires StatusCode, nullable Body, ContentType, CreatedAt, and nullable ExpiresAt at construction. Its derived IsExpired compares the non-null expiry against UTC now. IdempotentKeyInfo requires Endpoint and Method; Scope defaults empty and IdempotentKey is nullable. The filter validates the key before handing it to the store.
AddIdempotentKey<TStore>(). It is singleton and must support concurrent calls.SafeKey as storage identity.