Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Suport to Slide Cache #255

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion src/WebApi.OutputCache.Core/Cache/IApiOutputCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public interface IApiOutputCache

bool Contains(string key);

void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null);
void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null, TimeSpan slidingExpiration = default(TimeSpan), bool slide = false);

IEnumerable<string> AllKeys { get; }
}
Expand Down
18 changes: 9 additions & 9 deletions src/WebApi.OutputCache.Core/Cache/MemoryCacheDefault.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@ public virtual bool Contains(string key)
return Cache.Contains(key);
}

public virtual void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null)
public virtual void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null, TimeSpan slidingExpiration = default(TimeSpan), bool slide = false)
{
var cachePolicy = new CacheItemPolicy
{
AbsoluteExpiration = expiration
};
var cachePolicy = new CacheItemPolicy();

if (slide)
cachePolicy.SlidingExpiration = slidingExpiration;
else
cachePolicy.AbsoluteExpiration = expiration;

if (!string.IsNullOrWhiteSpace(dependsOnKey))
if (!string.IsNullOrWhiteSpace(dependsOnKey) && !slide)
{
cachePolicy.ChangeMonitors.Add(
Cache.CreateCacheEntryChangeMonitor(new[] { dependsOnKey })
);
cachePolicy.ChangeMonitors.Add(Cache.CreateCacheEntryChangeMonitor(new[] { dependsOnKey }));
}
lock (Cache)
{
Expand Down
2 changes: 2 additions & 0 deletions src/WebApi.OutputCache.Core/Time/CacheTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ public class CacheTime
public TimeSpan? SharedTimeSpan { get; set; }

public DateTimeOffset AbsoluteExpiration { get; set; }

public TimeSpan SlidingExpiration { get; set; }
}
}
12 changes: 8 additions & 4 deletions src/WebApi.OutputCache.Core/Time/ShortTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ public class ShortTime : IModelQuery<DateTime, CacheTime>
private readonly int serverTimeInSeconds;
private readonly int clientTimeInSeconds;
private readonly int? sharedTimeInSecounds;
private readonly bool slideExpiration;

