Browse Source

[CacheControl] Imported v1.0

feature/package-cache-control
Robin Thoni 9 years ago
parent
commit
ec9b452a57

+ 245
- 0
CacheControl/Business/Attributes/CacheControlAttribute.cs View File

@@ -0,0 +1,245 @@
1
+using System;
2
+using System.Linq;
3
+using System.Net;
4
+using System.Net.Http;
5
+using System.Net.Http.Formatting;
6
+using System.Net.Http.Headers;
7
+using System.Runtime.ExceptionServices;
8
+using System.Text;
9
+using System.Threading;
10
+using System.Threading.Tasks;
11
+using System.Web.Http;
12
+using System.Web.Http.Controllers;
13
+using System.Web.Http.Filters;
14
+using iiie.CacheControl.Business.HttpExtensions;
15
+using iiie.CacheControl.Business.OutputCache;
16
+using iiie.CacheControl.DBO;
17
+
18
+namespace iiie.CacheControl.Attributes
19
+{
20
+    [AttributeUsage(AttributeTargets.Method)]
21
+    public abstract class CacheControlAttribute : FilterAttribute, IActionFilter
22
+    {
23
+        protected static MediaTypeHeaderValue DefaultMediaType = new MediaTypeHeaderValue("application/json");
24
+
25
+        /// <summary>
26
+        /// Indicates if the client can reuse cached data without asking origin server
27
+        /// </summary>
28
+        protected bool MustRevalidate { get; set; }
29
+
30
+        /// <summary>
31
+        /// Indicates if the query string must be used to control cache
32
+        /// </summary>
33
+        protected bool ExcludeQueryStringFromCacheKey { get; set; }
34
+
35
+        /// <summary>
36
+        /// Define the cache type used to store cache
37
+        /// </summary>
38
+        protected OutputCacheType CacheType { get; set; }
39
+
40
+        protected Type CacheKeyGenerator { get; set; }
41
+
42
+        private MediaTypeHeaderValue _responseMediaType;
43
+
44
+        private IOutputCache _webCache;
45
+
46
+        protected void EnsureCache(HttpConfiguration config, HttpRequestMessage req)
47
+        {
48
+            _webCache = config.CacheOutputConfiguration(CacheType).GetCacheOutputProvider(req);
49
+        }
50
+
51
+        protected abstract bool IsValid(CacheDbo data);
52
+
53
+        protected virtual CacheDbo CreateCacheUser()
54
+        {
55
+            return new CacheDbo();
56
+        }
57
+
58
+        protected virtual MediaTypeHeaderValue GetExpectedMediaType(HttpConfiguration config, HttpActionContext actionContext)
59
+        {
60
+            MediaTypeHeaderValue responseMediaType = null;
61
+
62
+            var negotiator = config.Services.GetService(typeof(IContentNegotiator)) as IContentNegotiator;
63
+            var returnType = actionContext.ActionDescriptor.ReturnType;
64
+
65
+            if (negotiator != null && returnType != typeof(HttpResponseMessage))
66
+            {
67
+                var negotiatedResult = negotiator.Negotiate(returnType, actionContext.Request, config.Formatters);
68
+                responseMediaType = negotiatedResult.MediaType;
69
+                responseMediaType.CharSet = Encoding.UTF8.HeaderName;
70
+            }
71
+            else
72
+            {
73
+                if (actionContext.Request.Headers.Accept != null)
74
+                {
75
+                    responseMediaType = actionContext.Request.Headers.Accept.FirstOrDefault();
76
+                    if (responseMediaType == null ||
77
+                        !config.Formatters.Any(x => x.SupportedMediaTypes.Contains(responseMediaType)))
78
+                    {
79
+                        DefaultMediaType.CharSet = Encoding.UTF8.HeaderName;
80
+                        return DefaultMediaType;
81
+                    }
82
+                }
83
+            }
84
+
85
+            return responseMediaType;
86
+        }
87
+
88
+        private void OnActionExecuting(HttpActionContext actionContext)
89
+        {
90
+            if (actionContext == null) throw new ArgumentNullException("actionContext");
91
+
92
+            var config = actionContext.Request.GetConfiguration();
93
+
94
+            EnsureCache(config, actionContext.Request);
95
+
96
+            var cacheKeyGenerator = config.CacheOutputConfiguration(CacheType).GetCacheKeyGenerator(actionContext.Request, CacheKeyGenerator);
97
+
98
+            _responseMediaType = GetExpectedMediaType(config, actionContext);
99
+
100
+            var cachekey = cacheKeyGenerator.MakeCacheKey(actionContext, _responseMediaType, CacheType, ExcludeQueryStringFromCacheKey);
101
+
102
+            var data = _webCache.Get(cachekey) as CacheDbo;
103
+            if (data == null) return;
104
+
105
+            if (!IsValid(data))
106
+            {
107
+                _webCache.Remove(cachekey);
108
+                return;
109
+            }
110
+
111
+            if (actionContext.Request.Headers.IfNoneMatch != null)
112
+            {
113
+                if (data.ETag != null)
114
+                {
115
+                    if (actionContext.Request.Headers.IfNoneMatch.Any(x => x.Tag == data.ETag))
116
+                    {
117
+                        var quickResponse = actionContext.Request.CreateResponse(HttpStatusCode.NotModified);
118
+                        ApplyCacheHeaders(quickResponse);
119
+                        actionContext.Response = quickResponse;
120
+                        return;
121
+                    }
122
+                }
123
+            }
124
+
125
+            if (data.Content == null) return;
126
+
127
+            actionContext.Response = actionContext.Request.CreateResponse();
128
+            actionContext.Response.Content = new ByteArrayContent(data.Content);
129
+
130
+            actionContext.Response.Content.Headers.ContentType = new MediaTypeHeaderValue(data.ContentType);
131
+            if (data.ETag != null) SetEtag(actionContext.Response, data.ETag);
132
+
133
+            ApplyCacheHeaders(actionContext.Response);
134
+        }
135
+
136
+        private async Task OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
137
+        {
138
+            if (actionExecutedContext.ActionContext.Response == null || !actionExecutedContext.ActionContext.Response.IsSuccessStatusCode) return;
139
+
140
+            var config = actionExecutedContext.Request.GetConfiguration().CacheOutputConfiguration(CacheType);
141
+            var cacheKeyGenerator = config.GetCacheKeyGenerator(actionExecutedContext.Request, CacheKeyGenerator);
142
+
143
+            var cachekey = cacheKeyGenerator.MakeCacheKey(actionExecutedContext.ActionContext, _responseMediaType, CacheType, ExcludeQueryStringFromCacheKey);
144
+
145
+            if (!string.IsNullOrWhiteSpace(cachekey) && !(_webCache.Contains(cachekey)))
146
+            {
147
+                SetEtag(actionExecutedContext.Response, Guid.NewGuid().ToString());
148
+
149
+                if (actionExecutedContext.Response.Content != null)
150
+                {
151
+                    var data = CreateCacheUser();
152
+                    data.Content = await actionExecutedContext.Response.Content.ReadAsByteArrayAsync();
153
+                    data.ContentType = actionExecutedContext.Response.Content.Headers.ContentType.MediaType;
154
+                    data.ETag = actionExecutedContext.Response.Headers.ETag.Tag;
155
+                    data.Date = DateTime.Now;
156
+
157
+                    _webCache.Add(cachekey, data);
158
+                }
159
+            }
160
+
161
+            ApplyCacheHeaders(actionExecutedContext.ActionContext.Response);
162
+        }
163
+
164
+        private void ApplyCacheHeaders(HttpResponseMessage response)
165
+        {
166
+            if (MustRevalidate)
167
+            {
168
+                response.Headers.CacheControl = new CacheControlHeaderValue
169
+                {
170
+                    MustRevalidate = MustRevalidate
171
+                };
172
+            }
173
+        }
174
+
175
+        private static void SetEtag(HttpResponseMessage message, string etag)
176
+        {
177
+            if (etag != null)
178
+            {
179
+                message.Headers.ETag = new EntityTagHeaderValue(@"""" + etag.Replace("\"", string.Empty) + @"""");
180
+            }
181
+        }
182
+
183
+        Task<HttpResponseMessage> IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
184
+        {
185
+            if (actionContext == null)
186
+            {
187
+                throw new ArgumentNullException("actionContext");
188
+            }
189
+
190
+            if (continuation == null)
191
+            {
192
+                throw new ArgumentNullException("continuation");
193
+            }
194
+
195
+            OnActionExecuting(actionContext);
196
+
197
+            if (actionContext.Response != null)
198
+            {
199
+                return Task.FromResult(actionContext.Response);
200
+            }
201
+
202
+            return CallOnActionExecutedAsync(actionContext, cancellationToken, continuation);
203
+        }
204
+
205
+        private async Task<HttpResponseMessage> CallOnActionExecutedAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
206
+        {
207
+            cancellationToken.ThrowIfCancellationRequested();
208
+
209
+            HttpResponseMessage response = null;
210
+            Exception exception = null;
211
+            try
212
+            {
213
+                response = await continuation();
214
+            }
215
+            catch (Exception e)
216
+            {
217
+                exception = e;
218
+            }
219
+
220
+            try
221
+            {
222
+                var executedContext = new HttpActionExecutedContext(actionContext, exception) { Response = response };
223
+                await OnActionExecuted(executedContext);
224
+
225
+                if (executedContext.Response != null)
226
+                {
227
+                    return executedContext.Response;
228
+                }
229
+
230
+                if (executedContext.Exception != null)
231
+                {
232
+                    ExceptionDispatchInfo.Capture(executedContext.Exception).Throw();
233
+                }
234
+            }
235
+            catch (Exception e)
236
+            {
237
+                actionContext.Response = null;
238
+                ExceptionDispatchInfo.Capture(e).Throw();
239
+            }
240
+
241
+            throw new InvalidOperationException(GetType().Name);
242
+        }
243
+
244
+    }
245
+}

+ 44
- 0
CacheControl/Business/Attributes/TimeCacheControlAttribute.cs View File

@@ -0,0 +1,44 @@
1
+using System;
2
+using iiie.CacheControl.Attributes;
3
+using iiie.CacheControl.Business.OutputCache;
4
+using iiie.CacheControl.DBO;
5
+
6
+namespace iiie.CacheControl.Business.Attributes
7
+{
8
+    /// <summary>
9
+    /// A basic cache control based on time
10
+    /// </summary>
11
+    public class TimeCacheControlAttribute : CacheControlAttribute
12
+    {
13
+        /// <summary>
14
+        /// The number of seconds the cache is valid
15
+        /// </summary>
16
+        protected int Seconds { get; set; }
17
+
18
+        /// <summary>
19
+        /// Contruct a cache control based on time
20
+        /// </summary>
21
+        /// <param name="seconds">The number of seconds the cache is valid</param>
22
+        /// <param name="mustRevalidate">Indicates if the client can reuse cached data without asking origin server</param>
23
+        /// <param name="excludeQueryStringFromCacheKey">Indicates if the query string must be used to control cache</param>
24
+        /// <param name="cacheType">Define the cache type used to store cache</param>
25
+        public TimeCacheControlAttribute(int seconds, bool mustRevalidate = true,
26
+            bool excludeQueryStringFromCacheKey = false, OutputCacheType cacheType = OutputCacheType.Memory)
27
+        {
28
+            Seconds = seconds;
29
+            MustRevalidate = mustRevalidate;
30
+            ExcludeQueryStringFromCacheKey = excludeQueryStringFromCacheKey;
31
+            CacheType = cacheType;
32
+        }
33
+
34
+        /// <summary>
35
+        /// Check if data has been cached for less than Senconds seconds
36
+        /// </summary>
37
+        /// <param name="data">The cached data</param>
38
+        /// <returns>True if cache is still valid</returns>
39
+        protected override bool IsValid(CacheDbo data)
40
+        {
41
+            return data.Date.AddSeconds(Seconds) >= DateTime.Now;
42
+        }
43
+    }
44
+}

+ 80
- 0
CacheControl/Business/CacheKey/DefaultCacheKeyGenerator.cs View File

@@ -0,0 +1,80 @@
1
+using System.Collections;
2
+using System.Collections.Generic;
3
+using System.Linq;
4
+using System.Net.Http;
5
+using System.Net.Http.Headers;
6
+using System.Web.Http.Controllers;
7
+using iiie.CacheControl.Business.HttpExtensions;
8
+using iiie.CacheControl.Business.OutputCache;
9
+
10
+namespace iiie.CacheControl.Business.CacheKey
11
+{
12
+    public class DefaultCacheKeyGenerator : ICacheKeyGenerator
13
+    {
14
+        public virtual string MakeCacheKey(HttpActionContext context, MediaTypeHeaderValue mediaType, OutputCacheType cacheType, bool excludeQueryString = false)
15
+        {
16
+            var controller = context.ControllerContext.ControllerDescriptor.ControllerName;
17
+            var action = context.ActionDescriptor.ActionName;
18
+            var key = context.Request.GetConfiguration().CacheOutputConfiguration(cacheType).MakeBaseCachekey(controller, action);
19
+            var actionParameters = context.ActionArguments.Where(x => x.Value != null).Select(x => x.Key + "=" + GetValue(x.Value));
20
+
21
+            string parameters;
22
+
23
+            if (!excludeQueryString)
24
+            {
25
+                var queryStringParameters =
26
+                    context.Request.GetQueryNameValuePairs()
27
+                           .Where(x => x.Key.ToLower() != "callback" && x.Key.ToLower() != "_")
28
+                           .Select(x => x.Key + "=" + x.Value);
29
+                var parametersCollections = actionParameters.Union(queryStringParameters);
30
+                parameters = "-" + string.Join("&", parametersCollections);
31
+
32
+                var callbackValue = GetJsonpCallback(context.Request);
33
+                if (!string.IsNullOrWhiteSpace(callbackValue))
34
+                {
35
+                    var callback = "callback=" + callbackValue;
36
+                    if (parameters.Contains("&" + callback)) parameters = parameters.Replace("&" + callback, string.Empty);
37
+                    if (parameters.Contains(callback + "&")) parameters = parameters.Replace(callback + "&", string.Empty);
38
+                    if (parameters.Contains("-" + callback)) parameters = parameters.Replace("-" + callback, string.Empty);
39
+                    if (parameters.EndsWith("&")) parameters = parameters.TrimEnd('&');
40
+                }
41
+            }
42
+            else
43
+            {
44
+                parameters = "-" + string.Join("&", actionParameters);
45
+            }
46
+
47
+            if (parameters == "-") parameters = string.Empty;
48
+
49
+            var cachekey = string.Format("{0}{1}:{2}", key, parameters, mediaType.MediaType);
50
+            return cachekey;
51
+        }
52
+
53
+        private string GetJsonpCallback(HttpRequestMessage request)
54
+        {
55
+            var callback = string.Empty;
56
+            if (request.Method == HttpMethod.Get)
57
+            {
58
+                var query = request.GetQueryNameValuePairs();
59
+
60
+                if (query != null)
61
+                {
62
+                    var queryVal = query.FirstOrDefault(x => x.Key.ToLower() == "callback");
63
+                    if (!queryVal.Equals(default(KeyValuePair<string, string>))) callback = queryVal.Value;
64
+                }
65
+            }
66
+            return callback;
67
+        }
68
+
69
+        private string GetValue(object val)
70
+        {
71
+            if (val is IEnumerable && !(val is string))
72
+            {
73
+                var concatValue = string.Empty;
74
+                var paramArray = val as IEnumerable;
75
+                return paramArray.Cast<object>().Aggregate(concatValue, (current, paramValue) => current + (paramValue + ";"));
76
+            }
77
+            return val.ToString();
78
+        }
79
+    }
80
+}

+ 11
- 0
CacheControl/Business/CacheKey/ICacheKeyGenerator.cs View File

@@ -0,0 +1,11 @@
1
+using System.Net.Http.Headers;
2
+using System.Web.Http.Controllers;
3
+using iiie.CacheControl.Business.OutputCache;
4
+
5
+namespace iiie.CacheControl.Business.CacheKey
6
+{
7
+    public interface ICacheKeyGenerator
8
+    {
9
+        string MakeCacheKey(HttpActionContext context, MediaTypeHeaderValue mediaType, OutputCacheType cacheType, bool excludeQueryString = false);
10
+    }
11
+}

+ 108
- 0
CacheControl/Business/HttpExtensions/CacheOutputConfiguration.cs View File

@@ -0,0 +1,108 @@
1
+using System;
2
+using System.Linq;
3
+using System.Linq.Expressions;
4
+using System.Net.Http;
5
+using System.Reflection;
6
+using System.Web.Http;
7
+using iiie.CacheControl.Business.CacheKey;
8
+using iiie.CacheControl.Business.OutputCache;
9
+
10
+namespace iiie.CacheControl.Business.HttpExtensions
11
+{
12
+    public class CacheOutputConfiguration
13
+    {
14
+        private readonly HttpConfiguration _configuration;
15
+
16
+        private OutputCacheType _cacheType;
17
+
18
+        public CacheOutputConfiguration(HttpConfiguration configuration, OutputCacheType type)
19
+        {
20
+            _configuration = configuration;
21
+            _cacheType = type;
22
+        }
23
+
24
+        public void RegisterCacheOutputProvider(Func<IOutputCache> provider)
25
+        {
26
+            _configuration.Properties.GetOrAdd(typeof(IOutputCache), x => provider);
27
+        }
28
+
29
+        public void RegisterCacheKeyGeneratorProvider<T>(Func<T> provider)
30
+            where T : ICacheKeyGenerator
31
+        {
32
+            _configuration.Properties.GetOrAdd(typeof(T), x => provider);
33
+        }
34
+
35
+        public void RegisterDefaultCacheKeyGeneratorProvider(Func<ICacheKeyGenerator> provider)
36
+        {
37
+            RegisterCacheKeyGeneratorProvider(provider);
38
+        }
39
+
40
+        public string MakeBaseCachekey(string controller, string action)
41
+        {
42
+            return string.Format("{0}-{1}", controller.ToLower(), action.ToLower());
43
+        }
44
+
45
+        public string MakeBaseCachekey<T, U>(Expression<Func<T, U>> expression)
46
+        {
47
+            var method = expression.Body as MethodCallExpression;
48
+            if (method == null) throw new ArgumentException("Expression is wrong");
49
+
50
+            var methodName = method.Method.Name;
51
+            var nameAttribs = method.Method.GetCustomAttributes(typeof(ActionNameAttribute), false);
52
+            if (nameAttribs.Any())
53
+            {
54
+                var actionNameAttrib = (ActionNameAttribute)nameAttribs.FirstOrDefault();
55
+                if (actionNameAttrib != null)
56
+                {
57
+                    methodName = actionNameAttrib.Name;
58
+                }
59
+            }
60
+
61
+            return string.Format("{0}-{1}", typeof(T).Name.Replace("Controller", string.Empty).ToLower(), methodName.ToLower());
62
+        }
63
+
64
+        private static ICacheKeyGenerator TryActivateCacheKeyGenerator(Type generatorType)
65
+        {
66
+            var hasEmptyOrDefaultConstructor =
67
+                generatorType.GetConstructor(Type.EmptyTypes) != null ||
68
+                generatorType.GetConstructors(BindingFlags.Instance | BindingFlags.Public)
69
+                .Any(x => x.GetParameters().All(p => p.IsOptional));
70
+            return hasEmptyOrDefaultConstructor
71
+                ? Activator.CreateInstance(generatorType) as ICacheKeyGenerator
72
+                : null;
73
+        }
74
+
75
+        public ICacheKeyGenerator GetCacheKeyGenerator(HttpRequestMessage request, Type generatorType)
76
+        {
77
+            generatorType = generatorType ?? typeof(ICacheKeyGenerator);
78
+            object cache;
79
+            _configuration.Properties.TryGetValue(generatorType, out cache);
80
+
81
+            var cacheFunc = cache as Func<ICacheKeyGenerator>;
82
+
83
+            var generator = cacheFunc != null
84
+                ? cacheFunc()
85
+                : request.GetDependencyScope().GetService(generatorType) as ICacheKeyGenerator;
86
+
87
+            return generator
88
+                ?? TryActivateCacheKeyGenerator(generatorType)
89
+                ?? new DefaultCacheKeyGenerator();
90
+        }
91
+
92
+        public IOutputCache GetCacheOutputProvider(HttpRequestMessage request)
93
+        {
94
+            object cache;
95
+            _configuration.Properties.TryGetValue(typeof(IOutputCache), out cache);
96
+
97
+            var cacheFunc = cache as Func<IOutputCache>;
98
+
99
+            var cacheOutputProvider = cacheFunc != null ? cacheFunc() : request.GetDependencyScope().GetService(typeof(IOutputCache)) as IOutputCache;
100
+            if (cacheOutputProvider == null)
101
+            {
102
+                if (_cacheType == OutputCacheType.File)
103
+                cacheOutputProvider = new MemoryOutputCache();
104
+            }
105
+            return cacheOutputProvider;
106
+        }
107
+    }
108
+}

+ 13
- 0
CacheControl/Business/HttpExtensions/HttpConfigurationExtensions.cs View File

@@ -0,0 +1,13 @@
1
+using System.Web.Http;
2
+using iiie.CacheControl.Business.OutputCache;
3
+
4
+namespace iiie.CacheControl.Business.HttpExtensions
5
+{
6
+    public static class HttpConfigurationExtensions
7
+    {
8
+        public static CacheOutputConfiguration CacheOutputConfiguration(this HttpConfiguration config, OutputCacheType type)
9
+        {
10
+            return new CacheOutputConfiguration(config, type);
11
+        }
12
+    }
13
+}

+ 40
- 0
CacheControl/Business/OutputCache/FileOuputCache.cs View File

@@ -0,0 +1,40 @@
1
+using System;
2
+using System.Collections.Generic;
3
+
4
+namespace iiie.CacheControl.Business.OutputCache
5
+{
6
+    public class FileOuputCache : IOutputCache
7
+    {
8
+        public void RemoveStartsWith(string key)
9
+        {
10
+            throw new NotImplementedException();
11
+        }
12
+
13
+        public T Get<T>(string key) where T : class
14
+        {
15
+            throw new NotImplementedException();
16
+        }
17
+
18
+        public object Get(string key)
19
+        {
20
+            throw new NotImplementedException();
21
+        }
22
+
23
+        public void Remove(string key)
24
+        {
25
+            throw new NotImplementedException();
26
+        }
27
+
28
+        public bool Contains(string key)
29
+        {
30
+            throw new NotImplementedException();
31
+        }
32
+
33
+        public void Add(string key, object o, string dependsOnKey = null)
34
+        {
35
+            throw new NotImplementedException();
36
+        }
37
+
38
+        public IEnumerable<string> AllKeys { get; private set; }
39
+    }
40
+}

+ 15
- 0
CacheControl/Business/OutputCache/IOutputCache.cs View File

@@ -0,0 +1,15 @@
1
+using System.Collections.Generic;
2
+
3
+namespace iiie.CacheControl.Business.OutputCache
4
+{
5
+    public interface IOutputCache
6
+    {
7
+        void RemoveStartsWith(string key);
8
+        T Get<T>(string key) where T : class;
9
+        object Get(string key);
10
+        void Remove(string key);
11
+        bool Contains(string key);
12
+        void Add(string key, object o, string dependsOnKey = null);
13
+        IEnumerable<string> AllKeys { get; }
14
+    }
15
+}

+ 67
- 0
CacheControl/Business/OutputCache/MemoryOutputCache.cs View File

@@ -0,0 +1,67 @@
1
+using System.Collections.Generic;
2
+using System.Linq;
3
+using System.Runtime.Caching;
4
+
5
+namespace iiie.CacheControl.Business.OutputCache
6
+{
7
+    public class MemoryOutputCache : IOutputCache
8
+    {
9
+        private static readonly MemoryCache Cache = MemoryCache.Default;
10
+
11
+        public void RemoveStartsWith(string key)
12
+        {
13
+            lock (Cache)
14
+            {
15
+                Cache.Remove(key);
16
+            }
17
+        }
18
+
19
+        public T Get<T>(string key) where T : class
20
+        {
21
+            var o = Cache.Get(key) as T;
22
+            return o;
23
+        }
24
+
25
+        public object Get(string key)
26
+        {
27
+            return Cache.Get(key);
28
+        }
29
+
30
+        public void Remove(string key)
31
+        {
32
+            lock (Cache)
33
+            {
34
+                Cache.Remove(key);
35
+            }
36
+        }
37
+
38
+        public bool Contains(string key)
39
+        {
40
+            return Cache.Contains(key);
41
+        }
42
+
43
+        public void Add(string key, object o, string dependsOnKey = null)
44
+        {
45
+            var cachePolicy = new CacheItemPolicy();
46
+
47
+            if (!string.IsNullOrWhiteSpace(dependsOnKey))
48
+            {
49
+                cachePolicy.ChangeMonitors.Add(
50
+                    Cache.CreateCacheEntryChangeMonitor(new[] { dependsOnKey })
51
+                );
52
+            }
53
+            lock (Cache)
54
+            {
55
+                Cache.Add(key, o, cachePolicy);
56
+            }
57
+        }
58
+
59
+        public IEnumerable<string> AllKeys
60
+        {
61
+            get
62
+            {
63
+                return Cache.Select(x => x.Key);
64
+            }
65
+        }
66
+    }
67
+}

+ 19
- 0
CacheControl/Business/OutputCache/OutputCacheType.cs View File

@@ -0,0 +1,19 @@
1
+
2
+namespace iiie.CacheControl.Business.OutputCache
3
+{
4
+    /// <summary>
5
+    /// The different cache storages
6
+    /// </summary>
7
+    public enum OutputCacheType
8
+    {
9
+        /// <summary>
10
+        /// Cache is stored in memory
11
+        /// </summary>
12
+        Memory,
13
+
14
+        /// <summary>
15
+        /// Cache is stroed in a temp file
16
+        /// </summary>
17
+        File
18
+    }
19
+}

+ 84
- 0
CacheControl/CacheControl.csproj View File

@@ -0,0 +1,84 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4
+  <PropertyGroup>
5
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7
+    <ProjectGuid>{BA63D177-BE9E-41E0-89F5-3D134A26A604}</ProjectGuid>
8
+    <OutputType>Library</OutputType>
9
+    <AppDesignerFolder>Properties</AppDesignerFolder>
10
+    <RootNamespace>CacheControl</RootNamespace>
11
+    <AssemblyName>CacheControl</AssemblyName>
12
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13
+    <FileAlignment>512</FileAlignment>
14
+  </PropertyGroup>
15
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16
+    <DebugSymbols>true</DebugSymbols>
17
+    <DebugType>full</DebugType>
18
+    <Optimize>false</Optimize>
19
+    <OutputPath>bin\Debug\</OutputPath>
20
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
21
+    <ErrorReport>prompt</ErrorReport>
22
+    <WarningLevel>4</WarningLevel>
23
+  </PropertyGroup>
24
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
25
+    <DebugType>pdbonly</DebugType>
26
+    <Optimize>true</Optimize>
27
+    <OutputPath>bin\Release\</OutputPath>
28
+    <DefineConstants>TRACE</DefineConstants>
29
+    <ErrorReport>prompt</ErrorReport>
30
+    <WarningLevel>4</WarningLevel>
31
+  </PropertyGroup>
32
+  <ItemGroup>
33
+    <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
34
+      <SpecificVersion>False</SpecificVersion>
35
+      <HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
36
+    </Reference>
37
+    <Reference Include="System" />
38
+    <Reference Include="System.Core" />
39
+    <Reference Include="System.Net.Http" />
40
+    <Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
41
+      <SpecificVersion>False</SpecificVersion>
42
+      <HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
43
+    </Reference>
44
+    <Reference Include="System.Runtime.Caching" />
45
+    <Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
46
+      <SpecificVersion>False</SpecificVersion>
47
+      <HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath>
48
+    </Reference>
49
+    <Reference Include="System.Web.Http.WebHost, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
50
+      <SpecificVersion>False</SpecificVersion>
51
+      <HintPath>..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll</HintPath>
52
+    </Reference>
53
+    <Reference Include="System.Xml.Linq" />
54
+    <Reference Include="System.Data.DataSetExtensions" />
55
+    <Reference Include="Microsoft.CSharp" />
56
+    <Reference Include="System.Data" />
57
+    <Reference Include="System.Xml" />
58
+  </ItemGroup>
59
+  <ItemGroup>
60
+    <Compile Include="Business\Attributes\CacheControlAttribute.cs" />
61
+    <Compile Include="Business\Attributes\TimeCacheControlAttribute.cs" />
62
+    <Compile Include="Business\CacheKey\DefaultCacheKeyGenerator.cs" />
63
+    <Compile Include="Business\CacheKey\ICacheKeyGenerator.cs" />
64
+    <Compile Include="Business\HttpExtensions\CacheOutputConfiguration.cs" />
65
+    <Compile Include="Business\HttpExtensions\HttpConfigurationExtensions.cs" />
66
+    <Compile Include="Business\OutputCache\FileOuputCache.cs" />
67
+    <Compile Include="Business\OutputCache\IOutputCache.cs" />
68
+    <Compile Include="Business\OutputCache\MemoryOutputCache.cs" />
69
+    <Compile Include="Business\OutputCache\OutputCacheType.cs" />
70
+    <Compile Include="DBO\CacheDbo.cs" />
71
+    <Compile Include="Properties\AssemblyInfo.cs" />
72
+  </ItemGroup>
73
+  <ItemGroup>
74
+    <None Include="packages.config" />
75
+  </ItemGroup>
76
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
77
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
78
+       Other similar extension points exist, see Microsoft.Common.targets.
79
+  <Target Name="BeforeBuild">
80
+  </Target>
81
+  <Target Name="AfterBuild">
82
+  </Target>
83
+  -->
84
+</Project>

+ 30
- 0
CacheControl/DBO/CacheDBO.cs View File

@@ -0,0 +1,30 @@
1
+using System;
2
+
3
+namespace iiie.CacheControl.DBO
4
+{
5
+    /// <summary>
6
+    /// Basic fields for data to be cached
7
+    /// </summary>
8
+    public class CacheDbo
9
+    {
10
+        /// <summary>
11
+        /// The content type of the data
12
+        /// </summary>
13
+        public string ContentType { get; set; }
14
+
15
+        /// <summary>
16
+        /// The data itself
17
+        /// </summary>
18
+        public byte[] Content { get; set; }
19
+
20
+        /// <summary>
21
+        /// The e tag to identify cache
22
+        /// </summary>
23
+        public string ETag { get; set; }
24
+
25
+        /// <summary>
26
+        /// The date to data was first cached
27
+        /// </summary>
28
+        public DateTime Date { get; set; }
29
+    }
30
+}

+ 36
- 0
CacheControl/Properties/AssemblyInfo.cs View File

@@ -0,0 +1,36 @@
1
+using System.Reflection;
2
+using System.Runtime.CompilerServices;
3
+using System.Runtime.InteropServices;
4
+
5
+// General Information about an assembly is controlled through the following 
6
+// set of attributes. Change these attribute values to modify the information
7
+// associated with an assembly.
8
+[assembly: AssemblyTitle("CacheControl")]
9
+[assembly: AssemblyDescription("")]
10
+[assembly: AssemblyConfiguration("")]
11
+[assembly: AssemblyCompany("")]
12
+[assembly: AssemblyProduct("CacheControl")]
13
+[assembly: AssemblyCopyright("Copyright ©  2015")]
14
+[assembly: AssemblyTrademark("")]
15
+[assembly: AssemblyCulture("")]
16
+
17
+// Setting ComVisible to false makes the types in this assembly not visible 
18
+// to COM components.  If you need to access a type in this assembly from 
19
+// COM, set the ComVisible attribute to true on that type.
20
+[assembly: ComVisible(false)]
21
+
22
+// The following GUID is for the ID of the typelib if this project is exposed to COM
23
+[assembly: Guid("087758c5-539f-49d1-b9e9-771f42697459")]
24
+
25
+// Version information for an assembly consists of the following four values:
26
+//
27
+//      Major Version
28
+//      Minor Version 
29
+//      Build Number
30
+//      Revision
31
+//
32
+// You can specify all the values or you can default the Build and Revision Numbers 
33
+// by using the '*' as shown below:
34
+// [assembly: AssemblyVersion("1.0.*")]
35
+[assembly: AssemblyVersion("1.0.0.0")]
36
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 8
- 0
CacheControl/packages.config View File

@@ -0,0 +1,8 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<packages>
3
+  <package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net45" />
4
+  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net45" />
5
+  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net45" />
6
+  <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.3" targetFramework="net45" />
7
+  <package id="Newtonsoft.Json" version="6.0.8" targetFramework="net45" />
8
+</packages>

+ 6
- 0
NuGet-3ie.sln View File

@@ -5,6 +5,8 @@ VisualStudioVersion = 12.0.21005.1
5 5
 MinimumVisualStudioVersion = 10.0.40219.1
6 6
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGet-server", "NuGet-server\NuGet-server.csproj", "{23F13185-BFE0-435A-8772-36DA53DA5BDA}"
7 7
 EndProject
8
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CacheControl", "CacheControl\CacheControl.csproj", "{BA63D177-BE9E-41E0-89F5-3D134A26A604}"
9
+EndProject
8 10
 Global
9 11
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 12
 		Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
15 17
 		{23F13185-BFE0-435A-8772-36DA53DA5BDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 18
 		{23F13185-BFE0-435A-8772-36DA53DA5BDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 19
 		{23F13185-BFE0-435A-8772-36DA53DA5BDA}.Release|Any CPU.Build.0 = Release|Any CPU
20
+		{BA63D177-BE9E-41E0-89F5-3D134A26A604}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21
+		{BA63D177-BE9E-41E0-89F5-3D134A26A604}.Debug|Any CPU.Build.0 = Debug|Any CPU
22
+		{BA63D177-BE9E-41E0-89F5-3D134A26A604}.Release|Any CPU.ActiveCfg = Release|Any CPU
23
+		{BA63D177-BE9E-41E0-89F5-3D134A26A604}.Release|Any CPU.Build.0 = Release|Any CPU
18 24
 	EndGlobalSection
19 25
 	GlobalSection(SolutionProperties) = preSolution
20 26
 		HideSolutionNode = FALSE

+ 1
- 0
NuGet-server/NuGet-server.csproj View File

@@ -100,6 +100,7 @@
100 100
   </ItemGroup>
101 101
   <ItemGroup>
102 102
     <Content Include="packages.config" />
103
+    <None Include="Properties\PublishProfiles\nuget.pubxml" />
103 104
     <None Include="Web.Debug.config">
104 105
       <DependentUpon>Web.config</DependentUpon>
105 106
     </None>

Loading…
Cancel
Save