Skip to content

Commit 0314f6f

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 143427d commit 0314f6f

18 files changed

+255
-210
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: 12 additions & 14 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))
@@ -201,17 +201,17 @@ public override void OnActionExecuting(HttpActionContext actionContext)
201201
}
202202
}
203203

204-
var val = _webApiCache.Get<byte[]>(cachekey);
204+
var val = await _webApiCache.GetAsync<byte[]>(cachekey);
205205
if (val == null) return;
206206

207-
var contenttype = _webApiCache.Get<MediaTypeHeaderValue>(cachekey + Constants.ContentTypeKey) ?? responseMediaType;
207+
var contenttype = await _webApiCache.GetAsync<MediaTypeHeaderValue>(cachekey + Constants.ContentTypeKey) ?? responseMediaType;
208208
var contentGenerationTimestamp = DateTimeOffset.Parse(_webApiCache.Get<string>(cachekey + Constants.GenerationTimestampKey));
209209

210210
actionContext.Response = actionContext.Request.CreateResponse();
211211
actionContext.Response.Content = new ByteArrayContent(val);
212212

213213
actionContext.Response.Content.Headers.ContentType = contenttype;
214-
var responseEtag = _webApiCache.Get<string>(cachekey + Constants.EtagKey);
214+
var responseEtag = await _webApiCache.GetAsync<string>(cachekey + Constants.EtagKey);
215215
if (responseEtag != null) SetEtag(actionContext.Response, responseEtag);
216216

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

238-
if (!string.IsNullOrWhiteSpace(cachekey) && !(_webApiCache.Contains(cachekey)))
238+
if (!string.IsNullOrWhiteSpace(cachekey) && !(await _webApiCache.ContainsAsync(cachekey)))
239239
{
240240
SetEtag(actionExecutedContext.Response, CreateEtag(actionExecutedContext, cachekey, cacheTime));
241241

@@ -251,16 +251,14 @@ public override async Task OnActionExecutedAsync(HttpActionExecutedContext actio
251251

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

254-
_webApiCache.Add(baseKey, string.Empty, cacheTime.AbsoluteExpiration);
255-
_webApiCache.Add(cachekey, content, cacheTime.AbsoluteExpiration, baseKey);
256-
254+
await _webApiCache.AddAsync(baseKey, string.Empty, cacheTime.AbsoluteExpiration);
255+
await _webApiCache.AddAsync(cachekey, content, cacheTime.AbsoluteExpiration, baseKey);
257256

258-
_webApiCache.Add(cachekey + Constants.ContentTypeKey,
257+
await _webApiCache.AddAsync(cachekey + Constants.ContentTypeKey,
259258
contentType,
260259
cacheTime.AbsoluteExpiration, baseKey);
261-
262-
263-
_webApiCache.Add(cachekey + Constants.EtagKey,
260+
261+
await _webApiCache.AddAsync(cachekey + Constants.EtagKey,
264262
etag,
265263
cacheTime.AbsoluteExpiration, baseKey);
266264

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)