ASP.NET Web API通過ActionFilter來實現快取

FrankYou發表於2016-01-12
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading;
 5 using System.Threading.Tasks;
 6 using System.Web;
 7 using System.Web.Caching;
 8 using System.Web.Http;
 9 using System.Web.Http.Controllers;
10 using System.Web.Http.Filters;
11 
12 namespace WebApi
13 {
14     [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
15     public class CacheAttribute : ActionFilterAttribute
16     {
17         public string AbsoluteExpiration { get; set; }
18         public string SlidingExpiration { get; set; }
19         public CacheItemPriority Priority { get; set; }
20 
21         public CacheAttribute()
22         {
23             Priority = CacheItemPriority.Normal;
24         }
25 
26         public override void OnActionExecuting(HttpActionContext actionContext)
27         {
28             var actionDescriptor = actionContext.ActionDescriptor as ReflectedHttpActionDescriptor;
29             if (null == actionDescriptor)
30             {
31                 base.OnActionExecuting(actionContext);
32             }
33             var key = new CacheKey(actionDescriptor.MethodInfo, actionContext.ActionArguments);
34             var array = HttpRuntime.Cache.Get(key.ToString()) as object[];
35             if (null == array)
36             {
37                 base.OnActionExecuting(actionContext);
38                 return;
39             }
40             var value = array.Any() ? array[0] : null;
41             var actionResult = value as IHttpActionResult;
42             if (null != actionResult)
43             {
44                 actionContext.Response = actionResult.ExecuteAsync(CancellationToken.None).Result;
45                 return;
46             }
47             actionContext.Response = actionDescriptor.ResultConverter.Convert(actionContext.ControllerContext, value);
48         }
49     }
50 
51     public class CacheableActionDescriptor : ReflectedHttpActionDescriptor
52     {
53         private CacheAttribute CacheAttribute { get; }
54 
55         public CacheableActionDescriptor(ReflectedHttpActionDescriptor actionDescriptor, CacheAttribute cacheAttribute) : base(actionDescriptor.ControllerDescriptor, actionDescriptor.MethodInfo)
56         {
57             CacheAttribute = cacheAttribute;
58         }
59 
60         public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
61         {  
62             var absoluteExpiration = Cache.NoAbsoluteExpiration;
63             var slidingExpiration = Cache.NoSlidingExpiration;
64             var priority = CacheAttribute.Priority;
65             if (!string.IsNullOrWhiteSpace(CacheAttribute.AbsoluteExpiration))
66             {
67                 absoluteExpiration = DateTime.Now + TimeSpan.Parse(CacheAttribute.AbsoluteExpiration);
68             }
69             if (!string.IsNullOrWhiteSpace(CacheAttribute.SlidingExpiration))
70             {
71                 slidingExpiration = TimeSpan.Parse(CacheAttribute.SlidingExpiration);
72             }
73             var cacheKey = new CacheKey(MethodInfo, arguments);
74             var result = base.ExecuteAsync(controllerContext, arguments, cancellationToken).Result;
75             HttpRuntime.Cache.Insert(cacheKey.ToString(), new[] {result}, null, absoluteExpiration, slidingExpiration, priority, null);
76             return Task.FromResult(result);
77         }
78     }
79 
80     public class CacheableActionSelector : ApiControllerActionSelector
81     {
82         public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
83         {
84             var actionDescriptor = base.SelectAction(controllerContext);
85             var reflectedActionDescriptor = actionDescriptor as ReflectedHttpActionDescriptor;
86             if (null == reflectedActionDescriptor)
87             {
88                 return actionDescriptor;
89             }
90             var cacheAttribute = reflectedActionDescriptor.GetCustomAttributes<CacheAttribute>().FirstOrDefault() ??
91                                  reflectedActionDescriptor.ControllerDescriptor.GetCustomAttributes<CacheAttribute>().FirstOrDefault();
92             if (null == cacheAttribute)
93             {
94                 return actionDescriptor;
95             }
96             return new CacheableActionDescriptor(reflectedActionDescriptor, cacheAttribute);
97         }
98     }
99 }

註冊ActionSelector

 1 using System;
 2 using System.Web;
 3 using System.Web.Http;
 4 using System.Web.Http.Controllers;
 5 using WebApi;
 6 
 7 namespace WebHost
 8 {
 9     public class Global : HttpApplication
10     {
11         protected void Application_Start(object sender, EventArgs e)
12         {
13             // 註冊ASP.NET Web API路由
14             GlobalConfiguration.Configuration.Routes.MapHttpRoute("default", "api/{controller}/{id}", new { id = RouteParameter.Optional });
15 
16 
17             // 註冊CacheableActionSelector
18             GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpActionSelector), new CacheableActionSelector());
19         }
20     }
21 }

使用CacheAttribute

1     public class DemoController : ApiController
2     {
3         [Cache(AbsoluteExpiration = "00:00:02", SlidingExpiration = "", Priority = CacheItemPriority.High)]
4         public DateTime Get()
5         {
6             return DateTime.Now;
7         }
8     }

 

相關文章