OrchardCore 如何实现模块化( Modular )和 Multi-Tenancy

一、概述

通常我们会在 Startup 类通过 void ConfigureServices(IServiceCollection services) 配置应用的服务。常见的形如 AddXXX 的方法,实际上调用的都是 IServiceCollection 或直接说是 ServiceCollection 的 AddSingleton 等方法。调用ApplicationBuilder 的 RequestDelegate Build() 方法会调用 IServiceCollection 的扩展方法 BuildServiceProvider 会创建并返回一个 ServiceProvider 对象。
还会在 Startup 类通过 void Configure(IApplicationBuilder app, IHostingEnvironment env) 配置请求管道,在该方法内进行的主要操作是添加中间件。常见的形如 UseMiddleware 或 UseXXX 的方法,实际上调用的都是 IApplicationBuilder 或直接说是 ApplicationBuilder 的 IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware) 方法,Use 方法并不是马上将中间件配置入请求管道,而是将“实例化中间件的方式”保存到 ApplicationBuilder 内部一个列表的操作。调用ApplicationBuilder 的 RequestDelegate Build() 方法会实例化中间件并把各个中间件串联起来。

OrchardCore 通过将服务和中间件放在不同的程序集以支持模块化。各个模块提供类似于 ConfigureServices 和 Configure 的方法供运行时调用。

OrchardCore 还支持 Multi-TenancyTenant 有如下特性:

  1. 多个 Tenant 运行在同一个应用程序域中,每个 Tenant 几乎可以看做是独立的网站;

  2. 根据 Host 、Port 和 Path 的各种组合匹配不同的 Tenant(ModularTenantContainerMiddleware);

  3. 延迟激活,第一次请求 Tenant 才会激活(ModularTenantContainerMiddleware);

  4. 每个 Tenant 有不同的 DI 容器(ModularTenantContainerMiddleware);

  5. 每个 Tenant 有不同的请求管道,可以共享中间件,还可以使用特定中间件(ModularTenantRouterMiddleware)。

二、模块定义

模块是依赖于 OrchardCore.Modules.Targets 程序集的程序集,可以有各自的配置、选项、DI 服务和中间件等,还可以有各自的路由、视图、控制器、 Filter 和 ModelBinder 等,看起来像是一个 MVC Area
模块包含 0 或多个 Feature 。Feature 是功能的逻辑组合,可单独开启或禁用。
Feature 之间可有依赖关系,并且支持跨模块的依赖。

备注:
OrchardCore 中,一个程序集只包含一个模块。
模块可以看做是特殊的 Feature 。
用于定义 Theme 的 OrchardCore.Theme.Targets 程序集也依赖于 OrchardCore.Modules.Targets 程序集。

1、Mainifest.cs 文件

模块有个以程序集特性的形式嵌入程序集中的 Mainifest ,用于描述模块的基本信息、拥有的 Feature 和依赖的其他 Feature 等。一般写在 Mainifest.cs 文件中,比如:


using OrchardCore.Modules.Manifest;
[assembly: Module(
 Name = "XML-RPC",
 Author = "The Orchard Team",
 Website = "http://orchardproject.net",
 Version = "2.0.0"
)]
[assembly: Feature(
 Id = "OrchardCore.XmlRpc",
 Name = "XML-RPC",
 Description = "The XML-RPC module enables creation of contents from client applications such as Open Live Writer.",
 Category = "Infrastructure"
)]
[assembly: Feature(
 Id = "OrchardCore.RemotePublishing",
 Name = "Remote Publishing",
 Description = "The remote publishing feature enables creation of contents from client applications such as Open Live Writer.",
 Dependencies = new [] { "OrchardCore.XmlRpc" },
 Category = "Infrastructure"
)]

在运行时可将 Mainifest 读取至 MainifestInfo 对象中。
ModuleAttribure 用于描述模块基本信息,只能用于程序集并且只能使用一次,在运行时可读取至 ModuleInfo 对象中。
一个模块可以包含 0 或多个 Feature 。FeatureAttribure 用于描述模块提供的 Feature,只能用于程序集并且可以使用多次,在运行时可读取至 FeatureInfo 对象中。

备注:ModuleAttribute 继承自 FeatureAttribute ,都位于OrchardCore.Abstractions程序集、OrchardCore.Modules.Manifest命名空间中。

