diff --git a/PostFundManagement.Api/PostFundManagement.Api.csproj b/PostFundManagement.Api/PostFundManagement.Api.csproj
index df1910a..69d27a8 100644
--- a/PostFundManagement.Api/PostFundManagement.Api.csproj
+++ b/PostFundManagement.Api/PostFundManagement.Api.csproj
@@ -25,8 +25,8 @@
-
-
+
+
@@ -60,8 +60,8 @@
-
-
+
+
diff --git a/PostFundManagement.Api/appsettings.json b/PostFundManagement.Api/appsettings.json
index ca06352..b325942 100644
--- a/PostFundManagement.Api/appsettings.json
+++ b/PostFundManagement.Api/appsettings.json
@@ -1,4 +1,5 @@
{
+ "EnableServiceCaching": true,
"CorsOrigins": [
"https://console.ifri.khongisa.co.za",
"https://localhost:7208"
diff --git a/PostFundManagement.Application/PostFundManagement.Application.csproj b/PostFundManagement.Application/PostFundManagement.Application.csproj
index 3b25ffa..b69904b 100644
--- a/PostFundManagement.Application/PostFundManagement.Application.csproj
+++ b/PostFundManagement.Application/PostFundManagement.Application.csproj
@@ -24,9 +24,9 @@
-
-
-
+
+
+
@@ -36,6 +36,7 @@
+
diff --git a/PostFundManagement.Application/Services/Communications/CommunicationsCacheService.cs b/PostFundManagement.Application/Services/Communications/CommunicationsCacheService.cs
index 1690679..4d98bae 100644
--- a/PostFundManagement.Application/Services/Communications/CommunicationsCacheService.cs
+++ b/PostFundManagement.Application/Services/Communications/CommunicationsCacheService.cs
@@ -4,14 +4,19 @@ using PostFundManagement.Application.Extensions;
using PostFundManagement.Application.Services.Shared;
using PostFundManagement.Domain;
using PostFundManagement.Domain.Models;
+using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Application.Services.Communications;
-public sealed class CommunicationsCacheService(CommunicationsService service, IDistributedCache cache) : ServiceCacheBase, ICommunicationsService
+public sealed class CommunicationsCacheService(CommunicationsService service, IDistributedCache cache,
+ IFeatureManager featureManager) : ServiceCacheBase, ICommunicationsService
{
public async ValueTask> GetApplicantInviteAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetApplicantInviteAsync(applicantUserId, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getapplicantinvite-{applicantUserId}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -31,11 +36,14 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
public async ValueTask> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetApplicantInvitesAsync(applicantUserId, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getapplicantinvites-{applicantUserId}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetApplicantInvitesAsync(applicantUserId, cancellationToken);
@@ -52,6 +60,9 @@ public sealed class CommunicationsCacheService(CommunicationsService service, ID
public async ValueTask> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetInvitesAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getinvites-{pagination.Page}-{pagination.PageSize}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
diff --git a/PostFundManagement.Application/Services/Evidence/EvidenceCacheService.cs b/PostFundManagement.Application/Services/Evidence/EvidenceCacheService.cs
index 51d58c8..57a39d9 100644
--- a/PostFundManagement.Application/Services/Evidence/EvidenceCacheService.cs
+++ b/PostFundManagement.Application/Services/Evidence/EvidenceCacheService.cs
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
using PostFundManagement.Application.Services.Shared;
using PostFundManagement.Domain;
using PostFundManagement.Domain.Models;
+using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Application.Services.Evidence;
-public sealed class EvidenceCacheService(EvidenceService service, IDistributedCache cache) : ServiceCacheBase, IEvidenceService
+public sealed class EvidenceCacheService(EvidenceService service, IDistributedCache cache,
+ IFeatureManager featureManager) : ServiceCacheBase, IEvidenceService
{
public async ValueTask CreateEvidenceAsync(Guid userId, IFormCollection form, IFormFile file, CancellationToken cancellationToken = default) =>
await service.CreateEvidenceAsync(userId, form, file, cancellationToken);
@@ -21,6 +23,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
public async ValueTask> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetEvidenceAsync(evidenceId, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getevidence-{evidenceId}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -42,6 +47,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
public async ValueTask> GetEvidenceFilesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetEvidenceFilesAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getevidencefiles-{pagination.Page}-{pagination.PageSize}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -63,6 +71,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
public async ValueTask> GetEvidenceUrlAsync(string evidenceIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetEvidenceUrlAsync(evidenceIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getevidenceurl-{evidenceIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -84,6 +95,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
public async ValueTask> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetIndicatorAsync(indicatorId, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getindicator-{indicatorId}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -105,6 +119,9 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
public async ValueTask> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetIndicatorsAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getindicators-{pagination.Page}-{pagination.PageSize}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -126,11 +143,14 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
public async ValueTask> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetMilestoneEvidencesAsync(milestoneIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getmilestoneevidences-{milestoneIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetMilestoneEvidencesAsync(milestoneIdHash, cancellationToken);
@@ -147,11 +167,14 @@ public sealed class EvidenceCacheService(EvidenceService service, IDistributedCa
public async ValueTask> GetProjectEvidencesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProjectEvidencesAsync(projectIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprojectevidences-{projectIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetProjectEvidencesAsync(projectIdHash, cancellationToken);
diff --git a/PostFundManagement.Application/Services/Execution/ExecutionCacheService.cs b/PostFundManagement.Application/Services/Execution/ExecutionCacheService.cs
index 5dbbacd..acf9f19 100644
--- a/PostFundManagement.Application/Services/Execution/ExecutionCacheService.cs
+++ b/PostFundManagement.Application/Services/Execution/ExecutionCacheService.cs
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
using PostFundManagement.Application.Services.Shared;
using PostFundManagement.Domain;
using PostFundManagement.Domain.Models;
+using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Application.Services.Execution;
-public sealed class ExecutionCacheService(ExecutionService service, IDistributedCache cache) : ServiceCacheBase, IExecutionService
+public sealed class ExecutionCacheService(ExecutionService service, IDistributedCache cache,
+ IFeatureManager featureManager) : ServiceCacheBase, IExecutionService
{
public async ValueTask ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default) =>
await service.ApproveDisbursementAsync(disbursementIdHash, userId, cancellationToken);
@@ -21,6 +23,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
public async ValueTask> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetDisbursementAsync(disbursementIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getdisbursement-{disbursementIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -42,6 +47,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
public async ValueTask> GetDisbursementsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetDisbursementsAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getdisbursements-{pagination.Page}-{pagination.PageSize}-{pagination.Index}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -63,6 +71,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
public async ValueTask> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetRiskAsync(riskIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getrisk-{riskIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -84,6 +95,9 @@ public sealed class ExecutionCacheService(ExecutionService service, IDistributed
public async ValueTask> GetRisksAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetRisksAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getrisks-{pagination.Page}-{pagination.PageSize}-{pagination.Index}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
diff --git a/PostFundManagement.Application/Services/Governance/GovernanceCacheService.cs b/PostFundManagement.Application/Services/Governance/GovernanceCacheService.cs
index 7292f76..283d047 100644
--- a/PostFundManagement.Application/Services/Governance/GovernanceCacheService.cs
+++ b/PostFundManagement.Application/Services/Governance/GovernanceCacheService.cs
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
using PostFundManagement.Application.Services.Shared;
using PostFundManagement.Domain;
using PostFundManagement.Domain.Models;
+using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Application.Services.Governance;
-public sealed class GovernanceCacheService(GovernanceService service, IDistributedCache cache) : ServiceCacheBase, IGovernanceService
+public sealed class GovernanceCacheService(GovernanceService service, IDistributedCache cache,
+ IFeatureManager featureManager) : ServiceCacheBase, IGovernanceService
{
public async ValueTask CreateOrganisationAsync(CreateOrganisationRequest request, Guid userId, CancellationToken cancellationToken = default) =>
await service.CreateOrganisationAsync(request, userId, cancellationToken);
@@ -18,6 +20,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
public async ValueTask> GetDashboardAsync(CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetDashboardAsync(cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getdashboard").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -39,6 +44,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
public async ValueTask> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetInstrumentsAsync(programmeIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getinstruments").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -60,6 +68,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
public async ValueTask> GetOrganisationAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetOrganisationAsync(organisationIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getorganisation-{organisationIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -81,6 +92,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
public async ValueTask> GetOrganisationsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetOrganisationsAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getorganisations-{pagination.Page}-{pagination.PageSize}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -102,6 +116,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
public async ValueTask> GetPorfoliosAsync(string organisationIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetPorfoliosAsync(organisationIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getportfolios-{organisationIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -123,11 +140,14 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
public async ValueTask> GetPortfolioAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetPortfolioAsync(portfolioIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getportfolio-{portfolioIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetPortfolioAsync(portfolioIdHash, cancellationToken);
@@ -144,11 +164,14 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
public async ValueTask> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetPortfolioProgrammesAsync(portfolioIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getportfolioprogrammes-{portfolioIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetPortfolioProgrammesAsync(portfolioIdHash, cancellationToken);
@@ -165,6 +188,9 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
public async ValueTask> GetProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProgrammesAsync(portfolioIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprogrammes-{portfolioIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
diff --git a/PostFundManagement.Application/Services/Grants/GrantsCacheService.cs b/PostFundManagement.Application/Services/Grants/GrantsCacheService.cs
index 53c091f..2427f04 100644
--- a/PostFundManagement.Application/Services/Grants/GrantsCacheService.cs
+++ b/PostFundManagement.Application/Services/Grants/GrantsCacheService.cs
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
using PostFundManagement.Application.Services.Shared;
using PostFundManagement.Domain;
using PostFundManagement.Domain.Models;
+using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Application.Services.Grants;
-public sealed class GrantsCacheService(GrantsService service, IDistributedCache cache) : ServiceCacheBase, IGrantsService
+public sealed class GrantsCacheService(GrantsService service, IDistributedCache cache,
+ IFeatureManager featureManager) : ServiceCacheBase, IGrantsService
{
public async ValueTask CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default) =>
await service.CreateAwardAsync(request, userId, cancellationToken);
@@ -24,6 +26,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
public async ValueTask> GetAwardAsync(string awardIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetAwardAsync(awardIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getaward-{awardIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -45,6 +50,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
public async ValueTask> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetAwardsAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getawards-{pagination.Page}-{pagination.PageSize}-{pagination.Index}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -66,6 +74,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
public async ValueTask> GetBudgetAsync(string budgetIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetBudgetAsync(budgetIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getbudget-{budgetIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -87,6 +98,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
public async ValueTask> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetBudgetsAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getbudgets-{pagination.Page}-{pagination.PageSize}-{pagination.Index}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -108,6 +122,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
public async ValueTask> GetContractAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetContractAsync(contractIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getctract-{contractIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -129,6 +146,9 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
public async ValueTask> GetContractsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetContractsAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getcontracts-{pagination.Index}-{pagination.PageSize}-{pagination.Page}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -150,15 +170,18 @@ public sealed class GrantsCacheService(GrantsService service, IDistributedCache
public async ValueTask> GetContractUrlAsync(string contractIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetContractUrlAsync(contractIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getcontracturl-{contractIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetContractUrlAsync(contractIdHash, cancellationToken);
- if(result.IsFailed) return result;
+ if (result.IsFailed) return result;
await cache.SetStringAsync(cacheKey, result.Value, cancellationToken);
diff --git a/PostFundManagement.Application/Services/Projects/ProjectCacheService.cs b/PostFundManagement.Application/Services/Projects/ProjectCacheService.cs
index dcab185..6dd75d2 100644
--- a/PostFundManagement.Application/Services/Projects/ProjectCacheService.cs
+++ b/PostFundManagement.Application/Services/Projects/ProjectCacheService.cs
@@ -4,10 +4,12 @@ using PostFundManagement.Application.Extensions;
using PostFundManagement.Application.Services.Shared;
using PostFundManagement.Domain;
using PostFundManagement.Domain.Models;
+using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Application.Services.Projects;
-public sealed class ProjectCacheService(ProjectService service, IDistributedCache cache) : ServiceCacheBase, IProjectService
+public sealed class ProjectCacheService(ProjectService service, IDistributedCache cache,
+ IFeatureManager featureManager) : ServiceCacheBase, IProjectService
{
public async ValueTask CreateActivityAsync(CreateActivityRequest request, Guid userId, CancellationToken cancellationToken = default) =>
await service.CreateActivityAsync(request, userId, cancellationToken);
@@ -21,6 +23,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetActivitiesAsync(projectIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getactivities-{projectIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -42,11 +47,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetActivityAsync(activityIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getactivity-{activityIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetActivityAsync(activityIdHash, cancellationToken);
@@ -63,6 +71,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetMilestoneAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetMilestoneAsync(milestoneIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getmilestone-{milestoneIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -84,11 +95,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetMilestonesAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getmilestones-{pagination.Index}-{pagination.PageSize}-{pagination.Page}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if (string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetMilestonesAsync(pagination, cancellationToken);
@@ -105,11 +119,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProgrammeAsync(programmeIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprogramme-{programmeIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetProgrammeAsync(programmeIdHash, cancellationToken);
@@ -126,11 +143,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetProgrammeProjectsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProgrammeProjectsAsync(programmeIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprogrammeprojects-{programmeIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetProgrammeProjectsAsync(programmeIdHash, cancellationToken);
@@ -147,11 +167,14 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProgrammesAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprogrammes-{pagination.Index}-{pagination.PageSize}-{pagination.Page}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetProgrammesAsync(pagination, cancellationToken);
@@ -168,6 +191,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetProjectAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProjectAsync(projectIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getproject-{projectIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -189,6 +215,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetProjectIndicatorsAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProjectIndicatorsAsync(projectIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprojectindicators-{projectIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -197,7 +226,7 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
{
var result = await service.GetProjectIndicatorsAsync(projectIdHash, cancellationToken);
- if(result.IsFailed) return result;
+ if (result.IsFailed) return result;
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
@@ -210,15 +239,18 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetProjectMilestonesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProjectMilestonesAsync(projectIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprojectmilestones-{projectIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
- if(string.IsNullOrWhiteSpace(cached))
+ if (string.IsNullOrWhiteSpace(cached))
{
var result = await service.GetProjectMilestonesAsync(projectIdHash, cancellationToken);
- if(result.IsFailed) return result;
+ if (result.IsFailed) return result;
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
@@ -231,6 +263,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProjectRisksAsync(projectIdHash, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprojectrisks-{projectIdHash}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -239,7 +274,7 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
{
var result = await service.GetProjectRisksAsync(projectIdHash, cancellationToken);
- if(result.IsFailed) return result;
+ if (result.IsFailed) return result;
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
@@ -252,6 +287,9 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
public async ValueTask> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetProjectsAsync(pagination, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getprojects-{pagination.Index}-{pagination.Page}-{pagination.PageSize}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -260,7 +298,7 @@ public sealed class ProjectCacheService(ProjectService service, IDistributedCach
{
var result = await service.GetProjectsAsync(pagination, cancellationToken);
- if(result.IsFailed) return result;
+ if (result.IsFailed) return result;
await cache.SetStringAsync(cacheKey, result.Value.ToJson(), cacheOptions, cancellationToken);
diff --git a/PostFundManagement.Application/Services/Tools/ToolCacheService.cs b/PostFundManagement.Application/Services/Tools/ToolCacheService.cs
index fce4397..92b0ef0 100644
--- a/PostFundManagement.Application/Services/Tools/ToolCacheService.cs
+++ b/PostFundManagement.Application/Services/Tools/ToolCacheService.cs
@@ -1,14 +1,19 @@
using PostFundManagement.Application.Abstractions;
using PostFundManagement.Application.Abstractions.Services;
using PostFundManagement.Application.Services.Shared;
+using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Application.Services.Tools;
-public sealed class ToolCacheService(ToolService service, IDistributedCache cache) : ServiceCacheBase, IToolService
+public sealed class ToolCacheService(ToolService service, IDistributedCache cache,
+ IFeatureManager featureManager) : ServiceCacheBase, IToolService
{
public async ValueTask> EncodeLong(long id, CancellationToken cancellationToken) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.EncodeLong(id, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"encodelonghash-{id}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
diff --git a/PostFundManagement.Application/Services/Users/UserCacheService.cs b/PostFundManagement.Application/Services/Users/UserCacheService.cs
index 0f83137..a5d3ac3 100644
--- a/PostFundManagement.Application/Services/Users/UserCacheService.cs
+++ b/PostFundManagement.Application/Services/Users/UserCacheService.cs
@@ -4,14 +4,19 @@ using PostFundManagement.Application.Extensions;
using PostFundManagement.Application.Services.Shared;
using PostFundManagement.Domain;
using PostFundManagement.Domain.Models;
+using static PostFundManagement.Domain.Extensions.Constants;
namespace PostFundManagement.Application.Services.Users;
-public sealed class UserCacheService(UserService service, IDistributedCache cache) : ServiceCacheBase, IUserService
+public sealed class UserCacheService(UserService service, IDistributedCache cache,
+ IFeatureManager featureManager) : ServiceCacheBase, IUserService
{
public async ValueTask> GetUserAsync(Guid userId, CancellationToken cancellationToken) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetUserAsync(userId, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getuser-{userId}").Value;
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
@@ -33,6 +38,9 @@ public sealed class UserCacheService(UserService service, IDistributedCache cach
public async ValueTask> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default) =>
await Result.Try((Func>>)(async () =>
{
+ if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
+ return await service.GetUsersAsync(pagination, request, cancellationToken);
+
var cacheKey = HashService.ToMd5Hash($"getusers-{pagination.Page}-{pagination.PageSize}-" +
$"{request.Email}-{request.Status}-{request.SortBy}-{request.SortDescending}").Value;
diff --git a/PostFundManagement.Domain/Extensions/Constants.cs b/PostFundManagement.Domain/Extensions/Constants.cs
index 0c77cc1..7bd0bd0 100644
--- a/PostFundManagement.Domain/Extensions/Constants.cs
+++ b/PostFundManagement.Domain/Extensions/Constants.cs
@@ -2,6 +2,8 @@ namespace PostFundManagement.Domain.Extensions;
public static class Constants
{
+ public const string ServiceCachingFeature = "EnableServiceCaching";
+
public const string MainScope = "ApiScope";
public const string CorsPolicy = "AllowConfiguredOrigins";
diff --git a/PostFundManagement.Domain/PostFundManagement.Domain.csproj b/PostFundManagement.Domain/PostFundManagement.Domain.csproj
index f16e0cb..b176c43 100644
--- a/PostFundManagement.Domain/PostFundManagement.Domain.csproj
+++ b/PostFundManagement.Domain/PostFundManagement.Domain.csproj
@@ -12,9 +12,10 @@
-
-
-
+
+
+
+
@@ -27,12 +28,12 @@
-
-
-
-
-
-
+
+
+
+
+
+
@@ -62,8 +63,8 @@
-
-
+
+
@@ -73,17 +74,17 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
+
+
+
+
+
+
@@ -91,11 +92,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -108,9 +109,9 @@
-
-
-
+
+
+
@@ -136,18 +137,18 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
@@ -159,8 +160,8 @@
-
-
+
+
@@ -179,8 +180,8 @@
-
-
+
+
diff --git a/PostFundManagement.Infrastructure/PostFundManagement.Infrastructure.csproj b/PostFundManagement.Infrastructure/PostFundManagement.Infrastructure.csproj
index 2882d52..485285a 100644
--- a/PostFundManagement.Infrastructure/PostFundManagement.Infrastructure.csproj
+++ b/PostFundManagement.Infrastructure/PostFundManagement.Infrastructure.csproj
@@ -12,15 +12,15 @@
-
-
-
-
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
@@ -32,9 +32,9 @@
-
-
-
+
+
+
diff --git a/docker-compose.yml b/docker-compose.yml
index 728f826..9cd2552 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -9,6 +9,10 @@ services:
ports:
- "8075:8080"
environment:
+ # Service layer caching feature flag
+ - EnableServiceCaching=false
+
+ # Header forwarding overrides
- ASPNETCORE_ENVIRONMENT=${ENVIRONMENT:-Development}
- ForwardedHeadersConfiguration__Enabled=true
- ForwardedHeadersConfiguration__AllowAll=true