Welcome to mirror list, hosted at ThFree Co, Russian Federation.

CachedAssociatedMetadataProvider`1.cs « System.Web.Mvc « src - github.com/mono/aspnetwebstack.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 8000b52b8e50f4281524a8f155620ac37de0bbd6 (plain)
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
// 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"));
        }
    }
}