internal static List <Type> ReadTypesFromCache(
            string cacheName,
            Predicate <Type> predicate,
            IBuildManager buildManager,
            TypeCacheSerializer serializer
            )
        {
            try
            {
                Stream stream = buildManager.ReadCachedFile(cacheName);
                if (stream != null)
                {
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        List <Type> deserializedTypes = serializer.DeserializeTypes(reader);
                        if (
                            deserializedTypes != null &&
                            deserializedTypes.All(
                                type => TypeIsPublicClass(type) && predicate(type)
                                )
                            )
                        {
                            // If all read types still match the predicate, success!
                            return(deserializedTypes);
                        }
                    }
                }
            }
            catch { }

            return(null);
        }
        public void DeserializeTypes_ReturnsNullIfTypeNotFound() {
            string expectedFormat = @"<?xml version=""1.0"" encoding=""utf-16""?>
<!--This file is automatically generated. Please do not modify the contents of this file.-->
<typeCache lastModified=""__IGNORED__"" mvcVersionId=""{0}"">
  <assembly name=""{1}"">
    <module versionId=""{2}"">
      <type>System.String</type>
      <type>This.Type.Does.Not.Exist</type>
    </module>
  </assembly>
</typeCache>";

            // Arrange
            string expected = String.Format(expectedFormat,
                GetMvidForType(typeof(TypeCacheSerializer)) /* mvcVersionId */,
                _mscorlibAsmFullName /* assembly.name */,
                GetMvidForType(typeof(object)) /* module.versionId */
                );

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            StringReader input = new StringReader(expected);

            // Act
            List<Type> deserializedTypes = serializer.DeserializeTypes(input);

            // Assert
            Assert.IsNull(deserializedTypes);
        }
        public static List <Type> GetFilteredTypesFromAssemblies(
            string cacheName,
            Predicate <Type> predicate,
            IBuildManager buildManager
            )
        {
            TypeCacheSerializer serializer = new TypeCacheSerializer();

            // first, try reading from the cache on disk
            List <Type> matchingTypes = ReadTypesFromCache(
                cacheName,
                predicate,
                buildManager,
                serializer
                );

            if (matchingTypes != null)
            {
                return(matchingTypes);
            }

            // if reading from the cache failed, enumerate over every assembly looking for a matching type
            matchingTypes = FilterTypesInAssemblies(buildManager, predicate).ToList();

            // finally, save the cache back to disk
            SaveTypesToCache(cacheName, matchingTypes, buildManager, serializer);

            return(matchingTypes);
        }
        /// <summary>
        /// 获取当前项目中满足指定条件的类型集合
        /// 首先从缓存文件中查询,若无缓存则遍历所有引用的程序集,并最后保存到缓存文件中
        /// </summary>
        /// <param name="cacheName">缓存文件名</param>
        /// <param name="predicate">类型匹配的规则(一个委托)</param>
        /// <param name="buildManager">操作类型缓存的组件</param>
        /// <returns>匹配的类型集合</returns>
        public static List<Type> GetFilteredTypesFromAssemblies(string cacheName, Predicate<Type> predicate, IBuildManager buildManager)
        {
            //类型缓存序列化器
            TypeCacheSerializer serializer = new TypeCacheSerializer();

            //首先从本地磁盘读取缓存路由的缓存文件,获取缓存的区域路由的类型集合
            // first, try reading from the cache on disk
            List<Type> matchingTypes = ReadTypesFromCache(cacheName, predicate, buildManager, serializer);
            if (matchingTypes != null)
            {
                return matchingTypes;
            }

            //如果没有读取到路由的缓存信息,则枚举每一个程序集寻找匹配的类型
            //即寻找继承了AreaRegistration的类,并且包含无参构造函数
            // if reading from the cache failed, enumerate over every assembly looking for a matching type
            matchingTypes = FilterTypesInAssemblies(buildManager, predicate).ToList();


            // 将类型信息保存到XML文件中作为缓存
            // C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\985b57d0\89016edd\UserCache\MVC-AreaRegistrationTypeCache.xml
            // finally, save the cache back to disk
            SaveTypesToCache(cacheName, matchingTypes, buildManager, serializer);

            return matchingTypes;
        }
 internal static void SaveTypesToCache(string cacheName, IList<Type> matchingTypes, IBuildManager buildManager, TypeCacheSerializer serializer) {
     try {
         Stream stream = buildManager.CreateCachedFile(cacheName);
         if (stream != null) {
             using (StreamWriter writer = new StreamWriter(stream)) {
                 serializer.SerializeTypes(matchingTypes, writer);
             }
         }
     }
     catch {
     }
 }
        public void DeserializeTypes_ReturnsNullIfMvcVersionIdDoesNotMatch() {
            // Arrange
            string expected = String.Format(_expectedDeserializationFormat,
                Guid.Empty /* mvcVersionId */,
                _mscorlibAsmFullName /* assembly.name */,
                GetMvidForType(typeof(object)) /* module.versionId */
                );

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            StringReader input = new StringReader(expected);

            // Act
            List<Type> deserializedTypes = serializer.DeserializeTypes(input);

            // Assert
            Assert.IsNull(deserializedTypes);
        }
        public static List<Type> GetFilteredTypesFromAssemblies(string cacheName, Predicate<Type> predicate, IBuildManager buildManager) {
            TypeCacheSerializer serializer = new TypeCacheSerializer();

            // first, try reading from the cache on disk
            List<Type> matchingTypes = ReadTypesFromCache(cacheName, predicate, buildManager, serializer);
            if (matchingTypes != null) {
                return matchingTypes;
            }

            // if reading from the cache failed, enumerate over every assembly looking for a matching type
            matchingTypes = FilterTypesInAssemblies(buildManager, predicate).ToList();

            // finally, save the cache back to disk
            SaveTypesToCache(cacheName, matchingTypes, buildManager, serializer);

            return matchingTypes;
        }
        internal static List<Type> ReadTypesFromCache(string cacheName, Predicate<Type> predicate, IBuildManager buildManager, TypeCacheSerializer serializer) {
            try {
                Stream stream = buildManager.ReadCachedFile(cacheName);
                if (stream != null) {
                    using (StreamReader reader = new StreamReader(stream)) {
                        List<Type> deserializedTypes = serializer.DeserializeTypes(reader);
                        if (deserializedTypes != null && deserializedTypes.All(type => TypeIsPublicClass(type) && predicate(type))) {
                            // If all read types still match the predicate, success!
                            return deserializedTypes;
                        }
                    }
                }
            }
            catch {
            }

            return null;
        }
 internal static void SaveTypesToCache(
     string cacheName,
     IList <Type> matchingTypes,
     IBuildManager buildManager,
     TypeCacheSerializer serializer
     )
 {
     try
     {
         Stream stream = buildManager.CreateCachedFile(cacheName);
         if (stream != null)
         {
             using (StreamWriter writer = new StreamWriter(stream))
             {
                 serializer.SerializeTypes(matchingTypes, writer);
             }
         }
     }
     catch { }
 }
        public void SaveToCache_ReadFromCache_ReturnsNullIfTypesAreInvalid() {
            //
            // SAVING
            //

            // Arrange
            Type[] expectedTypes = new Type[] {
                typeof(object),
                typeof(string)
            };

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            string cacheName = "testCache";
            MockBuildManager buildManager = new MockBuildManager();

            // Act
            TypeCacheUtil.SaveTypesToCache(cacheName, expectedTypes, buildManager, serializer);

            // Assert
            MemoryStream writeStream = buildManager.CachedFileStore[cacheName] as MemoryStream;
            Assert.IsNotNull(writeStream, "Stream should've been created.");

            byte[] streamContents = writeStream.ToArray();
            Assert.AreNotEqual(0, streamContents.Length, "Data should've been written to the stream.");

            //
            // READING
            //

            // Arrange
            MemoryStream readStream = new MemoryStream(streamContents);
            buildManager.CachedFileStore[cacheName] = readStream;

            // Act
            List<Type> returnedTypes = TypeCacheUtil.ReadTypesFromCache(cacheName, _ => false /* all types are invalid */, buildManager, serializer);

            // Assert
            Assert.IsNull(returnedTypes);
        }
        public void DeserializeTypes_Success() {
            // Arrange
            string expected = String.Format(_expectedDeserializationFormat,
                GetMvidForType(typeof(TypeCacheSerializer)) /* mvcVersionId */,
                _mscorlibAsmFullName /* assembly.name */,
                GetMvidForType(typeof(object)) /* module.versionId */
                );

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            StringReader input = new StringReader(expected);

            Type[] expectedTypes = new Type[]{
                typeof(string),
                typeof(object)
            };

            // Act
            List<Type> deserializedTypes = serializer.DeserializeTypes(input);

            // Assert
            CollectionAssert.AreEquivalent(expectedTypes, deserializedTypes);
        }
        public void SerializeTypes() {
            // Arrange
            DateTime expectedDate = new DateTime(2001, 1, 1, 0, 0, 0, DateTimeKind.Utc); // Jan 1, 2001 midnight UTC
            string expectedFormat = @"<?xml version=""1.0"" encoding=""utf-16""?>
<!--This file is automatically generated. Please do not modify the contents of this file.-->
<typeCache lastModified=""{0}"" mvcVersionId=""{1}"">
  <assembly name=""{2}"">
    <module versionId=""{3}"">
      <type>System.String</type>
      <type>System.Object</type>
    </module>
  </assembly>
</typeCache>";
            string expected = String.Format(expectedFormat,
                expectedDate /* lastModified */,
                GetMvidForType(typeof(TypeCacheSerializer)) /* mvcVersionId */,
                _mscorlibAsmFullName /* assembly.name */,
                GetMvidForType(typeof(object)) /* module.versionId */
                );

            Type[] typesToSerialize = new Type[]{
                typeof(string),
                typeof(object)
            };

            TypeCacheSerializer serializer = new TypeCacheSerializer();
            serializer.CurrentDateOverride = expectedDate;

            StringWriter output = new StringWriter();

            // Act
            serializer.SerializeTypes(typesToSerialize, output);
            string outputString = output.ToString();

            // Assert
            Assert.AreEqual(expected, outputString);
        }