-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Farshad DASHTI
authored and
Farshad DASHTI
committed
Oct 1, 2024
1 parent
f972885
commit a3d6efb
Showing
9 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
name: .NET Build and Test for DfE.CoreLibs.Caching | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
paths: | ||
- 'src/DfE.CoreLibs.Caching/**' | ||
|
||
jobs: | ||
build-and-test: | ||
uses: ./.github/workflows/build-test-template.yml | ||
with: | ||
project_name: DfE.CoreLibs.Caching | ||
project_path: src/DfE.CoreLibs.Caching | ||
sonar_project_key: DFE-Digital_corelibs-caching | ||
secrets: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
name: .NET Build and Test Template | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
project_name: | ||
required: true | ||
type: string | ||
description: "The name of the project" | ||
project_path: | ||
required: true | ||
type: string | ||
description: "The relative path to the project directory" | ||
sonar_project_key: | ||
required: true | ||
type: string | ||
description: "SonarCloud project key" | ||
secrets: | ||
GITHUB_TOKEN: | ||
required: true | ||
SONAR_TOKEN: | ||
required: true | ||
|
||
env: | ||
DOTNET_VERSION: '8.0.x' | ||
EF_VERSION: '6.0.5' | ||
JAVA_VERSION: '17' | ||
CONNECTION_STRING: 'Server=localhost,1433;Database=sip;TrustServerCertificate=True;User Id=sa;Password=StrongPassword905' | ||
|
||
jobs: | ||
build-and-test: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
packages: read | ||
contents: read | ||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- name: Setup .NET | ||
uses: actions/setup-dotnet@v4 | ||
with: | ||
dotnet-version: ${{ env.DOTNET_VERSION }} | ||
|
||
- name: Setup JDK | ||
uses: actions/setup-java@v4 | ||
with: | ||
distribution: 'microsoft' | ||
java-version: ${{ env.JAVA_VERSION }} | ||
|
||
- name: Cache SonarCloud packages | ||
uses: actions/cache@v4 | ||
with: | ||
path: ~/.sonar/cache | ||
key: ${{ runner.os }}-sonar | ||
restore-keys: ${{ runner.os }}-sonar | ||
|
||
- name: Install SonarCloud scanners | ||
run: dotnet tool install --global dotnet-sonarscanner | ||
|
||
- name: Install EF for tests | ||
run: dotnet tool install --global dotnet-ef --version ${{ env.EF_VERSION }} | ||
|
||
- name: Install dotnet reportgenerator | ||
run: dotnet tool install --global dotnet-reportgenerator-globaltool | ||
|
||
- name: Add nuget package source | ||
run: dotnet nuget add source --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/DFE-Digital/index.json" | ||
|
||
- name: Restore dependencies | ||
run: dotnet restore ${{ inputs.project_path }} | ||
|
||
- name: Build, Test and Analyze | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
ConnectionStrings__DefaultConnection: ${{ env.CONNECTION_STRING }} | ||
CI: true | ||
run: | | ||
dotnet-sonarscanner begin /k:"${{ inputs.sonar_project_key }}" /o:"dfe-digital" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.coverageReportPaths=CoverageReport/SonarQube.xml | ||
dotnet build --no-restore -p:CI=${CI} ${{ inputs.project_path }} | ||
dotnet test --no-build --verbosity normal --collect:"XPlat Code Coverage" ${{ inputs.project_path }} | ||
reportgenerator -reports:./**/coverage.cobertura.xml -targetdir:./CoverageReport -reporttypes:SonarQube | ||
dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" /> | ||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" /> | ||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using System.Security.Cryptography; | ||
using System.Text; | ||
|
||
namespace DfE.CoreLibs.Caching.Helpers | ||
{ | ||
public static class CacheKeyHelper | ||
{ | ||
/// <summary> | ||
/// Generates a hashed cache key for any given input string. | ||
/// </summary> | ||
/// <param name="input">The input string to be hashed.</param> | ||
/// <returns>A hashed string that can be used as a cache key.</returns> | ||
public static string GenerateHashedCacheKey(string input) | ||
{ | ||
if (string.IsNullOrWhiteSpace(input)) | ||
{ | ||
throw new ArgumentException("Input cannot be null or empty", nameof(input)); | ||
} | ||
|
||
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(input)); | ||
|
||
return BitConverter.ToString(bytes).Replace("-", "").ToLower(); | ||
} | ||
|
||
/// <summary> | ||
/// Generates a hashed cache key for a collection of strings by concatenating them. | ||
/// </summary> | ||
/// <param name="inputs">A collection of strings to be concatenated and hashed.</param> | ||
/// <returns>A hashed string that can be used as a cache key.</returns> | ||
public static string GenerateHashedCacheKey(IEnumerable<string> inputs) | ||
{ | ||
if (inputs == null || !inputs.Any()) | ||
{ | ||
throw new ArgumentException("Input collection cannot be null or empty", nameof(inputs)); | ||
} | ||
|
||
var concatenatedInput = string.Join(",", inputs); | ||
|
||
return GenerateHashedCacheKey(concatenatedInput); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace DfE.CoreLibs.Caching.Interfaces | ||
{ | ||
public interface ICacheService | ||
{ | ||
Task<T> GetOrAddAsync<T>(string cacheKey, Func<Task<T>> fetchFunction, string methodName); | ||
void Remove(string cacheKey); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using DfE.CoreLibs.Caching.Interfaces; | ||
using DfE.CoreLibs.Caching.Services; | ||
using DfE.CoreLibs.Caching.Settings; | ||
using Microsoft.Extensions.Configuration; | ||
|
||
namespace Microsoft.Extensions.DependencyInjection | ||
{ | ||
public static class ServiceCollectionExtensions | ||
{ | ||
public static IServiceCollection AddServiceCaching( | ||
this IServiceCollection services, IConfiguration config) | ||
{ | ||
services.Configure<CacheSettings>(config.GetSection("CacheSettings")); | ||
services.AddSingleton<ICacheService, MemoryCacheService>(); | ||
|
||
return services; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System.Diagnostics.CodeAnalysis; | ||
using DfE.CoreLibs.Caching.Interfaces; | ||
using DfE.CoreLibs.Caching.Settings; | ||
using Microsoft.Extensions.Caching.Memory; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace DfE.CoreLibs.Caching.Services | ||
{ | ||
[ExcludeFromCodeCoverage] | ||
public class MemoryCacheService( | ||
IMemoryCache memoryCache, | ||
ILogger<MemoryCacheService> logger, | ||
IOptions<CacheSettings> cacheSettings) | ||
: ICacheService | ||
{ | ||
private readonly CacheSettings _cacheSettings = cacheSettings.Value; | ||
|
||
public async Task<T> GetOrAddAsync<T>(string cacheKey, Func<Task<T>> fetchFunction, string methodName) | ||
{ | ||
if (memoryCache.TryGetValue(cacheKey, out T? cachedValue)) | ||
{ | ||
logger.LogInformation("Cache hit for key: {CacheKey}", cacheKey); | ||
return cachedValue!; | ||
} | ||
|
||
logger.LogInformation("Cache miss for key: {CacheKey}. Fetching from source...", cacheKey); | ||
var result = await fetchFunction(); | ||
|
||
if (Equals(result, default(T))) return result; | ||
var cacheDuration = GetCacheDurationForMethod(methodName); | ||
memoryCache.Set(cacheKey, result, cacheDuration); | ||
logger.LogInformation("Cached result for key: {CacheKey} for duration: {CacheDuration}", cacheKey, cacheDuration); | ||
|
||
return result; | ||
} | ||
|
||
public void Remove(string cacheKey) | ||
{ | ||
memoryCache.Remove(cacheKey); | ||
logger.LogInformation("Cache removed for key: {CacheKey}", cacheKey); | ||
} | ||
|
||
private TimeSpan GetCacheDurationForMethod(string methodName) | ||
{ | ||
if (_cacheSettings.Durations.TryGetValue(methodName, out int durationInSeconds)) | ||
{ | ||
return TimeSpan.FromSeconds(durationInSeconds); | ||
} | ||
return TimeSpan.FromSeconds(_cacheSettings.DefaultDurationInSeconds); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace DfE.CoreLibs.Caching.Settings | ||
{ | ||
public class CacheSettings | ||
{ | ||
public int DefaultDurationInSeconds { get; set; } = 5; | ||
public Dictionary<string, int> Durations { get; set; } = new(); | ||
} | ||
} |