从类或对象来看,1 个 MainifestInfo 对象包含1个 ModuleInfo 对象,1 个 ModuleInfo 对象包含 0 或多个 FeatureInfo 对象。

2、ManifestInfo 和 FeatureInfo 类

ExtensionManager类用于获取 Mainifest ,并将相关数据反序列化入 ManifestInfo 和 FeatureInfo对象中。

3、ModuelNameAttribute 类

如果一个项目引用了一些模块,MSBuild 在生成项目时会针对每个模块添加一个程序集级的 ModuleNameAttrbute ,用于保存引用的模块名称。
AssemblyAttributeModuleNamesProvider 类的 IEnumerable<string> GetModuleNames() 方法能够收集到 ModuleNameAttrbute 。

备注:AssemblyAttributeModuleNamesProvider 位于OrchardCore.Abstractions程序集、OrchardCore.Modules命名空间中。

4、ModuleMarkerAttribute 类

MSBuild 在生成模块的项目时会自动添加程序集级的 ModuleMarkerAttribute 。ModuleMarkerAttribute 继承 ModuleAttribute),位于OrchardCore.Abstractions程序集、OrchardCore.Modules.Manifest命名空间中

5、ModuleAssetAttribute类

MSBuild 在生成模块的项目时会自动添加程序集级的 ModuleAssetAttribute。ModuleAssetAttribute继承 ModuleAttribute),位于OrchardCore.Abstractions程序集、OrchardCore.Modules.Manifest命名空间中

6、Module 类

在创建 Module 对象时,传入模块程序集的名称,构造函数会通过 Assembly.Load 加载模块程序集,并且收集模块的 ModuleAttribute、ModuleAssetAttribute 和 ModuleMarkerAttribute 放入自身属性中。

注意:这里说的是 Module 类不是 ModuleAttribute 类。

备注:ModularApplicationContext 位于 OrchardCore.Abstractions程序集、OrchardCore.Modules命名空间中。

7、IStartup 接口

每个模块可能需要注册一些服务至 DI 容器中,也可能需要注册一些中间件。OrchardCore 定义了一个 OrchardCore.Modules.IStartup, OrchardCore.Modules.Abstractions 接口,以及实现了该接口的 OrchardCore.Module s.StartupBase, sOrchardCore.Modules.Abstractions 抽象类。OrchardCore 模块通常有一个 Startup.cs 文件,实现了继承自 SetupBase 抽象类的名为 Startup 的具体类。

注意:OrchardCore 的 Startup 类不是指通常 ASP.NET Core 中的那个类,IStartup 接口也不是通常 ASP.NET Core 中的那个接口,尽管它们的确很相似。

通常,对于 ASP.NET Core 应用的 Startup 类我们不直接实现 IStartup 接口,而采用更灵活的基于方法名约定的方式。另外,通过 IHostingStartup(承载启动)实现,在启动时从外部程序集向应用添加增强功能。但是使用 IHostingStartup 无法控制各个模块注册服务和添加中间件的顺序,也不支持延迟加载。
OrchardCore.Modules.IStartup,OrchardCore.Modules.Abstractions 相较于 Microsoft.AspNetCore.Hosting.IStartup,Microsoft.AspNetCore.Hosting.Abstractions 多了个 Order 属性,并且前者的 Configure 方法签名为void Configure(IApplicationBuilder app, IRouteBuilder routes, IServiceProvider serviceProvider),后者为 void Configure(IApplicationBuilder app)。因为模块通常位于不同的程序集, Order 属性的作用是控制向 DI 容器注册服务、添加中间件、添加配置和添加路由的顺序。

备注:void Configure(IApplicationBuilder app, IRouteBuilder routes, IServiceProvider serviceProvider) 的 routes 和 serviceProvier 是为了支持模块化和 Multi-Tenancy

三、模块引擎

事实上没有一种明确的组件叫模块引擎。OrchardCore 提供了一些由于支持模块的基础设施,并提供将分散于各个模块的服务收集起来注册至 DI 容器,以及中间件添加至请求管道的机制。

1、AddOrchardCore

