public BaseTest()
        {
            HttpContext.Current = new HttpContext(
                new HttpRequest(string.Empty, "http://tempuri.org", string.Empty),
                new HttpResponse(new StringWriter())
                );

            ProcessStorage <string, CacheItem> .Clear();
        }
        protected void SetupValidator(ModelMetadata metadata)
        {
            var fieldId = $"{metadata.ContainerType.FullName}.{metadata.PropertyName}".ToLowerInvariant();

            AttributeFullId = $"{Attribute.TypeId}.{fieldId}".ToLowerInvariant();
            AttributeWeakId = $"{typeof(T).FullName}.{fieldId}".ToLowerInvariant();

            var item = ProcessStorage <string, CacheItem> .GetOrAdd(AttributeFullId, _ => // map cache is based on static dictionary, set-up once for entire application instance
            {                                                                             // (by design, no reason to recompile once compiled expressions)
                IDictionary <string, Expression> fields = null;
                Attribute.Compile(metadata.ContainerType, parser =>
                {
                    fields      = parser.GetFields();
                    FieldsMap   = fields.ToDictionary(x => x.Key, x => Helper.GetCoarseType(x.Value.Type));
                    ConstsMap   = parser.GetConsts();
                    EnumsMap    = parser.GetEnums();
                    MethodsList = parser.GetMethods();
                }); // compile the expression associated with attribute (to be cached for subsequent invocations)

                AssertClientSideCompatibility();

                ParsersMap = fields
                             .Select(kvp => new
                {
                    FullName        = kvp.Key,
                    ParserAttribute = (kvp.Value as MemberExpression)?.Member.GetAttributes <ValueParserAttribute>().SingleOrDefault()
                }).Where(x => x.ParserAttribute != null)
                             .ToDictionary(x => x.FullName, x => x.ParserAttribute.ParserName);

                if (!ParsersMap.ContainsKey(metadata.PropertyName))
                {
                    var currentField = metadata.ContainerType
                                       .GetProperties().Single(p => metadata.PropertyName == p.Name);
                    var valueParser = currentField.GetAttributes <ValueParserAttribute>().SingleOrDefault();
                    if (valueParser != null)
                    {
                        ParsersMap.Add(new KeyValuePair <string, string>(metadata.PropertyName, valueParser.ParserName));
                    }
                }

                return(new CacheItem
                {
                    FieldsMap = FieldsMap,
                    ConstsMap = ConstsMap,
                    EnumsMap = EnumsMap,
                    MethodsList = MethodsList,
                    ParsersMap = ParsersMap
                });
            });

            FieldsMap   = item.FieldsMap;
            ConstsMap   = item.ConstsMap;
            EnumsMap    = item.EnumsMap;
            MethodsList = item.MethodsList;
            ParsersMap  = item.ParsersMap;
        }
        private Thread[] MakeThreads(string[] keys)
        {
            var threads = keys.Select(key =>
                                      new Thread(load =>
            {
                var storage = (ConcurrentStack <TestItem>)((object[])load)[0];
                var counter = (ConcurrentStack <int>)((object[])load)[1];

                var item = ProcessStorage <string, TestItem> .GetOrAdd(key.ToString(), _ =>
                {
                    Debug.WriteLine($"{key} :: {Thread.CurrentThread.ManagedThreadId}");
                    counter.Push(Thread.CurrentThread.ManagedThreadId);     // we want to test that this value factory delegate is invoked only once, even if map is accessed concurrently for the same key
                    Thread.Sleep(500);
                    return(new TestItem {
                        Id = key
                    });
                });
                storage.Push(item);
            })).ToArray();

            return(threads);
        }
        /// <summary>
        ///     Constructor for expressive model validator.
        /// </summary>
        /// <param name="metadata">The model metadata instance.</param>
        /// <param name="context">The controller context instance.</param>
        /// <param name="attribute">The expressive attribute instance.</param>
        /// <exception cref="System.ComponentModel.DataAnnotations.ValidationException"></exception>
        protected ExpressiveValidator(ModelMetadata metadata, ControllerContext context, T attribute)
            : base(metadata, context, attribute)
        {
            try
            {
                Debug.WriteLine($"[ctor entry] process: {Process.GetCurrentProcess().Id}, thread: {Thread.CurrentThread.ManagedThreadId}");

                var fieldId = $"{metadata.ContainerType.FullName}.{metadata.PropertyName}".ToLowerInvariant();
                AttributeFullId = $"{attribute.TypeId}.{fieldId}".ToLowerInvariant();
                AttributeWeakId = $"{typeof(T).FullName}.{fieldId}".ToLowerInvariant();
                FieldName       = metadata.PropertyName;

                ResetSuffixAllocation();

                var item = ProcessStorage <string, CacheItem> .GetOrAdd(AttributeFullId, _ => // map cache is based on static dictionary, set-up once for entire application instance
                {                                                                             // (by design, no reason to recompile once compiled expressions)
                    Debug.WriteLine($"[cache add] process: {Process.GetCurrentProcess().Id}, thread: {Thread.CurrentThread.ManagedThreadId}");

                    IDictionary <string, Expression> fields = null;
                    attribute.Compile(metadata.ContainerType, parser =>
                    {
                        fields      = parser.GetFields();
                        FieldsMap   = fields.ToDictionary(x => x.Key, x => Helper.GetCoarseType(x.Value.Type));
                        ConstsMap   = parser.GetConsts();
                        EnumsMap    = parser.GetEnums();
                        MethodsList = parser.GetMethods();
                    }); // compile the expression associated with attribute (to be cached for subsequent invocations)

                    AssertClientSideCompatibility();

                    ParsersMap = fields
                                 .Select(kvp => new
                    {
                        FullName        = kvp.Key,
                        ParserAttribute = (kvp.Value as MemberExpression)?.Member.GetAttributes <ValueParserAttribute>().SingleOrDefault()
                    }).Where(x => x.ParserAttribute != null)
                                 .ToDictionary(x => x.FullName, x => x.ParserAttribute.ParserName);

                    if (!ParsersMap.ContainsKey(metadata.PropertyName))
                    {
                        var currentField = metadata.ContainerType
                                           .GetProperties().Single(p => metadata.PropertyName == p.Name);
                        var valueParser = currentField.GetAttributes <ValueParserAttribute>().SingleOrDefault();
                        if (valueParser != null)
                        {
                            ParsersMap.Add(new KeyValuePair <string, string>(metadata.PropertyName, valueParser.ParserName));
                        }
                    }

                    return(new CacheItem
                    {
                        FieldsMap = FieldsMap,
                        ConstsMap = ConstsMap,
                        EnumsMap = EnumsMap,
                        MethodsList = MethodsList,
                        ParsersMap = ParsersMap
                    });
                });

                FieldsMap   = item.FieldsMap;
                ConstsMap   = item.ConstsMap;
                EnumsMap    = item.EnumsMap;
                MethodsList = item.MethodsList;
                ParsersMap  = item.ParsersMap;

                Expression = attribute.Expression;

                IDictionary <string, Guid> errFieldsMap;
                FormattedErrorMessage = attribute.FormatErrorMessage(metadata.GetDisplayName(), attribute.Expression, metadata.ContainerType, out errFieldsMap); // fields names, in contrast to values, do not change in runtime, so will be provided in message (less code in js)
                ErrFieldsMap          = errFieldsMap;
            }
            catch (Exception e)
            {
                throw new ValidationException(
                          $"{GetType().Name}: validation applied to {metadata.PropertyName} field failed.", e);
            }
        }
 public ProcessStorageTest()
 {
     ProcessStorage <string, TestItem> .Clear();
 }