public ShortTime(int serverTimeInSeconds, int clientTimeInSeconds, int? sharedTimeInSecounds)
public ShortTime(int serverTimeInSeconds, int clientTimeInSeconds, int? sharedTimeInSeconds, bool slideExpiration)
{
if (serverTimeInSeconds < 0)
serverTimeInSeconds = 0;
Expand All @@ -20,17 +21,20 @@ public ShortTime(int serverTimeInSeconds, int clientTimeInSeconds, int? sharedTi

this.clientTimeInSeconds = clientTimeInSeconds;

if (sharedTimeInSecounds.HasValue && sharedTimeInSecounds.Value < 0)
sharedTimeInSecounds = 0;
if (sharedTimeInSeconds.HasValue && sharedTimeInSeconds.Value < 0)
sharedTimeInSeconds = 0;

this.sharedTimeInSecounds = sharedTimeInSecounds;
this.sharedTimeInSecounds = sharedTimeInSeconds;

this.slideExpiration = slideExpiration;
}

public CacheTime Execute(DateTime model)
{
var cacheTime = new CacheTime
{
AbsoluteExpiration = model.AddSeconds(serverTimeInSeconds),
SlidingExpiration = TimeSpan.FromSeconds(serverTimeInSeconds),
ClientTimeSpan = TimeSpan.FromSeconds(clientTimeInSeconds),
SharedTimeSpan = sharedTimeInSecounds.HasValue ? (TimeSpan?) TimeSpan.FromSeconds(sharedTimeInSecounds.Value) : null
};
Expand Down
25 changes: 15 additions & 10 deletions src/WebApi.OutputCache.V2/CacheOutputAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
Expand All @@ -16,6 +15,7 @@
using WebApi.OutputCache.Core;
using WebApi.OutputCache.Core.Cache;
using WebApi.OutputCache.Core.Time;
using System.Collections.Generic;

namespace WebApi.OutputCache.V2
{
Expand Down Expand Up @@ -50,7 +50,6 @@ public class CacheOutputAttribute : ActionFilterAttribute
/// </summary>
public int ClientTimeSpan { get; set; }


private int? _sharedTimeSpan = null;

/// <summary>
Expand All @@ -77,6 +76,11 @@ public int SharedTimeSpan
/// </summary>
public bool Private { get; set; }

/// <summary>
/// Sets cache expiration to from absolute to sliding. When cache expiration is set to sliding, the Cache-Control HTTP header will be renewed with each response.
/// </summary>
public bool Slide { get; set; }

/// <summary>
/// Class used to generate caching keys
/// </summary>
Expand Down Expand Up @@ -127,7 +131,7 @@ protected virtual void EnsureCacheTimeQuery()

protected void ResetCacheTimeQuery()
{
CacheTimeQuery = new ShortTime( ServerTimeSpan, ClientTimeSpan, _sharedTimeSpan);
CacheTimeQuery = new ShortTime(ServerTimeSpan, ClientTimeSpan, _sharedTimeSpan, Slide);
}

protected virtual MediaTypeHeaderValue GetExpectedMediaType(HttpConfiguration config, HttpActionContext actionContext)
Expand Down Expand Up @@ -238,7 +242,7 @@ public override void OnActionExecuting(HttpActionContext actionContext)
if (responseHeaders != null) AddCustomCachedHeaders(actionContext.Response, responseHeaders, responseContentHeaders);

var cacheTime = CacheTimeQuery.Execute(DateTime.Now);
ApplyCacheHeaders(actionContext.Response, cacheTime, contentGenerationTimestamp);
ApplyCacheHeaders(actionContext.Response, cacheTime, Slide ? DateTimeOffset.Now : contentGenerationTimestamp);
}

public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
Expand All @@ -249,7 +253,7 @@ public override async Task OnActionExecutedAsync(HttpActionExecutedContext actio

var actionExecutionTimestamp = DateTimeOffset.Now;
var cacheTime = CacheTimeQuery.Execute(actionExecutionTimestamp.DateTime);
if (cacheTime.AbsoluteExpiration > actionExecutionTimestamp)
if (cacheTime.AbsoluteExpiration > actionExecutionTimestamp || Slide)
{
var httpConfig = actionExecutedContext.Request.GetConfiguration();
var config = httpConfig.CacheOutputConfiguration();
Expand All @@ -274,22 +278,23 @@ public override async Task OnActionExecutedAsync(HttpActionExecutedContext actio

responseContent.Headers.Remove("Content-Length");

_webApiCache.Add(baseKey, string.Empty, cacheTime.AbsoluteExpiration);
_webApiCache.Add(cachekey, content, cacheTime.AbsoluteExpiration, baseKey);
_webApiCache.Add(baseKey, string.Empty, cacheTime.AbsoluteExpiration, null, cacheTime.SlidingExpiration, Slide);
_webApiCache.Add(cachekey, content, cacheTime.AbsoluteExpiration, baseKey, cacheTime.SlidingExpiration, Slide);


_webApiCache.Add(cachekey + Constants.ContentTypeKey,
contentType,
cacheTime.AbsoluteExpiration, baseKey);
cacheTime.AbsoluteExpiration, baseKey, cacheTime.SlidingExpiration, Slide);


_webApiCache.Add(cachekey + Constants.EtagKey,
etag,
cacheTime.AbsoluteExpiration, baseKey);
cacheTime.AbsoluteExpiration, baseKey, cacheTime.SlidingExpiration, Slide);


_webApiCache.Add(cachekey + Constants.GenerationTimestampKey,
actionExecutionTimestamp.ToString(),
cacheTime.AbsoluteExpiration, baseKey);
cacheTime.AbsoluteExpiration, baseKey, cacheTime.SlidingExpiration, Slide);

if (!String.IsNullOrEmpty(IncludeCustomHeaders))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public void selected_generator_with_internal_registration_is_used()
var client = new HttpClient(_server);
var result = client.GetAsync(_url + "cachekey/get_internalregistered").Result;

_cache.Verify(s => s.Add(It.Is<string>(x => x == "internal"), It.IsAny<byte[]>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.cachekeycontroller-get_internalregistered")), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "internal"), It.IsAny<byte[]>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.cachekeycontroller-get_internalregistered"), It.IsAny<TimeSpan>(), It.IsAny<bool>()), Times.Once());
}