AddOrchardCore 不准确地说就是将服务注册至 DI 容器中以及将中间件添加至请求管道的,并返回一个 OrchardCoreBuilder 对象。
OrchardCoreBuilder 严格来说不是生成器模式,它类似于 Startup 类有 ConfigureServices 和 Configure方法。但是当调用这两类方法时,并不是直接将服务注册到 DI 容器中或注册中间件,而是将注册的方式通过委托保存在集合中(通过 StartupAction )。这样做的目的是为了将来给每个 Tenant 注册这些服务和中间件。


/// <summary>
/// Adds OrchardCore services to the host service collection.
/// </summary>
public static OrchardCoreBuilder AddOrchardCore(this IServiceCollection services)
{
   // If an instance of OrchardCoreBuilder exists reuse it,
   // so we can call AddOrchardCore several times.
   var builder = services
       .LastOrDefault(d => d.ServiceType == typeof(OrchardCoreBuilder))?
       .ImplementationInstance as OrchardCoreBuilder;
   if (builder == null)
   {
       builder = new OrchardCoreBuilder(services);
       services.AddSingleton(builder);

       AddDefaultServices(services);
       AddShellServices(services);
       AddExtensionServices(builder);

       AddStaticFiles(builder);

       AddAntiForgery(builder);
       AddAuthentication(builder);
       AddDataProtection(builder);

       // Register the list of services to be resolved later on
       services.AddSingleton(services);
   }
   return builder;
}

① AddDefaultServices

添加默认服务,比如 Logging、Localization 和 Web Encoders (Web Encoders 是指 Html、Url 和 Javascript 的编码器)。
重要的是添加 Routing 服务。IServiceCollection 的扩展方法 AddMvc/AddMvcCore 会添加 Routing 服务。就算不是 MVC 应用也可以是使用路由,并且 OrchardCore 的路由可配置在不同的模块,所以在这里注册是因为后续会使用 Routing 相关服务。

② AddShellServices

添加用于支持 Tenant 的相关服务。Shell 涉及众多的类,这里暂时不分析。

③ AddExtensionServices

添加用于支持模块化的相关服务。主要是 AssemblyAttributeModuleNamesProvider : IModuleNamesProvider 和 ModularApplicationContext : IApplicationContext 。
AssemblyAttributeModuleNamesProvider 提供了一种从程序集的 Attribute 获取模块名称的方式。
ModularApplicationContext 提供了一个 OrchardCore.Modules.Application 对象,可在某些情况下指代应用。使用 ModularApplicationContext 的属性 Application 时,会触发 Application 对象的构造过程。

④ AddStaticFiles

添加静态文件服务中间件,主要是增加 ModuleEmbeddedStaticFileProvider 的支持。

⑤ AddAntiForgery

主要是提供对 Multi-Tenancy 的支持。为不同的 Tenant 的 Antiforgery Cookie 设置的名称和路径。

⑥ AddAuthentication

主要是提供对 Multi-Tenancy 的支持。

⑦ AddDataProtection

主要是提供对 Multi-Tenancy 的支持。

2、AddMvc

AddMvc 主要作用是添加和 Mvc 相关的中间件。请注意这是 OrchardBuilder 而不是 IServiceCollection 的扩展方法。
类似的方法 AddNancy 用于提供对 Nancy 的支持。

3、UseOrchardCore

UseOrchardCore 是一个 IApplicationBuilder 的扩展方法,主要作用是添加中间件 ModularTenantContainerMiddleware 和 ModularTenantRouterMiddleware 。


namespace Microsoft.AspNetCore.Builder
{
 public static class ApplicationBuilderExtensions
 {
      /// <summary>
      /// Enables multi-tenant requests support for the current path.
      /// </summary>
      public static IApplicationBuilder UseOrchardCore(this IApplicationBuilder app, Action<IApplicationBuilder> configure = null)
      {
          var env = app.ApplicationServices.GetRequiredService<IHostingEnvironment>();
          var appContext = app.ApplicationServices.GetRequiredService<IApplicationContext>();
          env.ContentRootFileProvider = new CompositeFileProvider(
              new ModuleEmbeddedFileProvider(appContext),
              env.ContentRootFileProvider);
          app.UseMiddleware<PoweredByMiddleware>();
          // Ensure the shell tenants are loaded when a request comes in
          // and replaces the current service provider for the tenant's one.
          app.UseMiddleware<ModularTenantContainerMiddleware>();
          configure?.Invoke(app);
          app.UseMiddleware<ModularTenantRouterMiddleware>();
          return app;
      }
 }
}

