forked from ServiceStack/ServiceStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHttpRuntimeCacheStorage.cs
More file actions
145 lines (125 loc) · 4.97 KB
/
HttpRuntimeCacheStorage.cs
File metadata and controls
145 lines (125 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#if !NETSTANDARD2_0
using System;
using System.Collections.Generic;
using System.Web;
namespace ServiceStack.MiniProfiler.Storage
{
/// <summary>
/// Understands how to store a <see cref="MiniProfiler"/> to the <see cref="System.Web.HttpRuntime.Cache"/> with absolute expiration.
/// </summary>
public class HttpRuntimeCacheStorage : IStorage
{
/// <summary>
/// The string that prefixes all keys that MiniProfilers are saved under, e.g.
/// "mini-profiler-ecfb0050-7ce8-4bf1-bf82-2cb38e90e31e".
/// </summary>
public const string CacheKeyPrefix = "mini-profiler-";
/// <summary>
/// How long to cache each <see cref="MiniProfiler"/> for (i.e. the absolute expiration parameter of
/// <see cref="System.Web.Caching.Cache.Insert(string, object, System.Web.Caching.CacheDependency, System.DateTime, System.TimeSpan, System.Web.Caching.CacheItemUpdateCallback)"/>)
/// </summary>
public TimeSpan CacheDuration { get; set; }
/// <summary>
/// Returns a new HttpRuntimeCacheStorage class that will cache MiniProfilers for the specified duration.
/// </summary>
public HttpRuntimeCacheStorage(TimeSpan cacheDuration)
{
CacheDuration = cacheDuration;
}
/// <summary>
/// Saves <paramref name="profiler"/> to the HttpRuntime.Cache under a key concated with <see cref="CacheKeyPrefix"/>
/// and the parameter's <see cref="MiniProfiler.Id"/>.
/// </summary>
public void Save(MiniProfiler profiler)
{
InsertIntoCache(GetCacheKey(profiler.Id), profiler);
// so we can easily follow POST -> redirects, store ids for this user
var ids = GetPerUserUnviewedIds(profiler);
lock (ids)
{
if (!ids.Contains(profiler.Id))
{
ids.Add(profiler.Id);
}
}
}
/// <summary>
/// Returns the saved <see cref="MiniProfiler"/> identified by <paramref name="id"/>. Also marks the resulting
/// profiler <see cref="MiniProfiler.HasUserViewed"/> to true.
/// </summary>
public MiniProfiler Load(Guid id)
{
var result = HttpRuntime.Cache[GetCacheKey(id)] as MiniProfiler;
if (result != null)
{
var ids = GetPerUserUnviewedIds(result);
lock (ids)
{
ids.Remove(result.Id);
result.HasUserViewed = true;
}
}
return result;
}
/// <summary>
/// Returns a list of <see cref="MiniProfiler.Id"/>s that haven't been seen by <paramref name="user"/>.
/// </summary>
/// <param name="user">User identified by the current <see cref="MiniProfiler.Settings.UserProvider"/>.</param>
public List<Guid> GetUnviewedIds(string user)
{
var ids = GetPerUserUnviewedIds(user);
lock (ids)
{
return new List<Guid>(ids);
}
}
private void InsertIntoCache(string key, object value)
{
// use insert instead of add; add fails if the item already exists
HttpRuntime.Cache.Insert(
key: key,
value: value,
dependencies: null,
absoluteExpiration: DateTime.Now.Add(CacheDuration), // servers will cache based on local now
slidingExpiration: System.Web.Caching.Cache.NoSlidingExpiration,
priority: System.Web.Caching.CacheItemPriority.Low,
onRemoveCallback: null);
}
private string GetCacheKey(Guid id)
{
return CacheKeyPrefix + id;
}
private string GetPerUserUnviewedCacheKey(string user)
{
return CacheKeyPrefix + "unviewed-for-user-" + user;
}
private List<Guid> GetPerUserUnviewedIds(MiniProfiler profiler)
{
return GetPerUserUnviewedIds(profiler.User);
}
private List<Guid> GetPerUserUnviewedIds(string user)
{
var key = GetPerUserUnviewedCacheKey(user);
var result = HttpRuntime.Cache[key] as List<Guid>;
if (result == null)
{
lock (AddPerUserUnviewedIdsLock)
{
// check again, as we could have been waiting
result = HttpRuntime.Cache[key] as List<Guid>;
if (result == null)
{
result = new List<Guid>();
InsertIntoCache(key, result);
}
}
}
return result;
}
/// <summary>
/// Syncs access to runtime cache when adding a new list of ids for a user.
/// </summary>
private static readonly object AddPerUserUnviewedIdsLock = new object();
}
}
#endif