我快速浏览了 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;
}
如您所见,它使用 aBuildManager
来读取缓存文件。
这是我能找到的唯一可以读取或创建缓存文件的地方。在调用层次结构中导航时,我最终会从DefaultControllerFactory
类或AreaRegistration
类中使用该方法。
所以我猜想这些类中的任何一个第一次需要应用程序中的控制器列表时,最终都会调用该类的GetFilteredTypesFromAssemblies
方法。TypeCacheUtil
它仅在无法读取文件时生成缓存文件。由于这个类使用 aBuildManager
来读取它,我相信它只会在文件损坏、丢失或重新启动应用程序时生成它。
浏览网页后,人们似乎报告说,为了重新生成 MVC-ControllerTypeCache.xml 文件,例如更改和保存 Global.asax 或 Web.Config 文件以触发重新启动就可以了。
你能在你自己的代码中利用这个文件吗?你可能可以,但你可能不应该。我只会使用反射。如果您因为这种方法而遇到性能问题,那么您可以开始考虑缓存,在这种情况下,我敢打赌,构建您自己的序列化控制器列表并使用 .NET 的内置缓存机制进行缓存会“更安全”他们而不是尝试重用 MVC-ControllerTypeCache.xml。我猜它是内部的。