Skip to content

Commit 9adf5f4

Browse files
author
Freek van Zee
committed
Update IApiOutputCache to Async signatures
Removes obsolete Get signature. Updates Core library to Framework 4.5 to better facilitate Task methods. IApiOutputCache usages and implementations are adjusted to use the updated interface.
1 parent 46e553c commit 9adf5f4

18 files changed

+256
-211
lines changed

sample/WebApi.OutputCache.V2.Demo/TeamsController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Linq;
33
using System.Net;
44
using System.Net.Http;
5+
using System.Threading.Tasks;
56
using System.Web.Http;
67
using WebApi.OutputCache.V2.TimeAttributes;
78

@@ -37,7 +38,7 @@ public void Post(Team value)
3738
Teams.Add(value);
3839
}
3940

40-
public void Put(int id, Team value)
41+
public async Task Put(int id, Team value)
4142
{
4243
if (!ModelState.IsValid) throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
4344

@@ -48,7 +49,7 @@ public void Put(int id, Team value)
4849
team.Name = value.Name;
4950

5051
var cache = Configuration.CacheOutputConfiguration().GetCacheOutputProvider(Request);
51-
cache.RemoveStartsWith(Configuration.CacheOutputConfiguration().MakeBaseCachekey((TeamsController t) => t.GetById(0)));
52+
await cache.RemoveStartsWithAsync(Configuration.CacheOutputConfiguration().MakeBaseCachekey((TeamsController t) => t.GetById(0)));
5253
}
5354

5455
public void Delete(int id)

src/WebApi.OutputCache.Core/Cache/CacheExtensions.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
using System;
2+
using System.Threading.Tasks;
23