四、Multi-Tenancy

在 ModularTenantContainerMiddleware 中间件中,根据 Host 、Port 和 Path 的各种组合匹配不同的 Tenant 。Tenant 的激活延迟性的,在第一次请求 Tenant 才会激活。每个 Tenant 可以有不同的 DI 容器。

在 ModularTenantRouterMiddleware 中间件中,为当前 Tenant 配置单独的请求管道。

五、服务和中间件注册点

总结一下目前为止遇见的服务和中间件注册点。

1、服务注册点

包含名为 ConfigureServices 或类似的方法的接口和类:

类/接口程序集命名空间备注
IStartupMicrosoft.AspNetCore.Hosting.AbstractionsMicrosoft.AspNetCore.Hosting接口。
IStartupMicrosoft.AspNetCore.Hosting.AbstractionsMicrosoft.AspNetCore.Hosting接口。
Startup自定义自定义定义于应用。不继承任何接口或类,实现 Configure 和 ConfigureServices 等方法。
IWebHostBuilderMicrosoft.AspNetCore.Hosting.Abstractions接口。
WebHostBuilder : IWebHostBuilderMicrosoft.AspNetCore.HostingMicrosoft.AspNetCore.HostingConfigureServices 不会进行实际的服务注册操作,当调用 Build 方法时才注册。
IStartupOrchardCore.Modules.AbstractionsOrchardCore.Modules接口。
StartupBase: IStartupOrchardCore.Modules.AbstractionsOrchardCore.Modules抽象类。
Startup: SetupBase自定义自定义定义于 OrchareCore 模块。
OrchardCoreBuilderOrchardCore .Modules.AbstractionsMicrosoft.Extensions.DependencyInjection注册 Tenant 服务和中间件。
StartupActionsOrchardCore.Modules.AbstractionsMicrosoft.Extensions.DependencyInjection包含 ConfigureServicesActions 属性,而非方法。

2、中间件注册点

包含名为 Configure 或类似方法的接口和类:

类/接口程序集命名空间备注
IStartupMicrosoft.AspNetCore.Hosting.AbstractionsMicrosoft.AspNetCore.Hosting接口。
IHostingStartupMicrosoft.AspNetCore.Hosting.AbstractionsMicrosoft.AspNetCore.Hosting接口。
HostingStartup:IHostingStartup自定义自定义定义于应用。
Startup自定义自定义定义于应用。不继承任何接口或类,实现 Configure 和 ConfigureServices 等方法。
IWebHostBuilderMicrosoft.AspNetCore.Hosting.Abstractions接口。
WebHostBuilder : IWebHostBuilderMicrosoft.AspNetCore.HostingMicrosoft.AspNetCore.HostingConfigure 不会进行实际的添加注册操作,当调用 Build 方法时才注册。
IStartupOrchardCore.Modules.AbstractionsOrchardCore.Modules接口。
StartupBase: IStartupOrchardCore.Modules.AbstractionsOrchardCore.Modules抽象类。
Startup: SetupBase自定义自定义定义于 OrchareCore 模块。
OrchardCoreBuilderOrchardCore .Modules.AbstractionsMicrosoft.Extensions.DependencyInjection注册 Tenant 服务和中间件。
StartupActionsOrchardCore.Modules.AbstractionsMicrosoft.Extensions.DependencyInjection包含 ConfigureActions 属性,而非方法。
IStartupFilterMicrosoft.AspNetCore.Hosting.AbstractionsMicrosoft.AspNetCore.Hosting定义于应用或 OrchareCore 模块。需注册为服务。

参考资料

https://orchardcore.readthedocs.io/en/latest/
http://docs.orchardproject.net/en/latest/
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/startup?view=aspnetcore-2.1
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/host/platform-specific-configuration?view=aspnetcore-2.1
https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/host/web-host?view=aspnetcore-2.1

原文地址: https://www.cnblogs.com/alby/p/orchardcore-modular-and-multi-tenancy.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318774.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

牛客题霸 [ 最长回文子串] C++题解/答案

