(二)学习了解OrchardCore笔记——开篇:OrchardCore的中间件
现在开始看Starpup的中间件。这是一个扩展方法app.UseOrchardCore()
public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseStaticFiles(); app.UseOrchardCore();
}
直接查看扩展方法,vs都是直接按住ctrl键+鼠标左键就可以跳转到具体方法,下面我我们定位到方法里面去。
可以清楚的看到下面代码又是很熟悉的结构。
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<IHostEnvironment>();
var appContext = app.ApplicationServices.GetRequiredService<IApplicationContext>(); env.ContentRootFileProvider = new CompositeFileProvider(
new ModuleEmbeddedFileProvider(appContext),
env.ContentRootFileProvider); // Init also the web host 'ContentRootFileProvider'.
app.ApplicationServices.GetRequiredService<IWebHostEnvironment>()
.ContentRootFileProvider = 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>(app.ServerFeatures); return app;
}
}
OrchardCore自己也注释的很清楚:为当前路径启用多租户请求支持。网上很多都介绍OrchardCore是一个多租户的cms,那么什么是租户呢?我的理解就是像虚拟主机一类的东西。都知道Program的main方法就是构建一个kestrel主机运行起来(这里我直接当作iis运行起来,这样比较好理解),kestrel是一个很简陋的主机,很多功能都没有,比如像iis那样的服务器能创建虚拟主机它是没办法的,它只能提供一个主机服务,而多租户就是类似于iis上的虚拟主机了,也就是可以提供多个web站点服务。当然我表述比较土,换个角度,我们要开通web服务,就必须像服务商租用web主机,服务商有一台服务器,而我们只要开一个web服务,因此只要租用一个虚拟主机就够了而不用租用整台服务器,当然我们朋友要多开个web服务就可以多租一个虚拟主机就够了。OrchardCore就是web服务器,而我们可以开n个web服务,OrchardCore提供足够的虚拟主机给我们租用。也就是说每个租户都是独立不干扰的虚拟主机,各自提供自己的web服务。我语文比较差,大概就这么个意思。
开始看代码,前面这几行没啥好说的,看过asp.net core源码的都能直接跳过了!就是获取环境变量,初始化Web主机“ ContentRootFileProvider”。好像很难理解,其实就是指定租户的wwwroot文件夹。后面有空再追踪下这段,先跳过。
var env = app.ApplicationServices.GetRequiredService<IHostEnvironment>();
var appContext = app.ApplicationServices.GetRequiredService<IApplicationContext>(); env.ContentRootFileProvider = new CompositeFileProvider(
new ModuleEmbeddedFileProvider(appContext),
env.ContentRootFileProvider); // Init also the web host 'ContentRootFileProvider'.
app.ApplicationServices.GetRequiredService<IWebHostEnvironment>()
.ContentRootFileProvider = env.ContentRootFileProvider;
前面跳过是因为下面这几行才是整个OrchardCore的灵魂,先搞懂这几行,其它先旁支忽略吧
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>(app.ServerFeatures);
app.UseMiddleware多么熟悉的结构,就是加了三个中间件PoweredByMiddleware、ModularTenantContainerMiddleware和ModularTenantRouterMiddleware,从名称上已经可以大致明白他们的作用。分别是版权、模块化租户容器和模块化租户路由。
PoweredByMiddleware比较简单,基本点进去直接看源码就明白了。
/// <summary>
/// Adds the X-Powered-By header with values OrchardCore.
/// </summary>
public class PoweredByMiddleware
{
private readonly RequestDelegate _next;
private readonly IPoweredByMiddlewareOptions _options; public PoweredByMiddleware(RequestDelegate next, IPoweredByMiddlewareOptions options)
{
_next = next;
_options = options;
} public Task Invoke(HttpContext httpContext)
{
if (_options.Enabled)
{
httpContext.Response.Headers[_options.HeaderName] = _options.HeaderValue;
} return _next.Invoke(httpContext);
}
}
asp.net core中间件熟悉的界面,一个构造函数和一个Invoke(或者异步的InvokeAsync),options也是下面的接口和类直接注入。也就是把Headers[X-Powered-By]的值设置为“OrchardCore”写入上下文对象。
public interface IPoweredByMiddlewareOptions
{
bool Enabled { get; set; }
string HeaderName { get; }
string HeaderValue { get; set; }
} internal class PoweredByMiddlewareOptions : IPoweredByMiddlewareOptions
{
private const string PoweredByHeaderName = "X-Powered-By";
private const string PoweredByHeaderValue = "OrchardCore"; public string HeaderName => PoweredByHeaderName;
public string HeaderValue { get; set; } = PoweredByHeaderValue; public bool Enabled { get; set; } = true;
}
ModularTenantContainerMiddleware这个中间件就是整个OrchardCore所有能力的体现了。这个Invoke比PoweredByMiddleware的复杂多了,感觉拆开可以讲三天三夜,而且坑也很多(是我知识水平太低被坑,而不是说项目不好),下次就篇再分析吧,简单说就租户主机没创建的创建,没开启的启动,收到请求的如何处理请求等等。这个Shell我是翻译不出意思,直接理解成具体某一个吧,说错请纠正,这也是我发学习笔记的原因。
/// <summary>
/// This middleware replaces the default service provider by the one for the current tenant
/// </summary>
public class ModularTenantContainerMiddleware
{
private readonly RequestDelegate _next;
private readonly IShellHost _shellHost;
private readonly IRunningShellTable _runningShellTable; public ModularTenantContainerMiddleware(
RequestDelegate next,
IShellHost shellHost,
IRunningShellTable runningShellTable)
{
_next = next;
_shellHost = shellHost;
_runningShellTable = runningShellTable;
} public async Task Invoke(HttpContext httpContext)
{
// Ensure all ShellContext are loaded and available.
await _shellHost.InitializeAsync(); var shellSettings = _runningShellTable.Match(httpContext); // We only serve the next request if the tenant has been resolved.
if (shellSettings != null)
{
if (shellSettings.State == TenantState.Initializing)
{
httpContext.Response.Headers.Add(HeaderNames.RetryAfter, "");
httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
await httpContext.Response.WriteAsync("The requested tenant is currently initializing.");
return;
} // Makes 'RequestServices' aware of the current 'ShellScope'.
httpContext.UseShellScopeServices(); var shellScope = await _shellHost.GetScopeAsync(shellSettings); // Holds the 'ShellContext' for the full request.
httpContext.Features.Set(new ShellContextFeature
{
ShellContext = shellScope.ShellContext,
OriginalPath = httpContext.Request.Path,
OriginalPathBase = httpContext.Request.PathBase
}); await shellScope.UsingAsync(scope => _next.Invoke(httpContext));
}
}
最后ModularTenantRouterMiddleware这个中间件一看就跟路由有关,具体代码自己ctrl+鼠标左键点吧,简单的可以理解成asp.net core web应用程序或者asp.net core web api里的app.UseEndpoints,当然不是这么简单,毕竟是模块化,所以有个StartupBase的自定义类要理解下,这也是说OrchardCore的模块化多租户不是asp.net core的原因。开始接触我也想怎么有这么矛盾的事情,明明OrchardCore就是一个asp.net core的程序,怎么有很多观点说它只是类似于asp.net core而不是asp.net core呢?现在我才明白,没错,OrchardCore是asp.net core,但是他提供模块化多租户的形式并不是跟asp.net core一样(不然哪里来的多租户,废话)。这个后面有时间再说,下一篇笔记应该是开始读上面那个ModularTenantContainerMiddleware中间件了。
最新文章
- 使用KRPano资源分析工具解密被加密的XML
- Java实现emf图片自己留转png(jpg)图片字节流
- 把HBITMAP 保存图片文件.
- PHP内核研究(内存管理1)
- Vue基础---->;VueJS的使用(一)
- 弃用的异步get和post方法之代理方法
- C++纯虚函数
- TFS2012团队管理基本配置及基础使用方法
- Vim编辑器的常用快捷键.
- Angularjs Directive(指令)机制
- Guava快速入门
- 初探LaTeX
- HTTP 错误码
- svg中实现文字随曲线走向,HTML直接写和JavaScript创建对象两种方式
- Ubuntu 18.0.4安装Mongodb
- 查看Orcale数据里的表是否有变化
- Android Wifi 主动扫描 被动扫描
- java 网络编(二)UDP的传输
- macOS SIP 权限设置
- AndroidDriver原理初步--Android自动化测试学习历程