34
namespace WebApi.OutputCache.Core.Cache
45
{
56
public static class CacheExtensions
67
{
7-
public static T GetCachedResult<T>(this IApiOutputCache cache, string key, DateTimeOffset expiry, Func<T> resultGetter, bool bypassCache = true) where T : class
8+
public static async Task<T> GetCachedResultAsync<T>(this IApiOutputCache cache, string key, DateTimeOffset expiry, Func<T> resultGetter, bool bypassCache = true) where T : class
89
{
9-
var result = cache.Get<T>(key);
10+
var result = await cache.GetAsync<T>(key);
1011

1112
if (result == null || bypassCache)
1213
{
1314
result = resultGetter();
14-
if (result != null) cache.Add(key, result, expiry);
15+
if (result != null) await cache.AddAsync(key, result, expiry);
1516
}
1617

1718
return result;
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Threading.Tasks;
34

45
namespace WebApi.OutputCache.Core.Cache
56
{
67
public interface IApiOutputCache
78
{
8-
void RemoveStartsWith(string key);
9+
Task RemoveStartsWithAsync(string key);
910

10-
T Get<T>(string key) where T : class;
11+
Task<T> GetAsync<T>(string key) where T : class;
1112

12-
[Obsolete("Use Get<T> instead")]
13-
object Get(string key);
13+
Task RemoveAsync(string key);
1414

15-
void Remove(string key);
15+
Task<bool> ContainsAsync(string key);
1616

17-
bool Contains(string key);
17+
Task AddAsync(string key, object value, DateTimeOffset expiration, string dependsOnKey = null);
1818

19-
void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null);
20-
21-
IEnumerable<string> AllKeys { get; }
19+
Task<IEnumerable<string>> AllKeysAsync { get; }
2220
}
2321
}

src/WebApi.OutputCache.Core/Cache/MemoryCacheDefault.cs

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,42 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Runtime.Caching;
5+
using System.Threading.Tasks;
56

67
namespace WebApi.OutputCache.Core.Cache
78
{
89
public class MemoryCacheDefault : IApiOutputCache
910
{
1011
private static readonly MemoryCache Cache = MemoryCache.Default;
1112

12-
public virtual void RemoveStartsWith(string key)
13+
private static void RemoveStartsWith(string key)
1314
{
1415
lock (Cache)
1516
{
1617
Cache.Remove(key);
1718
}
1819
}
1920

20-
public virtual T Get<T>(string key) where T : class
21+
private static T Get<T>(string key) where T : class
2122
{
2223
var o = Cache.Get(key) as T;
2324
return o;
2425
}
2526

26-
[Obsolete("Use Get<T> instead")]
27-
public virtual object Get(string key)
28-
{
29-
return Cache.Get(key);
30-
}
31-
32-
public virtual void Remove(string key)
27+
private static void Remove(string key)
3328
{
3429
lock (Cache)
3530
{
3631
Cache.Remove(key);
3732
}
3833
}
3934

40-
public virtual bool Contains(string key)
35+
private static bool Contains(string key)
4136
{
4237
return Cache.Contains(key);
4338
}
4439

45-
public virtual void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null)
40+
private static void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null)
4641
{
4742
var cachePolicy = new CacheItemPolicy
4843
{
@@ -59,14 +54,39 @@ public virtual void Add(string key, object o, DateTimeOffset expiration, string
5954
{
6055
Cache.Add(key, o, cachePolicy);
6156
}
62-
}
57+
}
6358

64-
public virtual IEnumerable<string> AllKeys
59+
public virtual Task<IEnumerable<string>> AllKeysAsync
6560
{
6661
get
6762
{
68-
return Cache.Select(x => x.Key);
63+
return Task.FromResult(Cache.Select(x => x.Key));
6964
}
7065
}
66+
67+
public virtual Task RemoveStartsWithAsync(string key)
68+
{
69+
return Task.Run(() => RemoveStartsWith(key));
70+
}
71+
72+
public virtual Task<T> GetAsync<T>(string key) where T : class
73+
{
74+
return Task.FromResult(Get<T>(key));
75+
}
76+
77+
public virtual Task RemoveAsync(string key)
78+
{
79+
return Task.Run(() => Remove(key));
80+
}
81+
82+
public virtual Task<bool> ContainsAsync(string key)
83+
{
84+
return Task.FromResult(Contains(key));
85+
}
86+
87+
public virtual Task AddAsync(string key, object value, DateTimeOffset expiration, string dependsOnKey = null)
88+
{
89+
return Task.Run(() => Add(key, value, expiration, dependsOnKey));
90+
}
7191
}
7292
}

src/WebApi.OutputCache.Core/WebApi.OutputCache.Core.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
44
<PropertyGroup>
55
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -9,7 +9,7 @@
99
<AppDesignerFolder>Properties</AppDesignerFolder>
1010
<RootNamespace>WebApi.OutputCache.Core</RootNamespace>
1111
<AssemblyName>WebApi.OutputCache.Core</AssemblyName>
12-
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
12+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
1313
<FileAlignment>512</FileAlignment>
1414
<TargetFrameworkProfile />
1515
</PropertyGroup>
@@ -21,6 +21,7 @@
2121
<DefineConstants>DEBUG;TRACE</DefineConstants>
2222
<ErrorReport>prompt</ErrorReport>
2323
<WarningLevel>4</WarningLevel>
24+
<Prefer32Bit>false</Prefer32Bit>
2425
</PropertyGroup>
2526
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
2627
<DebugType>pdbonly</DebugType>
@@ -29,6 +30,7 @@
2930
<DefineConstants>TRACE</DefineConstants>
3031
<ErrorReport>prompt</ErrorReport>
3132
<WarningLevel>4</WarningLevel>
33+
<Prefer32Bit>false</Prefer32Bit>
3234
</PropertyGroup>
3335
<ItemGroup>
3436
<Reference Include="System" />

src/WebApi.OutputCache.V2/AutoInvalidateCacheOutputAttribute.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System.Linq;
55
using System.Net.Http;
66
using System.Reflection;
7+
using System.Threading;
8+
using System.Threading.Tasks;
79
using System.Web.Http;
810
using System.Web.Http.Controllers;
911
using System.Web.Http.Filters;
@@ -15,7 +17,7 @@ public sealed class AutoInvalidateCacheOutputAttribute : BaseCacheAttribute
1517
{
1618
public bool TryMatchType { get; set; }
1719

18-
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
20+
public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
1921
{
2022
if (actionExecutedContext.Response != null && !actionExecutedContext.Response.IsSuccessStatusCode) return;
2123
if (actionExecutedContext.ActionContext.Request.Method != HttpMethod.Post &&
@@ -33,9 +35,9 @@ public override void OnActionExecuted(HttpActionExecutedContext actionExecutedCo
3335
foreach (var action in actions)
3436
{
3537
var key = config.CacheOutputConfiguration().MakeBaseCachekey(controller.ControllerType.FullName, action);
36-
if (WebApiCache.Contains(key))
38+
if (await WebApiCache.ContainsAsync(key))
3739
{
38-
WebApiCache.RemoveStartsWith(key);
40+
await WebApiCache.RemoveStartsWithAsync(key);
3941
}
4042
}
4143
}

src/WebApi.OutputCache.V2/CacheOutputAttribute.cs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ protected virtual MediaTypeHeaderValue GetExpectedMediaType(HttpConfiguration co
166166
return responseMediaType;
167167
}
168168

169-
public override void OnActionExecuting(HttpActionContext actionContext)
169+
public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
170170
{
171171
if (actionContext == null) throw new ArgumentNullException("actionContext");
172172

@@ -183,11 +183,11 @@ public override void OnActionExecuting(HttpActionContext actionContext)
183183
actionContext.Request.Properties[CurrentRequestMediaType] = responseMediaType;
184184
var cachekey = cacheKeyGenerator.MakeCacheKey(actionContext, responseMediaType, ExcludeQueryStringFromCacheKey);
185185

186-
if (!_webApiCache.Contains(cachekey)) return;
186+
if (await _webApiCache.ContainsAsync(cachekey) == false) return;
187187

188188
if (actionContext.Request.Headers.IfNoneMatch != null)
189189
{
190-
var etag = _webApiCache.Get<string>(cachekey + Constants.EtagKey);
190+
var etag = await _webApiCache.GetAsync<string>(cachekey + Constants.EtagKey);
191191
if (etag != null)
192192
{
193193
if (actionContext.Request.Headers.IfNoneMatch.Any(x => x.Tag == etag))
@@ -203,11 +203,11 @@ public override void OnActionExecuting(HttpActionContext actionContext)
203203
}
204204
}
205205

206-
var val = _webApiCache.Get<byte[]>(cachekey);
206+
var val = await _webApiCache.GetAsync<byte[]>(cachekey);
207207
if (val == null) return;
208208

209-
var contenttype = _webApiCache.Get<MediaTypeHeaderValue>(cachekey + Constants.ContentTypeKey) ?? responseMediaType;
210-
var contentGeneration = _webApiCache.Get<string>(cachekey + Constants.GenerationTimestampKey);
209+
var contenttype = await _webApiCache.GetAsync<MediaTypeHeaderValue>(cachekey + Constants.ContentTypeKey) ?? responseMediaType;
210+
var contentGeneration = await _webApiCache.GetAsync<string>(cachekey + Constants.GenerationTimestampKey);
211211

212212
DateTimeOffset? contentGenerationTimestamp = null;
213213
if (contentGeneration != null)
@@ -222,7 +222,7 @@ public override void OnActionExecuting(HttpActionContext actionContext)
222222
actionContext.Response.Content = new ByteArrayContent(val);
223223

224224
actionContext.Response.Content.Headers.ContentType = contenttype;
225-
var responseEtag = _webApiCache.Get<string>(cachekey + Constants.EtagKey);
225+
var responseEtag = await _webApiCache.GetAsync<string>(cachekey + Constants.EtagKey);
226226
if (responseEtag != null) SetEtag(actionContext.Response, responseEtag);
227227

228228
var cacheTime = CacheTimeQuery.Execute(DateTime.Now);
@@ -246,7 +246,7 @@ public override async Task OnActionExecutedAsync(HttpActionExecutedContext actio
246246
var responseMediaType = actionExecutedContext.Request.Properties[CurrentRequestMediaType] as MediaTypeHeaderValue ?? GetExpectedMediaType(httpConfig, actionExecutedContext.ActionContext);
247247
var cachekey = cacheKeyGenerator.MakeCacheKey(actionExecutedContext.ActionContext, responseMediaType, ExcludeQueryStringFromCacheKey);
248248

249-
if (!string.IsNullOrWhiteSpace(cachekey) && !(_webApiCache.Contains(cachekey)))
249+
if (!string.IsNullOrWhiteSpace(cachekey) && !(await _webApiCache.ContainsAsync(cachekey)))
250250
{
251251
SetEtag(actionExecutedContext.Response, CreateEtag(actionExecutedContext, cachekey, cacheTime));
252252

@@ -262,16 +262,14 @@ public override async Task OnActionExecutedAsync(HttpActionExecutedContext actio
262262

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

265-
_webApiCache.Add(baseKey, string.Empty, cacheTime.AbsoluteExpiration);
266-
_webApiCache.Add(cachekey, content, cacheTime.AbsoluteExpiration, baseKey);
267-
265+
await _webApiCache.AddAsync(baseKey, string.Empty, cacheTime.AbsoluteExpiration);
266+
await _webApiCache.AddAsync(cachekey, content, cacheTime.AbsoluteExpiration, baseKey);
268267

269-
_webApiCache.Add(cachekey + Constants.ContentTypeKey,
268+
await _webApiCache.AddAsync(cachekey + Constants.ContentTypeKey,
270269
contentType,
271270
cacheTime.AbsoluteExpiration, baseKey);
272-
273-
274-
_webApiCache.Add(cachekey + Constants.EtagKey,
271+
272+
await _webApiCache.AddAsync(cachekey + Constants.EtagKey,
275273
etag,
276274
cacheTime.AbsoluteExpiration, baseKey);
277275

src/WebApi.OutputCache.V2/InvalidateCacheOutputAttribute.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Net.Http;
3+
using System.Threading;
4+
using System.Threading.Tasks;
35
using System.Web.Http.Filters;
46

57
namespace WebApi.OutputCache.V2
@@ -21,7 +23,7 @@ public InvalidateCacheOutputAttribute(string methodName, Type type = null)
2123
_methodName = methodName;
2224
}
2325

24-
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
26+
public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
2527
{
2628
if (actionExecutedContext.Response != null && !actionExecutedContext.Response.IsSuccessStatusCode) return;
2729
_controller = _controller ?? actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerType.FullName;
@@ -30,9 +32,9 @@ public override void OnActionExecuted(HttpActionExecutedContext actionExecutedCo
3032
EnsureCache(config, actionExecutedContext.Request);
3133

3234
var key = actionExecutedContext.Request.GetConfiguration().CacheOutputConfiguration().MakeBaseCachekey(_controller, _methodName);
33-
if (WebApiCache.Contains(key))
35+
if (await WebApiCache.ContainsAsync(key))
3436
{
35-
WebApiCache.RemoveStartsWith(key);
37+
await WebApiCache.RemoveStartsWithAsync(key);
3638
}
3739
}
3840
}

src/WebApi.OutputCache.V2/WebApi.OutputCache.V2.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
44
<PropertyGroup>
55
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

0 commit comments

Comments
 (0)