How and when is MVC-ControllerTypeCache.xml populated

I have a few questions related to this file (MVC-ControllerTypeCache.xml).

1) Can someone tell me when and how this file is generated?

I know that it is generated by the framework to reduce the number of fixes needed to call the controllers.

I also know that for working with it there are several inner classes in the MVC source, the factory controller GetControllerTypeuses them.

2) Is there a way to work with it in the application?

For example, if I want to list all the controllers in an application, using this file will mean that I should not find them myself through reflection.

It would also be useful to know how / when it will be updated, since the method GetControllerType(requestContext, controllerName);will return the type of your controller based on what it finds in this file.

Knowing when it is being updated, and if you can rely on it, this can change the way registers are registered from the modules / modules that are in their own assemblies.

Basically I ask purely out of interest.

+5
source share
2 answers

1) Can someone tell me when and how this file is generated?

DefaultControllerFactory.GetControllerType, called upon each request, calls a method GetControllerTypeWithinNamespacesto obtain a list of available controller types:

private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces) {
    ControllerTypeCache.EnsureInitialized(BuildManager);
    ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);

    ... more code removed for brevity
}

As you can see, in the beginning it does 2 things: initialize and extract controller types from ControllerTypeCache.

EnsureInitialized , , :

public void EnsureInitialized(IBuildManager buildManager) {
    if (_cache == null) {
        lock (_lockObj) {
            if (_cache == null) {
                List<Type> controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(_typeCacheName, IsControllerType, buildManager);
                var groupedByName = controllerTypes.GroupBy(
                    t => t.Name.Substring(0, t.Name.Length - "Controller".Length),
                    StringComparer.OrdinalIgnoreCase);
                _cache = groupedByName.ToDictionary(
                    g => g.Key,
                    g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
                    StringComparer.OrdinalIgnoreCase);
            }
        }
    }
}

, _cache , null. , IIS.

TypeCacheUtil.GetFilteredTypesFromAssemblies. :

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;
}

:

  • TypeCacheSerializer . XmlDocument, .
  • , FilterTypesInAssemblies, .
  • , .

, : http://www.beletsky.net/2011/12/inside-aspnet-mvc-instantiation-of.html

2) ?

XML , , .

, , . , API .

, , :

public static class ControllerTypeCache
{
    private static object _syncRoot = new object();
    private static Type[] _cache;

    public static IEnumerable<Type> GetControllerTypes()
    {
        if (_cache == null)
        {
            lock (_syncRoot)
            {
                if (_cache == null)
                {
                    _cache = GetControllerTypesWithReflection();
                }
            }
        }
        return new ReadOnlyCollection<Type>(_cache);
    }

    private static Type[] GetControllerTypesWithReflection()
    {
        var typesSoFar = Type.EmptyTypes;
        var assemblies = BuildManager.GetReferencedAssemblies();
        foreach (Assembly assembly in assemblies) 
        {
            Type[] typesInAsm;
            try 
            {
                typesInAsm = assembly.GetTypes();
            }
            catch (ReflectionTypeLoadException ex) 
            {
                typesInAsm = ex.Types;
            }
            typesSoFar = typesSoFar.Concat(typesInAsm).ToArray();
        }

        return typesSoFar
            .Where(t => t != null && 
                        t.IsPublic && 
                        !t.IsAbstract && 
                        typeof(IController).IsAssignableFrom(t)
            )
            .ToArray();
    }
}

, / , GetControllerType (requestContext, _); , .

. , , .

+6

ASP.NET MVC, , , , - . .

ASP.NET MVC ControllerTypeCache , . "MVC-ControllerTypeCache.xml" .

internal sealed class ControllerTypeCache
{
    private const string TypeCacheName = "MVC-ControllerTypeCache.xml";
    ...
}

ControllerTypeCache:

public void EnsureInitialized(IBuildManager buildManager)
{
    if (_cache == null)
    {
        lock (_lockObj)
        {
            if (_cache == null)
            {
                List<Type> controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(TypeCacheName, IsControllerType, buildManager);
                var groupedByName = controllerTypes.GroupBy(
                    t => t.Name.Substring(0, t.Name.Length - "Controller".Length),
                    StringComparer.OrdinalIgnoreCase);
                _cache = groupedByName.ToDictionary(
                    g => g.Key,
                    g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase),
                    StringComparer.OrdinalIgnoreCase);
            }
        }
    }
}

, TypeCacheUtil.GetFilteresTypesFromAssemblies. :

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;
}

, . (, ), .

ReadTypesFromCache :

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;
}

, BuildManager.

, , . DefaultControllerFactory AreaRegistration.

, , , , GetFilteredTypesFromAssemblies TypeCacheUtil . , . BuildManager , , , , .

- , , , MVC-ControllerTypeCache.xml - Global.asax Web.Config .

? , , , , , . . - , , "" .NET , MVC-ControllerTypeCache.xml. , - .

+2

All Articles