牛客题霸 [ 最长回文子串] C题解/答案 题目描述 对于一个字符串&#xff0c;请设计一个高效算法&#xff0c;计算其中最长回文子串的长度。 给定字符串A以及它的长度n&#xff0c;请返回最长回文子串的长度。 题解&#xff1a; 两个方法&#xff1a; 一个是经典暴力&#…

【.NET Core项目实战-统一认证平台】第八章 授权篇-IdentityServer4源码分析

上篇文章我介绍了如何在网关上实现客户端自定义限流功能&#xff0c;基本完成了关于网关的一些自定义扩展需求&#xff0c;后面几篇将介绍基于IdentityServer4&#xff08;后面简称Ids4&#xff09;的认证相关知识&#xff0c;在具体介绍ids4实现我们统一认证的相关功能前&…

T183637-变异距离(2021 CoE III C)【单调栈】

正题 题目链接:https://www.luogu.com.cn/problem/T183637 题目大意 给出nnn个二元组(xi,yi)(x_i,y_i)(xi​,yi​)&#xff0c;求最大的 ∣xi−xj∣min{∣yi∣,∣yj∣}|x_i-x_j|\times min\{|y_i|,|y_j|\}∣xi​−xj​∣min{∣yi​∣,∣yj​∣} 1≤n≤2106,−106≤xi≤106,−…

dfs剪枝:洛谷P2809 hzwer爱折纸

传送门 解析 dfs暴力枚举即可 这题的重点是如何剪枝 不难发现&#xff0c;随着不断处理&#xff0c;纸条只会越来越短&#xff0c;且所有数字总加和不变 我一开始想到了2个条件&#xff1a; 1.当前长度比理想纸条小&#xff0c;return&#xff1b; 2.总加和与理想纸条不等&a…

[译]聊聊C#中的泛型的使用

写在前面今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章&#xff0c;因此加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译&#xff0c;当然在翻译的过程中发现了一些问题&#xff0c;因此也进行了纠正&#xff0c;当然&#xff0c;原文的地址我放在最…

P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】

前言 话说在LojLojLoj下了个数据发现这题的名字叫fgofgofgo 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 nnn张卡的权值为1/2/31/2/31/2/3的概率权重分别是px,1/2/3p_{x,1/2/3}px,1/2/3​&#xff0c;然后按照权值每次获得一张未获得的卡&#xff0c;然后…

模板:线段树

文章目录引言思想模板建树单点修改 / 查询区间修改/查询总结练习引言 有一类题目:要求在区间上维护信息&#xff0c;比如带修改区间求和问题。考虑到枚举求和肯定会超时&#xff0c;我们可以通过一些数据结构来维护信息&#xff0c;例如线段树。 它功能强大&#xff0c;支持区…

Docker最全教程——从理论到实战(三)

容器是应用走向云端之后必然的发展趋势&#xff0c;因此笔者非常乐于和大家分享我们这段时间对容器的理解、心得和实践。本篇教程持续编写了2个星期左右&#xff0c;只是为了大家更好地了解、理解和消化这个技术&#xff0c;能够搭上这波车。你可以关注我们的公众号“magiccode…

高并发、低延迟之C#玩转CPU高速缓存(附示例)

写在前面好久没有写博客了&#xff0c;一直在不断地探索响应式DDD&#xff0c;又get到了很多新知识&#xff0c;解惑了很多老问题&#xff0c;最近读了Martin Fowler大师一篇非常精彩的博客The LMAX Architecture&#xff0c;里面有一个术语Mechanical Sympathy&#xff0c;姑且…

RMQ问题:与众不同(st表的高端应用)

解析 预处理 用pre[i]表示以i结尾的最长完美序列起始点&#xff0c;用last[i]表示数字i最后出现的位置 那么可以得到递推式&#xff1a; pre[i]max(pre[i-1],last[x[i]]1);也就是说这个pre要么是受前一位一样的限制&#xff0c;要么是受自己的限制 用f[i]表示以i结尾的最长完…

Docker最全教程——从理论到实战(四)

容器是应用走向云端之后必然的发展趋势&#xff0c;因此笔者非常乐于和大家分享我们这段时间对容器的理解、心得和实践。本篇教程持续编写了2个星期左右并且一直在完善、补充具体的细节和实践&#xff0c;预计全部完成需要1到2个月的时间。由于编写的过程中极其费时&#xff0c…

