Add CacheController and caching support for signatures
Introduced a new `CacheController` to manage cached data for receiver signatures using distributed caching. Added endpoints to save, retrieve, and delete cached signatures. Created a `SignatureCacheRequest` model for caching payloads and a `CacheOptions` class to configure cache settings, including optional expiration. Updated `Program.cs` to bind `CacheOptions` to the `Cache` section in `appsettings.json`. Added a new `Cache` section in `appsettings.json` with a `SignatureCacheExpiration` property, defaulting to `null` (no expiration).
This commit is contained in:
82
EnvelopeGenerator.API/Controllers/CacheController.cs
Normal file
82
EnvelopeGenerator.API/Controllers/CacheController.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Text.Json;
|
||||||
|
using EnvelopeGenerator.API.Options;
|
||||||
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.API.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages cached data for receivers using distributed cache.
|
||||||
|
/// </summary>
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize(Policy = AuthPolicy.Receiver)]
|
||||||
|
public class CacheController(
|
||||||
|
IDistributedCache cache,
|
||||||
|
IOptions<CacheOptions> cacheOptions) : ControllerBase
|
||||||
|
{
|
||||||
|
private const string SignatureCacheKeyPrefix = "signature:91751687-8ae6-4777-bf5f-b8846085e62e:";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores a receiver's signature in cache for the specified envelope.
|
||||||
|
/// </summary>
|
||||||
|
[HttpPost("SignatureCapture/{envelopeKey}")]
|
||||||
|
public async Task<IActionResult> SaveSignature(
|
||||||
|
string envelopeKey,
|
||||||
|
[FromBody] SignatureCacheRequest request,
|
||||||
|
CancellationToken cancel)
|
||||||
|
{
|
||||||
|
var cacheKey = $"{SignatureCacheKeyPrefix}{envelopeKey}";
|
||||||
|
var json = JsonSerializer.Serialize(request);
|
||||||
|
|
||||||
|
var options = cacheOptions.Value.SignatureCacheExpiration.HasValue
|
||||||
|
? new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = cacheOptions.Value.SignatureCacheExpiration.Value }
|
||||||
|
: null;
|
||||||
|
|
||||||
|
await cache.SetStringAsync(cacheKey, json, options ?? new DistributedCacheEntryOptions(), cancel);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a cached signature for the specified envelope.
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("SignatureCapture/{envelopeKey}")]
|
||||||
|
public async Task<IActionResult> GetSignature(string envelopeKey, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
var cacheKey = $"{SignatureCacheKeyPrefix}{envelopeKey}";
|
||||||
|
var json = await cache.GetStringAsync(cacheKey, cancel);
|
||||||
|
|
||||||
|
if (json is null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
var signature = JsonSerializer.Deserialize<SignatureCacheRequest>(json);
|
||||||
|
return Ok(signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a cached signature for the specified envelope.
|
||||||
|
/// </summary>
|
||||||
|
[HttpDelete("SignatureCapture/{envelopeKey}")]
|
||||||
|
public async Task<IActionResult> DeleteSignature(string envelopeKey, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
var cacheKey = $"{SignatureCacheKeyPrefix}{envelopeKey}";
|
||||||
|
await cache.RemoveAsync(cacheKey, cancel);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Request model for caching signature data.
|
||||||
|
/// </summary>
|
||||||
|
public sealed record SignatureCacheRequest(
|
||||||
|
string? DataUrl,
|
||||||
|
string? FullName,
|
||||||
|
string? Position,
|
||||||
|
string? Place);
|
||||||
|
|
||||||
|
|
||||||
18
EnvelopeGenerator.API/Options/CacheOptions.cs
Normal file
18
EnvelopeGenerator.API/Options/CacheOptions.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace EnvelopeGenerator.API.Options;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration options for distributed caching.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class CacheOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration section name in appsettings.json.
|
||||||
|
/// </summary>
|
||||||
|
public const string SectionName = "Cache";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signature cache expiration time.
|
||||||
|
/// If null, signatures will not expire automatically.
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan? SignatureCacheExpiration { get; set; }
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using DigitalData.Core.Abstractions.Security.Extensions;
|
using DigitalData.Core.Abstractions.Security.Extensions;
|
||||||
using EnvelopeGenerator.API.Middleware;
|
using EnvelopeGenerator.API.Middleware;
|
||||||
|
using EnvelopeGenerator.API.Options;
|
||||||
using NLog.Web;
|
using NLog.Web;
|
||||||
using NLog;
|
using NLog;
|
||||||
using DigitalData.Auth.Claims;
|
using DigitalData.Auth.Claims;
|
||||||
@@ -265,6 +266,9 @@ try
|
|||||||
// Localizer
|
// Localizer
|
||||||
builder.Services.AddCookieBasedLocalizer();
|
builder.Services.AddCookieBasedLocalizer();
|
||||||
|
|
||||||
|
// Cache options
|
||||||
|
builder.Services.Configure<CacheOptions>(config.GetSection(CacheOptions.SectionName));
|
||||||
|
|
||||||
// Envelope generator serives
|
// Envelope generator serives
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
builder.Services
|
builder.Services
|
||||||
|
|||||||
@@ -174,6 +174,9 @@
|
|||||||
"Receiver": [],
|
"Receiver": [],
|
||||||
"EmailTemplate": [ "TBSIG_EMAIL_TEMPLATE_AFT_UPD" ]
|
"EmailTemplate": [ "TBSIG_EMAIL_TEMPLATE_AFT_UPD" ]
|
||||||
},
|
},
|
||||||
|
"Cache": {
|
||||||
|
"SignatureCacheExpiration": null
|
||||||
|
},
|
||||||
"MainPageTitle": null,
|
"MainPageTitle": null,
|
||||||
"AnnotationParams": {
|
"AnnotationParams": {
|
||||||
"Background": {
|
"Background": {
|
||||||
|
|||||||
Reference in New Issue
Block a user