forked from ServiceStack/ServiceStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRequestContext.cs
More file actions
169 lines (144 loc) · 5.48 KB
/
Copy pathRequestContext.cs
File metadata and controls
169 lines (144 loc) · 5.48 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using ServiceStack.Logging;
namespace ServiceStack
{
public class RequestContext
{
public static readonly RequestContext Instance = new RequestContext();
/// <summary>
/// Tell ServiceStack to use ThreadStatic Items Collection for RequestScoped items.
/// Warning: ThreadStatic Items aren't pinned to the same request in async services which callback on different threads.
/// </summary>
public static bool UseThreadStatic;
[ThreadStatic]
public static IDictionary RequestItems;
/// <summary>
/// Gets a list of items for this request.
/// </summary>
/// <remarks>This list will be cleared on every request and is specific to the original thread that is handling the request.
/// If a handler uses additional threads, this data will not be available on those threads.
/// </remarks>
public virtual IDictionary Items
{
get
{
return GetItems() ?? CreateItems();
}
set
{
CreateItems(value);
}
}
private const string _key = "__Request.Items";
private IDictionary GetItems()
{
try
{
if (UseThreadStatic)
return RequestItems;
//Don't init CallContext on Main Thread which inits copies in Request threads
if (!ServiceStackHost.IsReady())
return new Dictionary<object, object>();
if (System.Web.HttpContext.Current != null)
return System.Web.HttpContext.Current.Items;
return CallContext.LogicalGetData(_key) as IDictionary;
}
catch (NotImplementedException)
{
//Fixed in Mono master: https://github.com/mono/mono/pull/817
return CallContext.GetData(_key) as IDictionary;
}
}
private IDictionary CreateItems(IDictionary items = null)
{
try
{
if (UseThreadStatic)
{
RequestItems = items ?? (items = new Dictionary<object, object>());
}
else
{
CallContext.LogicalSetData(_key, items ?? (items = new ConcurrentDictionary<object, object>()));
}
}
catch (NotImplementedException)
{
//Fixed in Mono master: https://github.com/mono/mono/pull/817
CallContext.SetData(_key, items ?? (items = new ConcurrentDictionary<object, object>()));
}
return items;
}
public T GetOrCreate<T>(Func<T> createFn)
{
if (Items.Contains(typeof(T).Name))
return (T)Items[typeof(T).Name];
return (T)(Items[typeof(T).Name] = createFn());
}
public void EndRequest()
{
if (UseThreadStatic)
Items = null;
else
CallContext.FreeNamedDataSlot(_key);
}
/// <summary>
/// Track any IDisposable's to dispose of at the end of the request in IAppHost.OnEndRequest()
/// </summary>
/// <param name="instance"></param>
public void TrackDisposable(IDisposable instance)
{
if (!ServiceStackHost.IsReady()) return;
if (instance == null) return;
if (instance is IService) return; //IService's are already disposed right after they've been executed
DispsableTracker dispsableTracker = null;
if (!Items.Contains(DispsableTracker.HashId))
Items[DispsableTracker.HashId] = dispsableTracker = new DispsableTracker();
if (dispsableTracker == null)
dispsableTracker = (DispsableTracker)Items[DispsableTracker.HashId];
dispsableTracker.Add(instance);
}
/// <summary>
/// Release currently registered dependencies for this request
/// </summary>
/// <returns>true if any dependencies were released</returns>
public bool ReleaseDisposables()
{
if (!ServiceStackHost.IsReady()) return false;
if (!ServiceStackHost.Instance.Config.DisposeDependenciesAfterUse) return false;
var ctxItems = Instance.Items;
var disposables = ctxItems[DispsableTracker.HashId] as DispsableTracker;
if (disposables != null)
{
disposables.Dispose();
ctxItems.Remove(DispsableTracker.HashId);
return true;
}
return false;
}
}
[Serializable]
public class DispsableTracker : IDisposable
{
public static ILog Log = LogManager.GetLogger(typeof(RequestContext));
public const string HashId = "__disposables";
List<WeakReference> disposables = new List<WeakReference>();
public void Add(IDisposable instance)
{
disposables.Add(new WeakReference(instance));
}
public void Dispose()
{
foreach (var wr in disposables)
{
var disposable = (IDisposable)wr.Target;
if (!wr.IsAlive) continue;
HostContext.Release(disposable);
}
}
}
}