动态规划:openjudge 2.6-3532 最大上升子序列和 解题心得

传送门 题目描述 一个数的序列bi&#xff0c;当b1 < b2 < … < bS的时候&#xff0c;我们称这个序列是上升的。对于给定的一个序列(a1, a2, …,aN)&#xff0c;我们可以得到一些上升的子序列(ai1, ai2, …, aiK)&#xff0c;这里1 < i1 < i2 < … < iK…

边缘化搭建 DotNet Core 2.1 自动化发布和部署(下)

写在前面本篇文章是上一篇边缘化搭建 DotNet Core 2.1 自动化发布和部署(上)的后续操作&#xff0c;本文主要讲解如何开启Docker Remote API&#xff0c;开启Remote API后的权限安全问题。配置Jenkins构建项目&#xff0c;并在云服务器上构建成功。废话不多说&#xff0c;我们一…

边缘化搭建DotNet Core 2.1 自动化构建和部署环境(上)

写在前面写这篇文章的缘由是由于笔者的对新兴技术方向有所追求&#xff0c;但个人资产有限&#xff0c;只能容许购买一台阿里云低配1核2G服务器。服务器上搭建了 Centos7 & Docker & Jenkins & ASP.NET Core 2.0 自动化发布和部署 环境后牺牲了大部分性能。造成了一…

.NET Core实战项目之CMS 第六章 入门篇-Vue的快速入门及其使用

写在前面上面文章我给大家介绍了Dapper这个ORM框架的简单使用&#xff0c;大伙会用了嘛&#xff01;本来今天这篇文章是要讲Vue的快速入门的&#xff0c;原因是想在后面的文章中使用Vue进行这个CMS系统的后台管理界面的实现。但是奈何Vue实现的SPA有一定的门槛&#xff0c;不太…

不止代码:ybtoj-棋盘分割(二维区间dp)

题目描述 将一个8*8的棋盘进行如下分割&#xff1a;将原棋盘割下一块矩形棋盘并使剩下部分也是矩形&#xff0c;再将剩下的部分继续如此分割&#xff0c;这样割了n-1次后&#xff0c;连同最后剩下的矩形棋盘共有n块矩形棋盘。 (每次切割都只能沿着棋盘格子的边进行) 原棋盘上…

通俗易懂,C#如何安全、高效地玩转任何种类的内存之Span

前言作为.net程序员&#xff0c;使用过指针&#xff0c;写过不安全代码吗&#xff1f;为什么要使用指针&#xff0c;什么时候需要使用它&#xff1f;如果能很好地回答这两个问题&#xff0c;那么就能很好地理解今天了主题了。C#构建了一个托管世界&#xff0c;在这个世界里&…

AC自动机:例题与机制详解

介绍 AC自动机是kmp算法和trie树的结合 大体就是做这样的题用&#xff1a; 可以发现&#xff0c;这题和trie树的区别是把多个单词往一篇文章匹配&#xff0c;而trie恰好相反 匹配的时候其实就是判断子串&#xff0c;所以又用到了kmp 定义失配指针nxt[i]&#xff1a;表示root到…

.NET Core实战项目之CMS 第七章 设计篇-用户权限极简设计全过程

写在前面这篇我们对用户权限进行极简设计并保留其扩展性。首先很感谢大家的阅读&#xff0c;前面六章我带着大家快速入门了ASP.NET Core、ASP.NET Core的启动过程源码解析及配置文件的加载过程源码解析并引入依赖注入的概念、Git的快速入门、Dapper的快速入门、Vue的快速入门。…

2021“MINIEYE杯”中国大学生算法设计超级联赛(5)Random Walk 2(推式子+矩阵逆+矩阵乘)

Random Walk 2 【2.4】Gauss-Jordan消元法求矩阵的逆 高斯消元求矩阵的逆&#xff0c;伴随单位矩阵一起消元即可。 [A,I]→[I,A−1][\text A,\text I]\to [\text I,\text A^{-1}][A,I]→[I,A−1] 移项变形&#xff0c;后就是个矩阵的逆&#xff0c;为啥赛时不写&#xff1f;&a…