<深入理解Abp> 程式啟動 - 一切的開始

来源:https://www.cnblogs.com/realmaliming/archive/2018/12/04/10050018.html
-Advertisement-
Play Games

我們知道 應用程式的核心配置在項目中的 " " 文件. 方法主要用於將服務添加到 容器中並做一些配置. 配置請求管道. 框架使用自己的DI容器\(主要為了相容之前的NET Framework版本和使用一些高級特性,如攔截器\),所以我們在 方法的底部會看到 這時候 的方法返回值也變成了 \(關於這點 ...


我們知道NET Core應用程式的核心配置在項目中的Startup.cs 文件.

public class Startup
{
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        //...
        
        return services.AddAbp<WebModule>(//...);
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseAbp(//...);

        //...
    }
}
  • public void ConfigureServices(IServiceCollection services)方法主要用於將服務添加到DI容器中並做一些配置.
  • public void Configure(IApplicationBuilder app)配置請求管道.

Abp框架使用自己的DI容器(主要為了相容之前的NET Framework版本和使用一些高級特性,如攔截器),所以我們在ConfigureServices 方法的底部會看到return services.AddAbp(//...)這時候ConfigureServices的方法返回值也變成了IServiceProvider(關於這點請參考:預設服務容器替換)

框架與ASPNET Core深度集成的地方就在AddAbp方法和UseAbp的內部:

public static class AbpServiceCollectionExtensions
{
    /// <summary>
    /// Integrates ABP to AspNet Core.
    /// </summary>
    /// <typeparam name="TStartupModule">Startup module of the application which depends on other used modules. Should be derived from <see cref="AbpModule"/>.</typeparam>
    /// <param name="services">Services.</param>
    /// <param name="optionsAction">An action to get/modify options</param>
    public static IServiceProvider AddAbp<TStartupModule>(this IServiceCollection services, [CanBeNull] Action<AbpBootstrapperOptions> optionsAction = null)
        where TStartupModule : AbpModule
    {
        var abpBootstrapper = AddAbpBootstrapper<TStartupModule>(services, optionsAction);

        ConfigureAspNetCore(services, abpBootstrapper.IocManager);

        return WindsorRegistrationHelper.CreateServiceProvider(abpBootstrapper.IocManager.IocContainer, services);
    }

    private static void ConfigureAspNetCore(IServiceCollection services, IIocResolver iocResolver)
    {
        //See https://github.com/aspnet/Mvc/issues/3936 to know why we added these services.
        services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
        
        //Use DI to create controllers
        services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

        //Use DI to create view components
        services.Replace(ServiceDescriptor.Singleton<IViewComponentActivator, ServiceBasedViewComponentActivator>());

        //Change anti forgery filters (to work proper with non-browser clients)
        services.Replace(ServiceDescriptor.Transient<AutoValidateAntiforgeryTokenAuthorizationFilter, AbpAutoValidateAntiforgeryTokenAuthorizationFilter>());
        services.Replace(ServiceDescriptor.Transient<ValidateAntiforgeryTokenAuthorizationFilter, AbpValidateAntiforgeryTokenAuthorizationFilter>());

        //Add feature providers
        var partManager = services.GetSingletonServiceOrNull<ApplicationPartManager>();
        partManager?.FeatureProviders.Add(new AbpAppServiceControllerFeatureProvider(iocResolver));

        //Configure JSON serializer
        services.Configure<MvcJsonOptions>(jsonOptions =>
        {
            jsonOptions.SerializerSettings.ContractResolver = new AbpMvcContractResolver(iocResolver)
            {
                NamingStrategy = new CamelCaseNamingStrategy()
            };
        });

        //Configure MVC
        services.Configure<MvcOptions>(mvcOptions =>
        {
            mvcOptions.AddAbp(services);
        });

        //Configure Razor
        services.Insert(0,
            ServiceDescriptor.Singleton<IConfigureOptions<RazorViewEngineOptions>>(
                new ConfigureOptions<RazorViewEngineOptions>(
                    (options) =>
                    {
                        options.FileProviders.Add(new EmbeddedResourceViewFileProvider(iocResolver));
                    }
                )
            )
        );
    }

    private static AbpBootstrapper AddAbpBootstrapper<TStartupModule>(IServiceCollection services, Action<AbpBootstrapperOptions> optionsAction)
        where TStartupModule : AbpModule
    {
        var abpBootstrapper = AbpBootstrapper.Create<TStartupModule>(optionsAction);
        services.AddSingleton(abpBootstrapper);
        return abpBootstrapper;
    }
}

AbpBootstrapper作為Abp核心的引導類,負責初始化Abp系統,載入插件,配置Abp和模塊以及啟動模塊(PreInitialize,Initialize, PostInitialize). 這個引導類在console應用程式中同樣可以啟動Abp系統.

接下來Abp配置和替換了多個MVC的組件,如IControllerActivator,IViewComponentActivator,MvcJsonOptions,MvcOptions更多的配置在mvcOptions.AddAbp(services)方法下:

internal static class 

{
    public static void AddAbp(this MvcOptions options, IServiceCollection services)
    {
        AddConventions(options, services);
        AddFilters(options);
        AddModelBinders(options);
    }

    private static void AddConventions(MvcOptions options, IServiceCollection services)
    {
        options.Conventions.Add(new AbpAppServiceConvention(services));
    }

    private static void AddFilters(MvcOptions options)
    {
        options.Filters.AddService(typeof(AbpAuthorizationFilter));
        options.Filters.AddService(typeof(AbpAuditActionFilter));
        options.Filters.AddService(typeof(AbpValidationActionFilter));
        options.Filters.AddService(typeof(AbpUowActionFilter));
        options.Filters.AddService(typeof(AbpExceptionFilter));
        options.Filters.AddService(typeof(AbpResultFilter));
    }

    private static void AddModelBinders(MvcOptions options)
    {
        options.ModelBinderProviders.Insert(0, new AbpDateTimeModelBinderProvider());
    }
}

AbpAppServiceConvention 主要用於配置動態API,這個後面會有一章單獨說明.

AbpAuthorizationFilter
AbpAuditActionFilter
AbpValidationActionFilter
AbpUowActionFilter
AbpExceptionFilter
AbpResultFilter

依次添加6個MVC過濾器分別實現授權,審計,參數驗證,工作單元,異常處理以及返回內容的包裝.(請註意過濾器順序很重要)

AbpDateTimeModelBinderProvider 用作DateTime的統一時區處理.

接下來我們再看UseAbp方法:

public static class AbpApplicationBuilderExtensions
{
    public static void UseAbp(this IApplicationBuilder app)
    {
        app.UseAbp(null);
    }

    public static void UseAbp([NotNull] this IApplicationBuilder app, Action<AbpApplicationBuilderOptions> optionsAction)
    {
        Check.NotNull(app, nameof(app));

        var options = new AbpApplicationBuilderOptions();
        optionsAction?.Invoke(options);

        if (options.UseCastleLoggerFactory)
        {
            app.UseCastleLoggerFactory();
        }

        InitializeAbp(app);

        if (options.UseAbpRequestLocalization)
        {
            //TODO: This should be added later than authorization middleware!
            app.UseAbpRequestLocalization();
        }

        if (options.UseSecurityHeaders)
        {
            app.UseAbpSecurityHeaders();
        }
    }

    public static void UseEmbeddedFiles(this IApplicationBuilder app)
    {
        app.UseStaticFiles(
            new StaticFileOptions
            {
                FileProvider = new EmbeddedResourceFileProvider(
                    app.ApplicationServices.GetRequiredService<IIocResolver>()
                )
            }
        );
    }

    private static void InitializeAbp(IApplicationBuilder app)
    {
        var abpBootstrapper = app.ApplicationServices.GetRequiredService<AbpBootstrapper>();
        abpBootstrapper.Initialize();

        var applicationLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
        applicationLifetime.ApplicationStopping.Register(() => abpBootstrapper.Dispose());
    }

    public static void UseCastleLoggerFactory(this IApplicationBuilder app)
    {
        var castleLoggerFactory = app.ApplicationServices.GetService<Castle.Core.Logging.ILoggerFactory>();
        if (castleLoggerFactory == null)
        {
            return;
        }

        app.ApplicationServices
            .GetRequiredService<ILoggerFactory>()
            .AddCastleLogger(castleLoggerFactory);
    }

    public static void UseAbpRequestLocalization(this IApplicationBuilder app, Action<RequestLocalizationOptions> optionsAction = null)
    {
        var iocResolver = app.ApplicationServices.GetRequiredService<IIocResolver>();
        using (var languageManager = iocResolver.ResolveAsDisposable<ILanguageManager>())
        {
            var supportedCultures = languageManager.Object
                .GetLanguages()
                .Select(l => CultureInfo.GetCultureInfo(l.Name))
                .ToArray();

            var options = new RequestLocalizationOptions
            {
                SupportedCultures = supportedCultures,
                SupportedUICultures = supportedCultures
            };

            var userProvider = new AbpUserRequestCultureProvider();

            //0: QueryStringRequestCultureProvider
            options.RequestCultureProviders.Insert(1, userProvider);
            options.RequestCultureProviders.Insert(2, new AbpLocalizationHeaderRequestCultureProvider());
            //3: CookieRequestCultureProvider
            options.RequestCultureProviders.Insert(4, new AbpDefaultRequestCultureProvider());
            //5: AcceptLanguageHeaderRequestCultureProvider

            optionsAction?.Invoke(options);

            userProvider.CookieProvider = options.RequestCultureProviders.OfType<CookieRequestCultureProvider>().FirstOrDefault();
            userProvider.HeaderProvider = options.RequestCultureProviders.OfType<AbpLocalizationHeaderRequestCultureProvider>().FirstOrDefault();

            app.UseRequestLocalization(options);
        }
    }

    public static void UseAbpSecurityHeaders(this IApplicationBuilder app)
    {
        app.UseMiddleware<AbpSecurityHeadersMiddleware>();
    }
}

核心InitializeAbp(app),使用上文之前提到AbpBootstrapper引導啟動Abp系統.(我們知道Abp模塊有個Shutdown()方法,Abp使用IApplicationLifetime介面捕獲應用程式事件實現模塊的Shoutdown)

之後按需啟動幾個中間件,如: RequestLocalization,SecurityHeaders等(這些小組件和之前的過濾器後面我會分別詳細介紹,這裡就不深入講解)

至此Abp已經把框架的相關組件集成到了MVC中.接下來程式啟動.請求被各種中間件處理(MVC中間件會調用過濾器).

Abp中文網:https://cn.abp.io/
Abp交流群:735901849(純技術交流,無廣告,不賣課)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • wpf 的依賴屬性只能在loaded 事件之後才能取到,在構造函數的 InitializeComponent(); 之後取不到 wpf 的依賴屬性只能在loaded 事件之後才能取到,在構造函數的 InitializeComponent(); 之後取不到 wpf 的依賴屬性只能在loaded 事件之 ...
  • 調用 var reuslt = await _stTrendController.InitalrenderSourceandBrush2((int)firstrowgrid.ActualWidth - 27); ...
  • 一、下載Windows版本Redis 下載鏈接:https://github.com/MSOpenTech/redis/releases(根據系統選擇對應版本) 二、修改預設的配置文件 如上圖兩個配置文件,redis.windows.conf(應用程式配置文件);redis.windows-serv ...
  • 文本框增加驗證選項卡 列表複雜查詢,支持文本框,時間,下拉(如:客戶總表) ...
  • 獲取日期枚舉,可以根據switch去進行操作 ...
  • npoi完整代碼:NET npoi幫助類 ...
  • 本文純乾貨,直接拿走使用,不用付費。在業務開發中,手機號碼驗證是我們常常需要面對的問題,目前市場上各種各樣的手機號碼驗證方式,比如正則表達式等等,本文結合實際業務場景,在業務級別對手機號碼進行嚴格驗證;同時增加可配置方式,方便業務擴展,代碼非常簡單,擴展非常靈活。 ...
  • 1、變數的基本概念 變數是指用來存儲特定類型的數據,可以根據需要隨時改變變數中所存儲的數據值。變數具有名稱、類型和值,因此使用變數之前必須先聲明變數,即指定變數的類型和名稱。 2、變數類型 變數類型根據其定義可以分為兩種:一種是值類型,另一種是引用類型。這兩種變數類型的區別在於數據的存儲方式,值類型 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...