Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ permissions:
contents: write
pull-requests: write
security-events: write
pages: write
id-token: write

jobs:
build:
Expand Down Expand Up @@ -286,3 +288,49 @@ jobs:
--notes "Pre-release from \`${{ github.head_ref }}\` branch." \
--prerelease \
./artifacts/*.nupkg

docs:
needs: release
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master' && github.event_name == 'push'

steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
9.0.x
10.0.x

- name: Install DocFX
run: dotnet tool install -g docfx

- name: Restore
run: dotnet restore

- name: Build site
run: docfx docs/docfx.json

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/_site

docs-deploy:
needs: docs
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
concurrency:
group: pages
cancel-in-progress: false
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,8 @@ FodyWeavers.xsd
# JetBrains Rider
*.sln.iml
/.claude/settings.local.json

# DocFX generated output
/docs/_site/
/docs/api/
/docs/obj/
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

A flexible .NET caching library with multiple cache strategies, pluggable persistence backends, eviction policies, and a Blazor monitoring UI.

📖 **Documentation:** [cache.tharga.net](https://cache.tharga.net)

## Packages

| Package | Description | NuGet |
Expand Down
2 changes: 1 addition & 1 deletion Sample/Tharga.Cache.Console/Tharga.Cache.Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Tharga.Console" Version="4.1.1" />
<PackageReference Include="Tharga.Console" Version="4.1.2" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion Sample/Tharga.Cache.WebApi/Tharga.Cache.WebApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.1" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions Tharga.Cache.Blazor/Tharga.Cache.Blazor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Company>Thargelion AB</Company>
<Product>Tharga Cache Blazor</Product>
<Description>Component for manageing the Tharga Cache features in blazor.</Description>
<PackageIconUrl>https://thargelion.se/wp-content/uploads/2025/11/Thargelion-Cache-Icon-150.png</PackageIconUrl>
<PackageIconUrl>https://thargelion.net/assets/component-cache.png</PackageIconUrl>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
<DebugType>portable</DebugType>
Expand All @@ -27,7 +27,7 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Tharga.Blazor" Version="2.1.6" />
<PackageReference Include="Tharga.Blazor" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Tharga.Cache\Tharga.Cache.csproj" />
Expand Down
4 changes: 2 additions & 2 deletions Tharga.Cache.File.Tests/Tharga.Cache.File.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.10.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
Expand Down
2 changes: 1 addition & 1 deletion Tharga.Cache.File/Tharga.Cache.File.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Company>Thargelion AB</Company>
<Product>Tharga Cache File</Product>
<Description>File cache features.</Description>
<PackageIconUrl>https://thargelion.se/wp-content/uploads/2025/11/Thargelion-Cache-Icon-150.png</PackageIconUrl>
<PackageIconUrl>https://thargelion.net/assets/component-cache.png</PackageIconUrl>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageProjectUrl>https://github.com/Tharga/Cache</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down
4 changes: 2 additions & 2 deletions Tharga.Cache.Mcp/Tharga.Cache.Mcp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Company>Thargelion AB</Company>
<Product>Tharga Cache MCP</Product>
<Description>Exposes Tharga.Cache monitoring data (cache types, items, persistence health, fetch queue) and actions (clear all, clear stale) via MCP (Model Context Protocol). Plugs into Tharga.Mcp.</Description>
<PackageIconUrl>https://thargelion.se/wp-content/uploads/2025/11/Thargelion-Cache-Icon-150.png</PackageIconUrl>
<PackageIconUrl>https://thargelion.net/assets/component-cache.png</PackageIconUrl>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageProjectUrl>https://github.com/Tharga/Cache</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand All @@ -33,7 +33,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Tharga.Mcp" Version="0.1.4" />
<PackageReference Include="Tharga.Mcp" Version="0.1.6" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.300">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
4 changes: 2 additions & 2 deletions Tharga.Cache.MongoDB.Tests/Tharga.Cache.MongoDB.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.10.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
Expand Down
4 changes: 2 additions & 2 deletions Tharga.Cache.MongoDB/Tharga.Cache.MongoDB.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Company>Thargelion AB</Company>
<Product>Tharga Cache MongoDB</Product>
<Description>MongoDB cache features.</Description>
<PackageIconUrl>https://thargelion.se/wp-content/uploads/2025/11/Thargelion-Cache-Icon-150.png</PackageIconUrl>
<PackageIconUrl>https://thargelion.net/assets/component-cache.png</PackageIconUrl>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageProjectUrl>https://github.com/Tharga/Cache</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down Expand Up @@ -39,7 +39,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Tharga.MongoDB" Version="2.10.12" />
<PackageReference Include="Tharga.MongoDB" Version="2.11.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Tharga.Cache\Tharga.Cache.csproj" />
Expand Down
4 changes: 2 additions & 2 deletions Tharga.Cache.Redis.Tests/Tharga.Cache.Redis.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.10.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
Expand Down
6 changes: 3 additions & 3 deletions Tharga.Cache.Redis/Tharga.Cache.Redis.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Company>Thargelion AB</Company>
<Product>Tharga Cache Redis</Product>
<Description>Redis cache features.</Description>
<PackageIconUrl>https://thargelion.se/wp-content/uploads/2025/11/Thargelion-Cache-Icon-150.png</PackageIconUrl>
<PackageIconUrl>https://thargelion.net/assets/component-cache.png</PackageIconUrl>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageProjectUrl>https://github.com/Tharga/Cache</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down Expand Up @@ -40,8 +40,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Polly" Version="8.6.6" />
<PackageReference Include="StackExchange.Redis" Version="2.13.1" />
<PackageReference Include="Polly" Version="8.7.0" />
<PackageReference Include="StackExchange.Redis" Version="2.13.17" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.300">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
4 changes: 2 additions & 2 deletions Tharga.Cache.Tests/Tharga.Cache.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.10.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.8" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
Expand Down
4 changes: 2 additions & 2 deletions Tharga.Cache/Tharga.Cache.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Company>Thargelion AB</Company>
<Product>Tharga Cache</Product>
<Description>Memory cache features.</Description>
<PackageIconUrl>https://thargelion.se/wp-content/uploads/2025/11/Thargelion-Cache-Icon-150.png</PackageIconUrl>
<PackageIconUrl>https://thargelion.net/assets/component-cache.png</PackageIconUrl>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageProjectUrl>https://github.com/Tharga/Cache</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down Expand Up @@ -43,7 +43,7 @@

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="8.10.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.8" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.9" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.300">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
1 change: 1 addition & 0 deletions docs/CNAME
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cache.tharga.net
95 changes: 95 additions & 0 deletions docs/articles/cache-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Cache types

Tharga.Cache exposes four cache interfaces, each with a different expiration strategy. Inject the one that matches the lifetime your data needs — they share the same `ICache` operations (see [Common operations](getting-started.md#common-operations)) and differ only in when items expire.

| Interface | Expiration | Lifetime | Typical use |
|-----------|------------|----------|-------------|
| `IEternalCache` | Never (until explicitly removed) | Singleton | Reference data that rarely changes |
| `ITimeToLiveCache` | Fixed time after insertion (TTL) | Singleton | API responses, computed results |
| `ITimeToIdleCache` | Reset on every access (TTI) | Singleton | Session-like data kept alive while in use |
| `IScopeCache` | End of the DI scope | Scoped | Per-request memoization |

## IEternalCache

Data never expires unless explicitly dropped or invalidated. Registered as a singleton.

```csharp
public class UserService(IEternalCache cache)
{
public Task<User> GetUserAsync(string userId) =>
cache.GetAsync<User>(userId, () => LoadUserAsync(userId));
}
```

## ITimeToLiveCache

Data expires a fixed time after insertion (TTL). Registered as a singleton.

```csharp
var data = await ttlCache.GetAsync<Product>(
"product-123",
() => LoadProductAsync(123),
TimeSpan.FromMinutes(10));
```

## ITimeToIdleCache

The expiration clock resets every time the item is accessed (TTI). Useful for session-like data that should stay cached while it is actively being used and expire once it goes quiet.

```csharp
var session = await ttiCache.GetAsync<SessionData>(
"session-abc",
() => LoadSessionAsync("abc"),
TimeSpan.FromMinutes(30));
```

## IScopeCache

A scoped cache instance, cleared at the end of the DI scope (for example, per HTTP request). Data never expires within the scope, which makes it a clean way to memoize a value that may be requested several times while handling a single request.

```csharp
var result = await scopeCache.GetAsync<RequestContext>(
"current-context",
() => BuildContextAsync());
```

## Stale-while-revalidate

For the time-based caches, enabling `StaleWhileRevalidate` returns expired data immediately while fresh data is fetched in the background — eliminating the latency spike of a cache miss.

```csharp
o.RegisterType<Product, IMemory>(t =>
{
t.StaleWhileRevalidate = true;
t.DefaultFreshSpan = TimeSpan.FromMinutes(5);
});
```

Use `GetWithCallbackAsync` to be notified when the fresh value arrives:

```csharp
var (data, isFresh) = await cache.GetWithCallbackAsync<Product>(
"product-123",
() => LoadProductAsync(123),
async freshData =>
{
// Called when the background refresh completes
await NotifyClientsAsync(freshData);
},
TimeSpan.FromMinutes(5));

if (!isFresh)
{
// data is stale; the callback will fire when fresh data is ready
}
```

## Events

All cache types raise events for observing activity:

```csharp
cache.DataSetEvent += (sender, args) => Console.WriteLine($"Cached: {args.Key}");
cache.DataGetEvent += (sender, args) => Console.WriteLine($"Retrieved: {args.Key}");
cache.DataDropEvent += (sender, args) => Console.WriteLine($"Removed: {args.Key}");
```
Loading
Loading