Skip to content

Commit

Permalink
New InMemoryCacheService implementation of ICacheService in Spark
Browse files Browse the repository at this point in the history
- InMemoryCacheService cache can be used in any .net standard project
- CacheExpires class not longer has depenency on System.Web.Caching.Cache
- Renamed DefaultCacheService to WebCacheService
- Moved NullCacheService to Castle.MonoRail.Views project (it's the only place using it)
- Moved some classes back to Spark project when possible
- Moved markdown dependency back to spark
  • Loading branch information
bounav committed Feb 29, 2024
1 parent d8152fb commit 09e540c
Show file tree
Hide file tree
Showing 25 changed files with 330 additions and 176 deletions.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public HybridCacheService(IEngineContext context)
}
else
{
_fallbackCacheService = new DefaultCacheService(context.UnderlyingContext.Cache);
_fallbackCacheService = new WebCacheService(context.UnderlyingContext.Cache);
}
}

Expand Down
88 changes: 88 additions & 0 deletions src/Spark.Tests/InMemoryServiceTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Threading;
using Microsoft.Extensions.Caching.Memory;
using NUnit.Framework;

namespace Spark.Tests
{
[TestFixture]
public class InMemoryServiceTest
{
[Test]
public void TestStoreValueThenRetrieveIt()
{
var service = new InMemoryCacheService(new MemoryCache(new MemoryCacheOptions()));

var item = new { };

service.Store("identifier", CacheExpires.Empty, null, item);

var retrieved = service.Get("identifier");

Assert.AreSame(item, retrieved);
}

[Test]
public void TestStoreValueThenRetrieveItAfterAbsoluteExpiration()
{
var service = new InMemoryCacheService(new MemoryCache(new MemoryCacheOptions()));

var item = new { };

service.Store("identifier", new CacheExpires(DateTime.UtcNow.AddMilliseconds(50)), null, item);

Thread.Sleep(100);

var retrieved = service.Get("identifier");

Assert.IsNull(retrieved);
}

[Test]
public void TestStoreValueThenRetrieveItWhenExpirationSlides()
{
var service = new InMemoryCacheService(new MemoryCache(new MemoryCacheOptions()));

var item = new { };

service.Store("identifier", new CacheExpires(TimeSpan.FromMilliseconds(75)), null, item);

object retrieved;

for (var i = 0; i < 3; i++)
{
Thread.Sleep(50);

retrieved = service.Get("identifier");
}

retrieved = service.Get("identifier");

Assert.IsNotNull(retrieved);

Assert.AreSame(item, retrieved);
}

[Test]
public void TestStoreValueWithSignal()
{
var service = new InMemoryCacheService(new MemoryCache(new MemoryCacheOptions()));

var item = new { };

var signal = new CacheSignal();

service.Store("identifier", null, signal, item);

var retrieved = service.Get("identifier");

Assert.AreSame(item, retrieved);

signal.FireChanged();

retrieved = service.Get("identifier");

Assert.IsNull(retrieved);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public static IServiceCollection AddSpark(this IServiceCollection services, ISpa
{
if (HttpContext.Current != null && HttpContext.Current.Cache != null)
{
return new DefaultCacheService(HttpContext.Current.Cache);
return new WebCacheService(HttpContext.Current.Cache);
}
return null;
Expand Down
1 change: 0 additions & 1 deletion src/Spark.Web.Tests/Caching/CacheElementTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,6 @@ public void SignalWillExpireOutputCachingEntry()
<p>2</p>
</div>"));
Assert.That(calls, Is.EqualTo(2));

}
}
}
39 changes: 0 additions & 39 deletions src/Spark.Web/CacheExpires.cs

This file was deleted.

38 changes: 0 additions & 38 deletions src/Spark.Web/Caching/SpoolWriterOriginator.cs

This file was deleted.

39 changes: 0 additions & 39 deletions src/Spark.Web/Caching/StringWriterOriginator.cs

This file was deleted.

3 changes: 0 additions & 3 deletions src/Spark.Web/Spark.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
<Reference Include="System.Configuration" />
<Reference Include="System.Web" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MarkdownSharp" Version="2.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Spark\Spark.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
using System;
using System.Web.Caching;

namespace Spark.Caching
namespace Spark
{
public class DefaultCacheService : ICacheService
public class WebCacheService : ICacheService
{
private readonly Cache _cache;
private readonly Cache cache;

public DefaultCacheService(Cache cache)
public WebCacheService(Cache cache)
{
_cache = cache;
this.cache = cache;
}

public object Get(string identifier)
{
return _cache.Get(identifier);
return this.cache.Get(identifier);
}

public void Store(string identifier, CacheExpires expires, ICacheSignal signal, object item)
{
_cache.Insert(
this.cache.Insert(
identifier,
item,
SignalDependency.For(signal),
Expand Down
File renamed without changes.
60 changes: 60 additions & 0 deletions src/Spark/CacheExpires.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;

namespace Spark
{
/// <summary>
/// Represents when a cached entry should expire.
/// </summary>
public class CacheExpires
{
/// <summary>
/// Constructor for a non expiring cached entry.
/// </summary>
public CacheExpires()
{
Absolute = NoAbsoluteExpiration;
Sliding = NoSlidingExpiration;
}

/// <summary>
/// Constructor for a non cached entry expiring at a specified time.
/// </summary>
/// <param name="absolute">The time when to invalidate the cached entry.</param>
public CacheExpires(DateTime absolute)
{
Absolute = absolute;
Sliding = NoSlidingExpiration;
}

/// <summary>
/// Constructor for a cached entry that stays cached as long as it keeps being used.
/// </summary>
/// <param name="sliding">The timespan of sliding expirations.</param>
public CacheExpires(TimeSpan sliding)
{
Absolute = NoAbsoluteExpiration;
Sliding = sliding;
}

/// <summary>
/// Constructor for a cached entry that stays cached as long as it keeps being used.
/// </summary>
/// <param name="sliding">The number of seconds of sliding expirations.</param>
public CacheExpires(double sliding)
: this(TimeSpan.FromSeconds(sliding))
{
}

public DateTime Absolute { get; set; }
public TimeSpan Sliding { get; set; }

public static DateTime NoAbsoluteExpiration => DateTime.MaxValue;

public static TimeSpan NoSlidingExpiration => TimeSpan.Zero;

/// <summary>
/// Cached entry never to expire.
/// </summary>
public static CacheExpires Empty { get; } = new();
}
}
12 changes: 6 additions & 6 deletions src/Spark.Web/CacheSignal.cs → src/Spark/CacheSignal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class CacheSignal : ICacheSignal
lock (this)
{
_changed += value;
if (_enabled)
if (_enabled)
return;

Enable();
Expand All @@ -31,7 +31,7 @@ public class CacheSignal : ICacheSignal
lock (this)
{
_changed -= value;
if (_enabled != true || ChangedIsEmpty() == false)
if (_enabled != true || ChangedIsEmpty() == false)
return;

Disable();
Expand All @@ -42,7 +42,7 @@ public class CacheSignal : ICacheSignal

private bool ChangedIsEmpty()
{
return _changed == null ||
return _changed == null ||
_changed.GetInvocationList().Length == 0;
}

Expand All @@ -52,15 +52,15 @@ private bool ChangedIsEmpty()
/// to call FireChanged.
/// </summary>
protected virtual void Enable()
{
{
}

/// <summary>
/// Optionally implemented by descendant to tear down listening infrastructure
/// when no cache dependencies remain listenning to the signal.
/// </summary>
protected virtual void Disable()
{
{
}

/// <summary>
Expand All @@ -69,7 +69,7 @@ protected virtual void Disable()
/// </summary>
public void FireChanged()
{
if (_changed != null)
if (_changed != null)
_changed(this, EventArgs.Empty);
}
}
Expand Down

0 comments on commit 09e540c

Please sign in to comment.