带你读开源—ASP.NET_MVC(八)

上篇说到GetControllerTypeWithinNamespaces方法,我们跟踪进入其定义后,发现其调用了ControllerTypeCache.GetControllerTypes方法,从ControllerTypeCache这个名称我们就可以猜测出,它是从某个缓存中查找控制器类型的。跟踪之,进入代码段1。

C# code

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  public ICollection<Type> GetControllerTypes(string controllerName, HashSet<string> namespaces)
        {
            HashSet<Type> matchingTypes = new HashSet<Type>();
            ILookup<string, Type> namespaceLookup;
            if (_cache.TryGetValue(controllerName, out namespaceLookup))
            {
                // this friendly name was located in the cache, now cycle through namespaces
                if (namespaces != null)
                {
                    foreach (string requestedNamespace in namespaces)
                    {
                        foreach (var targetNamespaceGrouping in namespaceLookup)
                        {
                            if (IsNamespaceMatch(requestedNamespace, targetNamespaceGrouping.Key))
                            {
                                matchingTypes.UnionWith(targetNamespaceGrouping);
                            }
                        }
                    }
                }
                else
                {
                    // if the namespaces parameter is null, search *every* namespace
                    foreach (var namespaceGroup in namespaceLookup)
                    {
                        matchingTypes.UnionWith(namespaceGroup);
                    }
                }
            }
            return matchingTypes;
        }

 

代码段 1

代码段1中,我们看语句【_cache.TryGetValue(controllerName, out namespaceLookup)】,其中的_cache是一个字典对象,涉及到它的操作见代码段2。

C# code

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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);
                    }
                }
            }
        }

 

代码段 2

在代码段2中找到GetFilteredTypesFromAssemblies方法,跟踪进入其定义(代码段3),里面又有三条很扎眼的注释:【// first, try reading from the cache on disk】、【// if reading from the cache failed, enumerate over every assembly looking for a matching type】、【// finally, save the cache back to disk】,看来微软开源项目组很喜欢“三”这个数字,呵呵!给大家大概翻译一下:首先,尝试读取磁盘缓存;如果缓存读取失败,则枚举所有程序集,以寻找匹配的类型;最后,把缓存保存回磁盘。这就验证了MVC框架从缓存获取控制器类型的猜测。

C# code

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  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;
        }

 

代码段 3

好了,现在我们得到了控制器的类型。我们再回到DefaultControllerFactory的CreateController方法,找到语句【IController controller = GetControllerInstance(requestContext, controllerType);】,这句的作用是实例化IController接口。跟踪GetControllerInstance的定义,见代码段4。

C# code

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType == null)
            {
                throw new HttpException(404,
                                        String.Format(
                                            CultureInfo.CurrentCulture,
                                            MvcResources.DefaultControllerFactory_NoControllerFound,
                                            requestContext.HttpContext.Request.Path));
            }
            if (!typeof(IController).IsAssignableFrom(controllerType))
            {
                throw new ArgumentException(
                    String.Format(
                        CultureInfo.CurrentCulture,
                        MvcResources.DefaultControllerFactory_TypeDoesNotSubclassControllerBase,
                        controllerType),
                    "controllerType");
            }
            return ControllerActivator.Create(requestContext, controllerType);
        }

 

代码段 4

代码段4最后一句【return ControllerActivator.Create(requestContext, controllerType);】,正是这一句创建了IController实例。
OK,控制器的实例化完成了。

xiaotmh
  • 版权声明: 本文源自 CSDN CKAOS, 于9个月前,由整理发表,共 5237字。
  • 原文链接:点此查看原文

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: