C#学习教程:如何以及何时填充MVC-ControllerTypeCache.xml1)谁能告诉我这个文件是何时以及如何生成的?我知道它是由框架生成的,以减少调用控制器时所需的反射量。我也知道在MVC源代码中有一些内部类来处理这个,控制器工厂GetControllerType使用它们。2)有没有办法在应用程序中使用它?例如,如果我想列出应用程序中的所有控制器,使用这个文件意味着我不必通过反射自己找到它们。还应该知道如何/何时更新方法GetControllerType(requestContext,controllerName);将根据在此文件中找到的内容返回您的控制器类型。了解它何时更新以及您是否可以依赖它可能会改变您从驻留在它们自己的程序集中的插件/模块注册控制器的方式。我主要是纯粹出于兴趣而问。1)谁能告诉我这个文件是何时以及如何生成的?在每个请求上调用的DefaultControllerFactory.GetControllerType调用GetControllerTypeWithinNamespaces方法来检索可用控制器类型的列表:ICollectionmatchingTypes=ControllerTypesCache。控制器名称、命名空间);...为简洁起见删除了更多代码}如您所见,它在开始时做了两件事:从ControllerTypeCache初始化和检索控制器类型。EnsureInitialized方法使用带有双重检查锁定的单例来确保在应用程序的整个生命周期中只执行一次初始化:==null){列表controllerTypes=TypeCacheUtil.GetFilteredTypesFromAssemblies(_typeCacheName,IsControllerType,buildManager);vargroupedByName=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??}注意_cache字段如果为空,将如何只初始化一次。这将发生在第一次在IIS启动应用程序后向您的站点请求。使用TypeCacheUtil.GetFilteredTypesFromAssemblies方法检索控制器类型。那么让我们来看看它:publicstaticListGetFilteredTypesFromAssemblies(stringcacheName,Predicatepredicate,IBuildManagerbuildManager){//首先,尝试从磁盘List的缓存中读取matchingTypes=ReadTypesFromCache(,buildManager,serializer);如果(匹配类型!=null){返回匹配类型;}//如果从缓存中读取失败,则枚举每个程序集以查找匹配类型matchingTypes=FilterTypesInAssemblies(buildManager,predicate).ToList();//最后将缓存存回磁盘SaveTypesToCache(cacheName,matchingTypes,buildManager,serializer);返回匹配类型;这段代码很容易解释:它使用TypeCacheSerializer类从缓存中读取它们。在内部,此序列化程序将文件加载到XmlDocument中,然后操作其元素以提取类型。如果在缓存中找不到任何内容,则会对FilterTypesInAssemblies方法进行昂贵的调用,该方法将使用反射从所有引用的程序FilterTypesInAssemblies中检索控制器类型。它将类型保存到缓存中,以便下次可以从缓存中加载它们。这是一篇也描述了该过程的博客文章:http://www.beletsky.net/2011/12/inside-aspnet-mvc-instantiation-of.html2)有没有办法在应用程序中使用它?您不应在代码中直接使用XML文件,因为其内容和格式可能会在未来的版本中发生变化,这会破坏您的代码。我同意,如果能够在我们的代码中利用此功能来提高昂贵的反射代码的性能,那就太好了。我希望框架的作者公开这个API。不幸的是他们没有,所以我们可以自己动手:publicstaticclassControllerTypeCache{privatestaticobject_syncRoot=newobject();私有静态类型[]_cache;publicstaticIEnumerableGetControllerTypes(){if(_cache==null){lock(_syncRoot){if(_cache==null){_cache=GetControllerTypesWithReflection();}}}返回新的ReadOnlyCollection(_cache);}privatestaticType[]GetControllerTypesWithReflection(){vartypesSoFar=Type.EmptyTypes;varassemblies=BuildManager.GetReferencedAssemblies();foreach(Assemblyassemblyinassemblies){Type[]typesInAsm;尝试{typesInAsm=assembly.GetTypes();}catch(ReflectionTypeLoadExceptionex){typesInAsm=ex.Types;}typesSoFar=typesSoFar.Concat(typesInAsm).ToArray();}返回类型SoFar}}还应该知道如何/何时更新方法GetControllerType(requestContext,controllerName);将根据在此文件中找到的内容返回您的控制器类类型此文件在应用程序的整个生命周期内永远不会更新。如前所述,它在应用程序启动时创建一次。我快速浏览了ASP.NETMVC源代码,据我所知,缓存文件是在第一次尝试读取它时创建的。这通常发生在应用程序启动期间。ASP.NETMVC包含一个内部类ControllerTypeCache,它包含一个包含文件名的常量字符串。这是源代码中唯一出现的“MVC-ControllerTypeCache.xml”。内部密封类ControllerTypeCache{privateconststringTypeCacheName="MVC-ControllerTypeCache.xml";...}这个常量只用在ControllerTypeCache类的这个方法中:publicvoidEnsureInitialized(IBuildManagerbuildManager){if(_cache==null){lock(_lockObj){if(_cache==null){.GetFilteredTypesFromAssemblies(TypeCacheName,IsControllerType,buildManager);vargroupedByName=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.GetFiltersTypesFromAssemblies。这是该方法的样子:publicstaticListGetFilteredTypesFromAssemblies(stringcacheName,Predicatepredicate,IBuildManagerbuildManager){//首先,尝试从磁盘List的缓存中读取matchingTypes=ReadTypesFromCache(buildManager,serializer);如果(匹配类型!=null){返回匹配类型;}//如果从缓存中读取失败,则枚举每个程序集以查找匹配类型matchingTypes=FilterTypesInAssemblies(buildManager,predicate).ToList();//最后,将缓存保存回磁盘SaveTypesToCache(cacheName,matchingTypes,buildManager,serializer);返回匹配类型;如您所见,它尝试从缓存文件中读取。如果读取失败(例如,因为文件尚不存在),则会生成一个新的控件类型列表并将其保存在新版本的缓存文件中。ReadTypesFromCache方法如下所示:内部静态列表ReadTypesFromCache(stringcacheName,Predicatepredicate,IBuildManagerbuildManager,TypeCacheSerializerserializer)if(stream!=null){using(Reader=stream!=null)StreamReader(stream)){列表deserializedTypes=serializer.DeserializeTypes(reader);if(deserializedTypes!=null&&deserializedTypes.All(type=>TypeIsPublicClass(type)&&predicate(type))){//如果所有读取类型仍然匹配谓词,成功!返回反序列化类型;}}}}catch{}返回空值;如您所见,它使用BuildManager读取缓存文件。这是我能找到的唯一可以读取或创建缓存文件的地方。在调用层次结构中导航时,我最终使用DefaultControllerFactory类或AreaRegistration类中的这个方法。所以我想这些类中的任何一个第一次需要应用程序中的控制器列表时,它们最终会调用TypeCacheUtil类的GetFilteredTypesFromAssemblies方法。它仅在无法读取文件时生成缓存文件。由于此类使用BuildManager来读取它,我相信它只会在文件损坏、丢失或应用程序重新启动时生成它。浏览网页后,人们似乎报告说,为了重新生成MVC-ControllerTypeCache.xml文件,更改并保存Global.asax或Web.Config文件以触发重新启动就可以了。你能在你自己的代码中使用这个文件吗?你可能可以,但你可能不应该。我只是用反射。如果您在使用这种方法时遇到性能问题,那么您可以开始考虑缓存,在这种情况下我敢打赌,构建您自己的序列化控制器列表并使用.NET的内置缓存机制来缓存它们会“更安全”而是尝试重用MVC-ControllerTypeCache.xml。我认为这是一个内部原因。以上就是C#学习教程:如何以及何时填写MVC-ControllerTypeCache.xml分享的所有内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场,如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处:
