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