(二)學習了解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, "10");
                    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中間件了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM