在(三)的时候已经说到模块集合用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 > )
{
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 = ;
} 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 = ;
} 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的软件都不知道有哪些,后面学学看。

(五)学习了解OrchardCore笔记——灵魂中间件ModularTenantContainerMiddleware的第一行②模块的功能部分的更多相关文章

  1. (三)学习了解OrchardCore笔记——灵魂中间件ModularTenantContainerMiddleware的第一行①的模块部分

    了解到了OrchardCore主要由两个中间件(ModularTenantContainerMiddleware和ModularTenantRouterMiddleware)构成,下面开始了解Modu ...

  2. (二)学习了解OrchardCore笔记——开篇:OrchardCore的中间件

    现在开始看Starpup的中间件.这是一个扩展方法app.UseOrchardCore() public void Configure(IApplicationBuilder app, IHostEn ...

  3. (四)学习了解OrchardCore笔记——将模块的名字添加到程序集的ModuleName

    关于如何将模块名添加到程序集的ModuleName说简单吧也简单,说不简单吧也不简单. 简单的原因是代码只有几行,不简单的原因是这些都不是c#,都是MSbuild的代码.这可真难为我了,所以这个地方我 ...

  4. (一)学习了解OrchardCore笔记——开篇:基于asp.net core的OrchardCore

    想深入了解OrchadCore源码许久了,但是读源码的时候遇到很多问题而网上的参考资料太少了(几乎都是OrchadCms不带OrchardCore的),现在解决得差不多了,做下笔记方便自己查看,有错误 ...

  5. 学习phalcon框架按照官网手册搭建第一个项目注册功能

    中文手册官网:http://phalcon.ipanta.com/1.3/tutorial.html#bootstrap 官网提供http://www.tutorial.com项目源码github地址 ...

  6. (学习笔记)laravel 中间件

    (学习笔记)laravel 中间件 laravel的请求在进入逻辑处理之前会通过http中间件进行处理. 也就是说http请求的逻辑是这样的: 建立中间件 首先,通过Artisan命令建立一个中间件. ...

  7. Python学习的个人笔记(基础语法)

    Python学习的个人笔记 题外话: 我是一个大二的计算机系的学生,这份python学习个人笔记是趁寒假这一周在慕课网,w3cschool,还有借鉴了一些博客,资料整理出来的,用于自己方便的时候查阅, ...

  8. 《Python数据科学手册》第五章机器学习的笔记

    目录 <Python数据科学手册>第五章机器学习的笔记 0. 写在前面 1. 判定系数 2. 朴素贝叶斯 3. 自举重采样方法 4. 白化 5. 机器学习章节总结 <Python数据 ...

  9. hadoop2.5.2学习及实践笔记(二)—— 编译源代码及导入源码至eclipse

    生产环境中hadoop一般会选择64位版本,官方下载的hadoop安装包中的native库是32位的,因此运行64位版本时,需要自己编译64位的native库,并替换掉自带native库. 源码包下的 ...

随机推荐

  1. TensorFlow从0到1之TensorFlow超参数及其调整(24)

    正如你目前所看到的,神经网络的性能非常依赖超参数.因此,了解这些参数如何影响网络变得至关重要. 常见的超参数是学习率.正则化器.正则化系数.隐藏层的维数.初始权重值,甚至选择什么样的优化器优化权重和偏 ...

  2. CODING DevOps 系列第一课:基于开源工具链打造持续交付平台

    当下软件发展趋势 当今 IT 行业发展中比较流行的几个技术,首先是微服务化,将原有的一个系统拆分成多个,意味着有多个系统需要构建.测试.部署和运维. 第二个是敏捷开发模式,需求粒度更细化,要求一个可独 ...

  3. ca70a_c++_重载函数_实参类型转换

    /*ca70a_c++_重载函数_实参类型转换转换等级,详见P290 编译选择哪个函数版本呢?1.精确匹配2.通过类型提升3.通过标准转换4.通过类类型转换参数匹配和枚举类型重载和const形参 vo ...

  4. SQLserver 的分页存储过程

      -- 1.建立修改学生数据的存储过程 -- 2.建立根据班级Id和学生姓名模糊查询的分页存储过程,要求正确输出总记录数,总页数-- (输入班学生姓名 计算总记录数 计算总页数) -- @name ...

  5. ConcurrentHashMap源码解析-Java7

    目录 一.ConcurrentHashMap的模型图 二.源码分析-类定义 2.1 极简ConcurrentHashMap定义 2.2 Segment内部类 2.3 HashEntry内部类 2.4 ...

  6. 08.DRF-反序列化

    三.反序列化使用 3.1 验证 使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象. 在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功 ...

  7. Jmeter之仿真高并发测试-集合点

    场景: 大家在使用Jmeter测试的时候应该发现了, (1)线程启动了就会直接发送测试请求:--如果要模拟在一瞬间高并发量测试的时候,需要调高线程数量,这很耗测试机器的性能,往往无法支持较大的并发数, ...

  8. 如何用Tesseract做日文OCR(c#实现)

    首先做一下背景介绍,Tesseract是一个开源的OCR组件,主要针对的是打印体的文字识别,对手写的文字识别能力较差,支持多国语言(中文.英文.日文.韩文等).是开源世界里最强的一款OCR组件.当然和 ...

  9. IntelliJ IDEA安装配置、搭建Spring MVC

    安装前必备软件: 1.jdk1.8.0_144安装包 2.IntelliJ IDEA 2016.1.1(64) 3.Tomcat安装包 4.Mysql.MySQL-JDBC驱动安装包 5.Jetbra ...

  10. 一.1搭建跨平台的统一python开发环境

    搭建跨平台的统一python开发环境: 使用开发环境的好处: 可不用在服务器上直接修改源代码---写的代码首先得入版本库(放git或giitlab中),在本地写代码提交到git中.然后在服务器上git ...