You've already forked linux-packaging-mono
97 lines
4.2 KiB
C#
97 lines
4.2 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Runtime.Caching;
|
|
|
|
namespace System.Web.Mvc
|
|
{
|
|
public abstract class CachedAssociatedMetadataProvider<TModelMetadata> : AssociatedMetadataProvider
|
|
where TModelMetadata : ModelMetadata
|
|
{
|
|
private static ConcurrentDictionary<Type, string> _typeIds = new ConcurrentDictionary<Type, string>();
|
|
private string _cacheKeyPrefix;
|
|
private CacheItemPolicy _cacheItemPolicy = new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(20) };
|
|
private ObjectCache _prototypeCache;
|
|
|
|
protected internal CacheItemPolicy CacheItemPolicy
|
|
{
|
|
get { return _cacheItemPolicy; }
|
|
set { _cacheItemPolicy = value; }
|
|
}
|
|
|
|
protected string CacheKeyPrefix
|
|
{
|
|
get
|
|
{
|
|
if (_cacheKeyPrefix == null)
|
|
{
|
|
_cacheKeyPrefix = "MetadataPrototypes::" + GetType().GUID.ToString("B");
|
|
}
|
|
return _cacheKeyPrefix;
|
|
}
|
|
}
|
|
|
|
protected internal ObjectCache PrototypeCache
|
|
{
|
|
get { return _prototypeCache ?? MemoryCache.Default; }
|
|
set { _prototypeCache = value; }
|
|
}
|
|
|
|
protected sealed override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
|
|
{
|
|
// If metadata is being created for a property then containerType != null && propertyName != null
|
|
// If metadata is being created for a type then containerType == null && propertyName == null, so we have to use modelType for the cache key.
|
|
Type typeForCache = containerType ?? modelType;
|
|
string cacheKey = GetCacheKey(typeForCache, propertyName);
|
|
TModelMetadata prototype = PrototypeCache.Get(cacheKey) as TModelMetadata;
|
|
if (prototype == null)
|
|
{
|
|
prototype = CreateMetadataPrototype(attributes, containerType, modelType, propertyName);
|
|
PrototypeCache.Add(cacheKey, prototype, CacheItemPolicy);
|
|
}
|
|
|
|
return CreateMetadataFromPrototype(prototype, modelAccessor);
|
|
}
|
|
|
|
// New override for creating the prototype metadata (without the accessor)
|
|
protected abstract TModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes, Type containerType, Type modelType, string propertyName);
|
|
|
|
// New override for applying the prototype + modelAccess to yield the final metadata
|
|
protected abstract TModelMetadata CreateMetadataFromPrototype(TModelMetadata prototype, Func<object> modelAccessor);
|
|
|
|
internal string GetCacheKey(Type type, string propertyName = null)
|
|
{
|
|
propertyName = propertyName ?? String.Empty;
|
|
return CacheKeyPrefix + GetTypeId(type) + propertyName;
|
|
}
|
|
|
|
public sealed override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
|
|
{
|
|
return base.GetMetadataForProperty(modelAccessor, containerType, propertyName);
|
|
}
|
|
|
|
protected sealed override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, PropertyDescriptor propertyDescriptor)
|
|
{
|
|
return base.GetMetadataForProperty(modelAccessor, containerType, propertyDescriptor);
|
|
}
|
|
|
|
public sealed override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType)
|
|
{
|
|
return base.GetMetadataForProperties(container, containerType);
|
|
}
|
|
|
|
public sealed override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType)
|
|
{
|
|
return base.GetMetadataForType(modelAccessor, modelType);
|
|
}
|
|
|
|
private static string GetTypeId(Type type)
|
|
{
|
|
// It's fine using a random Guid since we store the mapping for types to guids.
|
|
return _typeIds.GetOrAdd(type, _ => Guid.NewGuid().ToString("B"));
|
|
}
|
|
}
|
|
}
|