1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc {
\r
15 using System.Collections;
\r
16 using System.Collections.Generic;
\r
17 using System.Diagnostics.CodeAnalysis;
\r
20 using System.Reflection;
\r
22 internal static class TypeCacheUtil {
\r
24 private static IEnumerable<Type> FilterTypesInAssemblies(IBuildManager buildManager, Predicate<Type> predicate) {
\r
25 // Go through all assemblies referenced by the application and search for types matching a predicate
\r
26 IEnumerable<Type> typesSoFar = Type.EmptyTypes;
\r
28 ICollection assemblies = buildManager.GetReferencedAssemblies();
\r
29 foreach (Assembly assembly in assemblies) {
\r
32 typesInAsm = assembly.GetTypes();
\r
34 catch (ReflectionTypeLoadException ex) {
\r
35 typesInAsm = ex.Types;
\r
37 typesSoFar = typesSoFar.Concat(typesInAsm);
\r
39 return typesSoFar.Where(type => TypeIsPublicClass(type) && predicate(type));
\r
42 public static List<Type> GetFilteredTypesFromAssemblies(string cacheName, Predicate<Type> predicate, IBuildManager buildManager) {
\r
43 TypeCacheSerializer serializer = new TypeCacheSerializer();
\r
45 // first, try reading from the cache on disk
\r
46 List<Type> matchingTypes = ReadTypesFromCache(cacheName, predicate, buildManager, serializer);
\r
47 if (matchingTypes != null) {
\r
48 return matchingTypes;
\r
51 // if reading from the cache failed, enumerate over every assembly looking for a matching type
\r
52 matchingTypes = FilterTypesInAssemblies(buildManager, predicate).ToList();
\r
54 // finally, save the cache back to disk
\r
55 SaveTypesToCache(cacheName, matchingTypes, buildManager, serializer);
\r
57 return matchingTypes;
\r
60 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
\r
61 Justification = "Cache failures are not fatal, and the code should continue executing normally.")]
\r
62 internal static List<Type> ReadTypesFromCache(string cacheName, Predicate<Type> predicate, IBuildManager buildManager, TypeCacheSerializer serializer) {
\r
64 using (Stream stream = buildManager.ReadCachedFile(cacheName)) {
\r
65 if (stream != null) {
\r
66 using (StreamReader reader = new StreamReader(stream)) {
\r
67 List<Type> deserializedTypes = serializer.DeserializeTypes(reader);
\r
68 if (deserializedTypes != null && deserializedTypes.All(type => TypeIsPublicClass(type) && predicate(type))) {
\r
69 // If all read types still match the predicate, success!
\r
70 return deserializedTypes;
\r
82 [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
\r
83 Justification = "Cache failures are not fatal, and the code should continue executing normally.")]
\r
84 internal static void SaveTypesToCache(string cacheName, IList<Type> matchingTypes, IBuildManager buildManager, TypeCacheSerializer serializer) {
\r
86 using (Stream stream = buildManager.CreateCachedFile(cacheName)) {
\r
87 if (stream != null) {
\r
88 using (StreamWriter writer = new StreamWriter(stream)) {
\r
89 serializer.SerializeTypes(matchingTypes, writer);
\r
98 private static bool TypeIsPublicClass(Type type) {
\r
99 return (type != null && type.IsPublic && type.IsClass && !type.IsAbstract);
\r