zoukankan      html  css  js  c++  java
  • (五)学习了解OrchardCore笔记——灵魂中间件ModularTenantContainerMiddleware的第一行②模块的功能部分

      在(三)的时候已经说到模块集合用ForEachAsync的扩展方法分配多个任务,把每个modules的ManifestInfo分析出来的功能加入ConcurrentDictionary。我们先看看这个扩展方法:

    public static class EnumerableExtensions
        {
            public static Task ForEachAsync<T>(this IEnumerable<T> source, Func<T, Task> body)
            {
                var partitionCount = System.Environment.ProcessorCount;
    
                return Task.WhenAll(
                    from partition in Partitioner.Create(source).GetPartitions(partitionCount)
                    select Task.Run(async delegate
                    {
                        using (partition)
                        {
                            while (partition.MoveNext())
                            {
                                await body(partition.Current);
                            }
                        }
                    }));
            }
        }

      这个查下msdn就非常简单明了,partitionCount获取可用逻辑处理器的数量(网上也有说是一组逻辑处理器的数量,一组的区别是有的服务器cpu是多组核心构成的,clr只能在一组逻辑处理器运行?也有人说现在已经可以运行在该服务器所有逻辑处理器上了,这点我不清楚,因为我没有这么多核心的处理器可以测试,这里当作所有逻辑处理器吧)。然后Partitioner.Create(source)就是把模块集合创建成可排序的程序分区,GetPartitions(partitionCount)就是按逻辑处理器的数量分区,然后开始按分区执行任务,看看partition.MoveNext()就是每个分区都是一个接着一个执行到最后一个集合的元素(Task.WhenAll和Task.Run这个不用说估计大家都懂,不懂自己msdn),partition.Current就是当前位置的元素。body就是委托,因此可以清晰的知道ForEachAsync就是把modules集合按逻辑处理器分区然后迭代执行委托,天啊,我只会foreach,这种多线程操作我也是第一次见。

      返回ExtensionManager类继续看看ForEachAsync这部分代码

              // Load all extensions in parallel
                    await modules.ForEachAsync((module) =>
                    {
                        if (!module.ModuleInfo.Exists)
                        {
                            return Task.CompletedTask;
                        }
                        var manifestInfo = new ManifestInfo(module.ModuleInfo);
    
                        var extensionInfo = new ExtensionInfo(module.SubPath, manifestInfo, (mi, ei) =>
                        {
                            return _featuresProvider.GetFeatures(ei, mi);
                        });
    
                        var entry = new ExtensionEntry
                        {
                            ExtensionInfo = extensionInfo,
                            Assembly = module.Assembly,
                            ExportedTypes = module.Assembly.ExportedTypes
                        };
    
                        loadedExtensions.TryAdd(module.Name, entry);
    
                        return Task.CompletedTask;
                    });

      每个modules集合的元素都执行一遍ForEachAsync里面的委托(我还是喜欢c里面指针函数的叫法,因为明显就是个函数吗)。看看这个函数不对是委托,传入参数就是具体的某一个module,先判断module.ModuleInfo是否存在,之前篇幅没说这个module.ModuleInfo其实就是每个模块项目(包括主题项目)里面的Manifest.cs文件映射到类,看看Module的构造函数就很清楚了(在(三)里面Application实例化中第二个参数里面GetModules()添加Module的时候)。也就是说以后自定义模块必须包含这个文件,不然不会加载进来。接下来就实例化该模块的扩展信息类extensionInfo,这个类很简单,我们看看ExtensionInfo的代码:

        public class ExtensionInfo : IExtensionInfo
        {
            public ExtensionInfo(
                string subPath,
                IManifestInfo manifestInfo,
                Func<IManifestInfo, IExtensionInfo, IEnumerable<IFeatureInfo>> features)
            {
                SubPath = subPath;
                Manifest = manifestInfo;
                Features = features(manifestInfo, this);
            }
    
            public string Id => Manifest.ModuleInfo.Id;
            public string SubPath { get; }
            public IManifestInfo Manifest { get; }
            public IEnumerable<IFeatureInfo> Features { get; }
            public bool Exists => Manifest.Exists;
        }

      里面主要几个属性((三)里没追踪Modules自己追踪下很清楚这些属性的值是什么)。构造函数传入的三个参数也很明了就是实例化给属性赋值。1、SubPath模块的路径,自己点下很清晰就是Areas/模块名,这个很属性吧,没错,跟asp.net core的区域一样。2、Manifest模块的Manifest.cs文件反射出的类。3、调用这个委托给功能集合赋值。我们看看这个委托实现的代码(跟ExtensionManager同个目录下有个Features目录的FeaturesProvider类):

      

       public class FeaturesProvider : IFeaturesProvider
        {
            public const string FeatureProviderCacheKey = "FeatureProvider:Features";
    
            private readonly IEnumerable<IFeatureBuilderEvents> _featureBuilderEvents;
    
            public FeaturesProvider(IEnumerable<IFeatureBuilderEvents> featureBuilderEvents)
            {
                _featureBuilderEvents = featureBuilderEvents;
            }
    
            public IEnumerable<IFeatureInfo> GetFeatures(
                IExtensionInfo extensionInfo,
                IManifestInfo manifestInfo)
            {
                var featuresInfos = new List<IFeatureInfo>();
    
                // Features and Dependencies live within this section
                var features = manifestInfo.ModuleInfo.Features.ToList();
                if (features.Count > 0)
                {
                    foreach (var feature in features)
                    {
                        if (String.IsNullOrWhiteSpace(feature.Id))
                        {
                            throw new ArgumentException(
                                $"A feature is missing a mandatory 'Id' property in the Module '{extensionInfo.Id}'");
                        }
    
                        var featureId = feature.Id;
                        var featureName = feature.Name ?? feature.Id;
    
                        var featureDependencyIds = feature.Dependencies
                            .Select(e => e.Trim()).ToArray();
    
                        if (!int.TryParse(feature.Priority ?? manifestInfo.ModuleInfo.Priority, out int featurePriority))
                        {
                            featurePriority = 0;
                        }
    
                        var featureCategory = feature.Category ?? manifestInfo.ModuleInfo.Category;
                        var featureDescription = feature.Description ?? manifestInfo.ModuleInfo.Description;
                        var featureDefaultTenantOnly = feature.DefaultTenantOnly;
                        var featureIsAlwaysEnabled = feature.IsAlwaysEnabled;
    
                        var context = new FeatureBuildingContext
                        {
                            FeatureId = featureId,
                            FeatureName = featureName,
                            Category = featureCategory,
                            Description = featureDescription,
                            ExtensionInfo = extensionInfo,
                            ManifestInfo = manifestInfo,
                            Priority = featurePriority,
                            FeatureDependencyIds = featureDependencyIds,
                            DefaultTenantOnly = featureDefaultTenantOnly,
                            IsAlwaysEnabled = featureIsAlwaysEnabled
                        };
    
                        foreach (var builder in _featureBuilderEvents)
                        {
                            builder.Building(context);
                        }
    
                        var featureInfo = new FeatureInfo(
                            featureId,
                            featureName,
                            featurePriority,
                            featureCategory,
                            featureDescription,
                            extensionInfo,
                            featureDependencyIds,
                            featureDefaultTenantOnly,
                            featureIsAlwaysEnabled);
    
                        foreach (var builder in _featureBuilderEvents)
                        {
                            builder.Built(featureInfo);
                        }
    
                        featuresInfos.Add(featureInfo);
                    }
                }
                else
                {
                    // The Extension has only one feature, itself, and that can have dependencies
                    var featureId = extensionInfo.Id;
                    var featureName = manifestInfo.Name;
    
                    var featureDependencyIds = manifestInfo.ModuleInfo.Dependencies
                        .Select(e => e.Trim()).ToArray();
    
                    if (!int.TryParse(manifestInfo.ModuleInfo.Priority, out int featurePriority))
                    {
                        featurePriority = 0;
                    }
    
                    var featureCategory = manifestInfo.ModuleInfo.Category;
                    var featureDescription = manifestInfo.ModuleInfo.Description;
                    var featureDefaultTenantOnly = manifestInfo.ModuleInfo.DefaultTenantOnly;
                    var featureIsAlwaysEnabled = manifestInfo.ModuleInfo.IsAlwaysEnabled;
    
                    var context = new FeatureBuildingContext
                    {
                        FeatureId = featureId,
                        FeatureName = featureName,
                        Category = featureCategory,
                        Description = featureDescription,
                        ExtensionInfo = extensionInfo,
                        ManifestInfo = manifestInfo,
                        Priority = featurePriority,
                        FeatureDependencyIds = featureDependencyIds,
                        DefaultTenantOnly = featureDefaultTenantOnly,
                        IsAlwaysEnabled = featureIsAlwaysEnabled
                    };
    
                    foreach (var builder in _featureBuilderEvents)
                    {
                        builder.Building(context);
                    }
    
                    var featureInfo = new FeatureInfo(
                        context.FeatureId,
                        context.FeatureName,
                        context.Priority,
                        context.Category,
                        context.Description,
                        context.ExtensionInfo,
                        context.FeatureDependencyIds,
                        context.DefaultTenantOnly,
                        context.IsAlwaysEnabled);
    
                    foreach (var builder in _featureBuilderEvents)
                    {
                        builder.Built(featureInfo);
                    }
    
                    featuresInfos.Add(featureInfo);
                }
    
                return featuresInfos;
            }
        }

      看起来有点长,其实没啥说的,基本都在赋值,构造函数通过依赖注入解决,略过。直接看看委托的方法GetFeatures(IExtensionInfo extensionInfo,IManifestInfo manifestInfo),两个参数就是刚刚那个扩展信息和对应的mainfest.cs所反射的类。创建要返回的功能列表信息集合var featuresInfos = new List<IFeatureInfo>()。然后获取该模块依赖的功能集合var features = manifestInfo.ModuleInfo.Features.ToList(),官网也说了一个模块可以有0到多个功能,具体就是Manifest.cs文件有没多个assembly: Feature,具体代码0个和多个并没有多大区别,你可以发现多个了用foreach把每个功能加入集合,0个就用扩展信息填充功能然后加入集合返回。这些没啥问题,然后之前好像注入了什么featureBuilderEvents在这里居然有两个方法Building和Built,它们实现的类是ThemeFeatureBuilderEvents(继承FeatureBuilderEvents,依赖注入不说也懂,直接找实现就对了,我最怕Events了,我最不了解事件,说是委托的封装,委托我直接理解成指针函数,事件这个概念我还没想好代替的说辞,其实我都是简单的理解成多个委托,毕竟事件和委托的区别就是事件可以有多个方法嘛,不对多个委托,我c#都是自学,这些概念可能表述不清楚,上学科班只教了c和java里面都没这种概念,我是计算机系但是非软件专业而是网络专业,见谅)。重写了方法Building,就是提取出主题啊(判断是否是主题),(四)这篇说过,模块包含三个解决方案文件夹里的项目:普通模块、cms模块和主题模块(可能上篇表述不一样)。下面代码很明显就是有基础主题就修改下:

      

        public class ThemeFeatureBuilderEvents : FeatureBuilderEvents
        {
            public override void Building(FeatureBuildingContext context)
            {
                var moduleInfo = context.ExtensionInfo.Manifest.ModuleInfo;
    
                if (moduleInfo is ThemeAttribute || (moduleInfo is ModuleMarkerAttribute &&
                    moduleInfo.Type.Equals("Theme", StringComparison.OrdinalIgnoreCase)))
                {
                    var extensionInfo = new ThemeExtensionInfo(context.ExtensionInfo);
    
                    if (extensionInfo.HasBaseTheme())
                    {
                        context.FeatureDependencyIds = context
                            .FeatureDependencyIds
                            .Concat(new[] { extensionInfo.BaseTheme })
                            .ToArray();
                    }
    
                    context.ExtensionInfo = extensionInfo;
                }
            }
        }

      感觉第(四)篇了解过后没啥说的,后面直接跟踪就好了,是我的角度不对?怪不得别人都从架构说起,我从asp.net core按流程说中间少了点什么,有点不连贯,老是得去补充点什么,越说越乱,被我弄乱的感觉还不如直接自己追踪下源码?我看看能不能努力写到下个中间件。要我从架构上说我办不到啊,我连画uml的软件都不知道有哪些,后面学学看。

  • 相关阅读:
    exchangeNetwork
    VRP OS Management
    filleSystemBasises
    Study_way
    1.MySQL 安装
    7.进程池与线程池
    6.线程
    5.进程 -锁
    4.进程-1
    3.多线程TCP协议与加密方式
  • 原文地址:https://www.cnblogs.com/ShuiSen/p/13297787.html
Copyright © 2011-2022 走看看