[Test]
Expand Down
8 changes: 4 additions & 4 deletions test/WebApi.OutputCache.V2.Tests/CacheKeyGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public void custom_default_cache_key_generator_called_and_key_used()
var result = client.GetAsync(_url + "sample/Get_c100_s100").Result;

_cache.Verify(s => s.Contains(It.Is<string>(x => x == "keykeykey")), Times.Exactly(2));
_cache.Verify(s => s.Add(It.Is<string>(x => x == "keykeykey"), It.IsAny<byte[]>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100")), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "keykeykey:response-ct"), It.IsAny<object>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100")), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "keykeykey"), It.IsAny<byte[]>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100"), It.IsAny<TimeSpan>(), It.IsAny<bool>()), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "keykeykey:response-ct"), It.IsAny<object>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100"), It.IsAny<TimeSpan>(), It.IsAny<bool>()), Times.Once());

_keyGeneratorA.VerifyAll();
}
Expand All @@ -79,8 +79,8 @@ public void custom_cache_key_generator_called()
var result = client.GetAsync(_url + "cachekey/get_custom_key").Result;

_cache.Verify(s => s.Contains(It.Is<string>(x => x == "custom_key")), Times.Exactly(2));
_cache.Verify(s => s.Add(It.Is<string>(x => x == "custom_key"), It.IsAny<byte[]>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.cachekeycontroller-get_custom_key")), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "custom_key:response-ct"), It.IsAny<object>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.cachekeycontroller-get_custom_key")), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "custom_key"), It.IsAny<byte[]>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.cachekeycontroller-get_custom_key"), It.IsAny<TimeSpan>(), It.IsAny<bool>()), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "custom_key:response-ct"), It.IsAny<object>(), It.Is<DateTimeOffset>(x => x <= DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.cachekeycontroller-get_custom_key"), It.IsAny<TimeSpan>(), It.IsAny<bool>()), Times.Once());
}
}
}
4 changes: 2 additions & 2 deletions test/WebApi.OutputCache.V2.Tests/ConnegTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ public void subsequent_xml_request_is_not_cached()
var result = client.GetAsync(_url + "Get_c100_s100").Result;

_cache.Verify(s => s.Contains(It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100:application/json; charset=utf-8")), Times.Exactly(2));
_cache.Verify(s => s.Add(It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100:application/json; charset=utf-8"), It.IsAny<object>(), It.Is<DateTimeOffset>(x => x < DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100")), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100:application/json; charset=utf-8"), It.IsAny<object>(), It.Is<DateTimeOffset>(x => x < DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100"), It.IsAny<TimeSpan>(), It.IsAny<bool>()), Times.Once());

var req = new HttpRequestMessage(HttpMethod.Get, _url + "Get_c100_s100");
req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/xml"));

var result2 = client.SendAsync(req).Result;
_cache.Verify(s => s.Contains(It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100:text/xml; charset=utf-8")), Times.Exactly(2));
_cache.Verify(s => s.Add(It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100:text/xml; charset=utf-8"), It.IsAny<object>(), It.Is<DateTimeOffset>(x => x < DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100")), Times.Once());
_cache.Verify(s => s.Add(It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100:text/xml; charset=utf-8"), It.IsAny<object>(), It.Is<DateTimeOffset>(x => x < DateTime.Now.AddSeconds(100)), It.Is<string>(x => x == "webapi.outputcache.v2.tests.testcontrollers.samplecontroller-get_c100_s100"), It.IsAny<TimeSpan>(), It.IsAny<bool>()), Times.Once());

}

Expand Down
2 changes: 1 addition & 1 deletion test/WebApi.OutputCache.V2.Tests/MemoryCacheForTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public virtual bool Contains(string key)
return _cachedItems.ContainsKey(key);
}

public virtual void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null)
public virtual void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null, TimeSpan slidingExpiration = default(TimeSpan), bool slide = false)
{
_cachedItems.Add(key, o);
}
Expand Down
Loading