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 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
|
//------------------------------------------------------------------------------
// <copyright file="cache.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
* Cache class
*
* Copyright (c) 1999 Microsoft Corporation
*/
namespace System.Web.Caching {
using System.Collections;
using System.Collections.Specialized;
using System.Configuration;
using System.Configuration.Provider;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Web.Util;
using System.Web;
using Microsoft.Win32;
using System.Security.Permissions;
using System.Globalization;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.Management;
using Debug = System.Web.Util.Debug;
/// <devdoc>
/// <para>Represents the method that will handle the <see langword='onRemoveCallback'/>
/// event of a System.Web.Caching.Cache instance.</para>
/// </devdoc>
public delegate void CacheItemRemovedCallback(
string key, object value, CacheItemRemovedReason reason);
/// <devdoc>
/// <para>Represents the method that will handle the <see langword='onUpdateCallback'/>
/// event of a System.Web.Caching.Cache instance.</para>
/// </devdoc>
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters",
Justification="Shipped this way in NetFx 2.0 SP2")]
public delegate void CacheItemUpdateCallback(
string key, CacheItemUpdateReason reason,
out object expensiveObject, out CacheDependency dependency, out DateTime absoluteExpiration, out TimeSpan slidingExpiration);
/// <devdoc>
/// <para> Specifies the relative priority of items stored in the System.Web.Caching.Cache. When the Web
/// server runs low on memory, the Cache selectively purges items to free system
/// memory. Items with higher priorities are less likely to be removed from the
/// cache when the server is under load. Web
/// applications can use these
/// values to prioritize cached items relative to one another. The default is
/// normal.</para>
/// </devdoc>
public enum CacheItemPriority {
/// <devdoc>
/// <para> The cahce items with this priority level will be the first
/// to be removed when the server frees system memory by deleting items from the
/// cache.</para>
/// </devdoc>
Low = 1,
/// <devdoc>
/// <para> The cache items with this priority level
/// are in the second group to be removed when the server frees system memory by
/// deleting items from the cache. </para>
/// </devdoc>
BelowNormal,
/// <devdoc>
/// <para> The cache items with this priority level are in
/// the third group to be removed when the server frees system memory by deleting items from the cache. This is the default. </para>
/// </devdoc>
Normal,
/// <devdoc>
/// <para> The cache items with this priority level are in the
/// fourth group to be removed when the server frees system memory by deleting items from the
/// cache. </para>
/// </devdoc>
AboveNormal,
/// <devdoc>
/// <para>The cache items with this priority level are in the fifth group to be removed
/// when the server frees system memory by deleting items from the cache. </para>
/// </devdoc>
High,
/// <devdoc>
/// <para>The cache items with this priority level will not be removed when the server
/// frees system memory by deleting items from the cache. </para>
/// </devdoc>
NotRemovable,
/// <devdoc>
/// <para>The default value is Normal.</para>
/// </devdoc>
Default = Normal
}
/// <devdoc>
/// <para>Specifies the reason that a cached item was removed.</para>
/// </devdoc>
public enum CacheItemRemovedReason {
/// <devdoc>
/// <para>The item was removed from the cache by the 'System.Web.Caching.Cache.Remove' method, or by an System.Web.Caching.Cache.Insert method call specifying the same key.</para>
/// </devdoc>
Removed = 1,
/// <devdoc>
/// <para>The item was removed from the cache because it expired. </para>
/// </devdoc>
Expired,
/// <devdoc>
/// <para>The item was removed from the cache because the value in the hitInterval
/// parameter was not met, or because the system removed it to free memory.</para>
/// </devdoc>
Underused,
/// <devdoc>
/// <para>The item was removed from the cache because a file or key dependency was
/// changed.</para>
/// </devdoc>
DependencyChanged
}
/// <devdoc>
/// <para>Specifies the reason why a cached item needs to be updated.</para>
/// </devdoc>
[SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue",
Justification = "This enum should mirror CacheItemRemovedReason enum in design")]
public enum CacheItemUpdateReason {
/// <devdoc>
/// <para>The item needs to be updated because it expired. </para>
/// </devdoc>
Expired = 1,
/// <devdoc>
/// <para>The item needs to be updated because a file or key dependency was
/// changed.</para>
/// </devdoc>
DependencyChanged
}
/// <devdoc>
/// <para>Implements the cache for a Web application. There is only one instance of
/// this class per application domain, and it remains valid only as long as the
/// application domain remains active. Information about an instance of this class
/// is available through the <see langword='Cache'/> property of the System.Web.HttpContext.</para>
/// </devdoc>
//
// Extra notes:
// - The Cache object contains a ICacheStore object and wraps it for public consumption.
//
public sealed class Cache : IEnumerable {
/// <devdoc>
/// <para>Sets the absolute expiration policy to, in essence,
/// never. When set, this field is equal to the the System.DateTime.MaxValue , which is a constant
/// representing the largest possible <see langword='DateTime'/> value. The maximum date and
/// time value is equivilant to "12/31/9999 11:59:59 PM". This field is read-only.</para>
/// </devdoc>
public static readonly DateTime NoAbsoluteExpiration = DateTime.MaxValue;
/// <devdoc>
/// <para>Sets the amount of time for sliding cache expirations to
/// zero. When set, this field is equal to the System.TimeSpan.Zero field, which is a constant value of
/// zero. This field is read-only.</para>
/// </devdoc>
public static readonly TimeSpan NoSlidingExpiration = TimeSpan.Zero;
static CacheStoreProvider _objectCache = null;
static CacheStoreProvider _internalCache = null;
static CacheItemRemovedCallback s_sentinelRemovedCallback = new CacheItemRemovedCallback(SentinelEntry.OnCacheItemRemovedCallback);
/// <internalonly/>
/// <devdoc>
/// <para>This constructor is for internal use only, and was accidentally made public - do not use.</para>
/// </devdoc>
[SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
public Cache() {
}
//
// internal ctor used by CacheCommon that avoids the demand for UnmanagedCode.
//
internal Cache(int dummy) {
}
/// <devdoc>
/// <para>Gets the number of items stored in the cache. This value can be useful when
/// monitoring your application's performance or when using the ASP.NET tracing
/// functionality.</para>
/// </devdoc>
public int Count {
get {
return Convert.ToInt32(ObjectCache.ItemCount);
}
}
internal CacheStoreProvider GetInternalCache(bool createIfDoesNotExist) {
if (_internalCache == null && createIfDoesNotExist) {
lock (this) {
if (_internalCache == null) {
NameValueCollection cacheProviderSettings = HostingEnvironment.CacheStoreProviderSettings;
if (cacheProviderSettings != null) {
string providerName = (string)cacheProviderSettings["name"]; // Grab this now, as InstantiateProvider will remove it from settings
cacheProviderSettings["isPublic"] = "false";
_internalCache = (CacheStoreProvider)ProvidersHelper.InstantiateProvider(cacheProviderSettings, typeof(CacheStoreProvider));
_internalCache.Initialize(providerName, cacheProviderSettings);
}
else {
if (_objectCache is AspNetCache) {
_internalCache = new AspNetCache((AspNetCache)_objectCache, isPublic: false);
}
else {
_internalCache = new AspNetCache(isPublic: false);
}
_internalCache.Initialize(null, new NameValueCollection());
}
}
}
}
return _internalCache;
}
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control this method's callers.")]
internal CacheStoreProvider GetObjectCache(bool createIfDoesNotExist) {
if (_objectCache == null && createIfDoesNotExist) {
lock (this) {
if (_objectCache == null) {
NameValueCollection cacheProviderSettings = HostingEnvironment.CacheStoreProviderSettings;
if (cacheProviderSettings != null) {
string providerName = (string)cacheProviderSettings["name"]; // Grab this now, as InstantiateProvider will remove it from settings
cacheProviderSettings["isPublic"] = "true";
_objectCache = (CacheStoreProvider)ProvidersHelper.InstantiateProvider(cacheProviderSettings, typeof(CacheStoreProvider));
_objectCache.Initialize(providerName, cacheProviderSettings);
}
else {
if (_internalCache is AspNetCache) {
_objectCache = new AspNetCache((AspNetCache)_internalCache, isPublic: true);
}
else {
_objectCache = new AspNetCache(isPublic: true);
}
_objectCache.Initialize(null, new NameValueCollection());
}
}
}
}
return _objectCache;
}
/// <devdoc>
/// <para>Provides access to the cache store used by ASP.Net internals.</para>
/// </devdoc>
internal CacheStoreProvider InternalCache {
get { return GetInternalCache(createIfDoesNotExist: true); }
}
/// <devdoc>
/// <para>Provides access to the cache store that backs HttpRuntime.Cache.</para>
/// </devdoc>
internal CacheStoreProvider ObjectCache {
get { return GetObjectCache(createIfDoesNotExist: true); }
}
/// <internalonly/>
IEnumerator IEnumerable.GetEnumerator() {
return ObjectCache.GetEnumerator();
}
/// <devdoc>
/// <para>Returns a dictionary enumerator used for iterating through the key/value
/// pairs contained in the cache. Items can be added to or removed from the cache
/// while this method is enumerating through the cache items.</para>
/// </devdoc>
public IDictionaryEnumerator GetEnumerator() {
return ObjectCache.GetEnumerator();
}
/// <devdoc>
/// <para>Gets or sets an item in the cache.</para>
/// </devdoc>
public object this[string key] {
get {
return Get(key);
}
set {
Insert(key, value);
}
}
private class SentinelEntry {
private string _key;
private CacheDependency _expensiveObjectDependency;
private CacheItemUpdateCallback _cacheItemUpdateCallback;
public SentinelEntry(string key, CacheDependency expensiveObjectDependency, CacheItemUpdateCallback callback) {
_key = key;
_expensiveObjectDependency = expensiveObjectDependency;
_cacheItemUpdateCallback = callback;
}
public string Key {
get { return _key; }
}
public CacheDependency ExpensiveObjectDependency {
get { return _expensiveObjectDependency; }
}
public CacheItemUpdateCallback CacheItemUpdateCallback {
get { return _cacheItemUpdateCallback; }
}
public static void OnCacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason) {
CacheItemUpdateReason updateReason;
SentinelEntry entry = value as SentinelEntry;
switch (reason) {
case CacheItemRemovedReason.Expired:
updateReason = CacheItemUpdateReason.Expired;
break;
case CacheItemRemovedReason.DependencyChanged:
updateReason = CacheItemUpdateReason.DependencyChanged;
if (entry.ExpensiveObjectDependency.HasChanged) {
// If the expensiveObject has been removed explicitly by Cache.Remove,
// return from the SentinelEntry removed callback
// thus effectively removing the SentinelEntry from the cache.
return;
}
break;
case CacheItemRemovedReason.Underused:
Debug.Fail("Reason should never be CacheItemRemovedReason.Underused since the entry was inserted as NotRemovable.");
return;
default:
// do nothing if reason is Removed
return;
}
CacheDependency cacheDependency;
DateTime absoluteExpiration;
TimeSpan slidingExpiration;
object expensiveObject;
CacheItemUpdateCallback callback = entry.CacheItemUpdateCallback;
// invoke update callback
try {
callback(entry.Key, updateReason, out expensiveObject, out cacheDependency, out absoluteExpiration, out slidingExpiration);
// Dev10 861163 - Only update the "expensive" object if the user returns a new object and the
// cache dependency hasn't changed. (Inserting with a cache dependency that has already changed will cause recursion.)
if (expensiveObject != null && (cacheDependency == null || !cacheDependency.HasChanged)) {
HttpRuntime.Cache.Insert(entry.Key, expensiveObject, cacheDependency, absoluteExpiration, slidingExpiration, entry.CacheItemUpdateCallback);
}
else {
HttpRuntime.Cache.Remove(entry.Key);
}
}
catch (Exception e) {
HttpRuntime.Cache.Remove(entry.Key);
try {
WebBaseEvent.RaiseRuntimeError(e, value);
}
catch {
}
}
}
}
/// <devdoc>
/// <para>Retrieves an item from the cache.</para>
/// </devdoc>
public object Get(string key) {
return ObjectCache.Get(key);
}
/// <devdoc>
/// <para>Inserts an item into the Cache with default values.</para>
/// </devdoc>
public void Insert(string key, object value) {
ObjectCache.Insert(key, value, options: null);
}
/// <devdoc>
/// <para>Inserts an object into the System.Web.Caching.Cache that has file or key
/// dependencies.</para>
/// </devdoc>
public void Insert(string key, object value, CacheDependency dependencies) {
ObjectCache.Insert(key, value, new CacheInsertOptions() { Dependencies = dependencies });
}
/// <devdoc>
/// <para>Inserts an object into the System.Web.Caching.Cache that has file or key dependencies and
/// expires at the value set in the <paramref name="absoluteExpiration"/> parameter.</para>
/// </devdoc>
public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration) {
DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
ObjectCache.Insert(key, value, new CacheInsertOptions() {
Dependencies = dependencies,
AbsoluteExpiration = utcAbsoluteExpiration,
SlidingExpiration = slidingExpiration
});
}
public void Insert(
string key,
object value,
CacheDependency dependencies,
DateTime absoluteExpiration,
TimeSpan slidingExpiration,
CacheItemPriority priority,
CacheItemRemovedCallback onRemoveCallback) {
DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
ObjectCache.Insert(key, value, new CacheInsertOptions() {
Dependencies = dependencies,
AbsoluteExpiration = utcAbsoluteExpiration,
SlidingExpiration = slidingExpiration,
Priority = priority,
OnRemovedCallback = onRemoveCallback
});
}
// DevDiv Bugs 162763:
// Add a an event that fires *before* an item is evicted from the ASP.NET Cache
public void Insert(
string key,
object value,
CacheDependency dependencies,
DateTime absoluteExpiration,
TimeSpan slidingExpiration,
CacheItemUpdateCallback onUpdateCallback) {
if (dependencies == null && absoluteExpiration == Cache.NoAbsoluteExpiration && slidingExpiration == Cache.NoSlidingExpiration) {
throw new ArgumentException(SR.GetString(SR.Invalid_Parameters_To_Insert));
}
if (onUpdateCallback == null) {
throw new ArgumentNullException("onUpdateCallback");
}
DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
// Insert updatable cache entry
ObjectCache.Insert(key, value, new CacheInsertOptions() { Priority = CacheItemPriority.NotRemovable });
// Ensure the sentinel depends on its updatable entry
string[] cacheKeys = { key };
CacheDependency expensiveObjectDep = new CacheDependency(null, cacheKeys);
if (dependencies == null) {
dependencies = expensiveObjectDep;
}
else {
AggregateCacheDependency deps = new AggregateCacheDependency();
deps.Add(dependencies, expensiveObjectDep);
dependencies = deps;
}
// Insert sentinel entry for the updatable cache entry
HttpRuntime.Cache.InternalCache.Insert(
CacheInternal.PrefixValidationSentinel + key,
new SentinelEntry(key, expensiveObjectDep, onUpdateCallback),
new CacheInsertOptions() {
Dependencies = dependencies,
AbsoluteExpiration = utcAbsoluteExpiration,
SlidingExpiration = slidingExpiration,
Priority = CacheItemPriority.NotRemovable,
OnRemovedCallback = Cache.s_sentinelRemovedCallback
});
}
public object Add(
string key,
object value,
CacheDependency dependencies,
DateTime absoluteExpiration,
TimeSpan slidingExpiration,
CacheItemPriority priority,
CacheItemRemovedCallback onRemoveCallback) {
DateTime utcAbsoluteExpiration = DateTimeUtil.ConvertToUniversalTime(absoluteExpiration);
return ObjectCache.Add(key, value, new CacheInsertOptions() {
Dependencies = dependencies,
AbsoluteExpiration = utcAbsoluteExpiration,
SlidingExpiration = slidingExpiration,
Priority = priority,
OnRemovedCallback = onRemoveCallback
});
}
/// <devdoc>
/// <para>Removes the specified item from the cache. </para>
/// </devdoc>
public object Remove(string key) {
return ObjectCache.Remove(key, CacheItemRemovedReason.Removed);
}
public long EffectivePrivateBytesLimit {
get {
return AspNetMemoryMonitor.ProcessPrivateBytesLimit;
}
}
public long EffectivePercentagePhysicalMemoryLimit {
get {
return AspNetMemoryMonitor.PhysicalMemoryPercentageLimit;
}
}
}
}
|