<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          探索 ABP 基礎架構

          共 8448字,需瀏覽 17分鐘

           ·

          2022-05-24 18:02

          前言

          為了了解應用程序是如何配置和初始化,本文將探討ASP.NET Core和ABP框架最基本的構建模塊。我們將從 ASP.NET Core 的?Startup類開始了解為什么我們需要模塊化系統(tǒng),以及 ABP 如何提供模塊化方式來配置和初始化應用程序。

          然后我們將探索 ASP.NET Core 的依賴注入,以及ABP是如何使用預定義規(guī)則(predefined rules)自動進行依賴注入。

          最后,我們將了解 ASP.NET Core 的配置和選項框架,以及其他類庫。

          以下是本文的所有主題:

          • 了解模塊化
          • 使用依賴注入系統(tǒng)
          • 配置應用程序
          • 實現(xiàn)選項模式
          • 日志系統(tǒng)

          一、了解模塊化

          模塊化是一種將大型軟件按功能分解為更小的部分,并允許每個部分通過標準化接口進行通信。模塊化有以下主要好處:

          • 模塊按規(guī)則進行隔離后,大大降低了系統(tǒng)復雜性。
          • 模塊之間松散耦合,提供了更大的靈活性。因為模塊是可組裝、可替換的。
          • 因為模塊是獨立的,所以它允許跨應用被重用。

          大多數(shù)企業(yè)的軟件被設計成模塊化,但是,實現(xiàn)模塊化并不容易。ABP 框架的主要目標之一是為模塊化提供基礎設施和工具。我們將在后面詳細介紹模塊化開發(fā),本節(jié)只介紹 ABP 模塊的基礎知識。

          Startup 類

          在定義ABP的模塊之前,建議先熟悉 ASP.NET Core 中的StartUp類,我們看下ASP.NET Core 的Startup類:

          public class Startup
          {
          public void ConfigureServices(IServiceCollection services)
          {
          services.AddMvc();
          services.AddTransient();
          }
          public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
          {
          app.UseRouting();
          if (env.IsDevelopment())
          {
          app.UseDeveloperExceptionPage();
          }
          app.UseEndpoints(endpoints =>
          {
          endpoints.MapControllers();
          });
          }
          }

          ConfigureServices方法用于配置服務并將新服務注冊到依賴注入系統(tǒng)。另一方面,Configure方法用于配置 ASP.NET Core 管道中間件,用于處理 HTTP 請求。在應用程序啟動之前,我們需要在Program.cs中配置Startup類:

          public?class?Program
          {
          ????public?static?void?Main(string[]?args)
          ????{
          ????????CreateHostBuilder(args).Build().Run();
          ????}
          ????public?static?IHostBuilder?CreateHostBuilder(string[]?args)?=>
          ????????Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder?=>
          ????????????{
          ????????????????webBuilder.UseStartup();
          ????????????});
          }

          這個Startup類是獨一無二的,我們只有一個點來配置和初始化所有的服務。但是,在模塊化應用程序中,我們希望每個模塊都能獨立配置和初始化與該模塊相關的服務。此外,一個模塊通常需要使用或依賴于其他模塊,因此模塊配置順序和初始化就非常重要了。我們來看下 ABP 的模塊是如何定義的

          模塊定義

          ABP 模塊是一組類型(比如類或接口),它們一同開發(fā)一同交付的。它是一個程序集(一般來說是Visual Studio 中的一個項目),派生自AbpModule,模塊類負責配置和初始化,并在必要時配置依賴模塊。

          下面是一個短信發(fā)送模塊的簡單定義:

          using?Microsoft.Extensions.DependencyInjection;
          using?Volo.Abp.Modularity;
          namespace?SmsSending
          {
          ????public?class?SmsSendingModule?:?AbpModule?
          ????{
          ????????public?override?void?ConfigureServices(
          ServiceConfigurationContext?context)

          ????????
          {
          ????????????context.Services.AddTransient();
          ????????}
          ????}
          }

          每個模塊都可以重寫ConfigureServices方法,以便將其服務注冊到依賴注入系統(tǒng)。此示例中的SmsService服務被注冊為瞬態(tài)生命周期。該示例和上面Startup類似。但是,大多時候,您不需要手動注冊服務,這要歸功ABP 框架的按約定注冊系統(tǒng)。

          OnApplicationInitialization方法用在服務注冊完成后,并且在應用準備就緒后執(zhí)行。使用此方法,您可以在應用啟動時執(zhí)行任何操作。例如,您可以初始化一個服務:

          public?class?SmsSendingModule?:?AbpModule?
          {
          ????//...
          ????public?override?void?OnApplicationInitialization(ApplicationInitializationContext?context)
          ????{
          ????????var?service?=?context.ServiceProvider.GetRequiredService();
          ????????service.Initialize();
          ????}
          }

          這里,我們使用context.ServiceProvider從依賴注入系統(tǒng)請求并初始化服務??梢姡藭r服務已經(jīng)完成注冊。

          您也可以將OnApplicationInitialization方法等同于Startup類的Configure方法。

          您可以在此處構建 ASP.NET Core 請求管道。但是,通常我們會在啟動模塊中配置請求管道,如下一節(jié)所述。

          模塊依賴和啟動模塊

          一個業(yè)務應用通常由多個模塊組成,ABP 框架允許您聲明模塊之間的依賴關系。一個應用必須要有一個啟動模塊。啟動模塊可以依賴于其他模塊,其他模塊可以再依賴于其他模塊,以此類推。

          下圖是一個簡單的模塊依賴關系圖:

          如果所示,如果模塊 A 依賴于模塊 B,則模塊 B 總是在模塊 A 之前初始化。這允許模塊 A 使用、設置、更改或覆蓋模塊 B 定義的配置和服務。

          對于示例圖,模塊初始化的順序應該是:G、F、E、D、B、C、A。

          您不必知道確切的初始化順序;只需要知道如果你的模塊依賴于模塊xx,那么模塊xx在你的模塊之前被初始化。

          ABP使用[DependsOn](屬性聲明)方式來定義模塊依賴:

          [DependsOn(typeof(ModuleB), typeof(ModuleC))]
          public class ModuleA : AbpModule
          {
          }

          這里,ModuleA通過[DependsOn]依賴于ModuleBModuleC。本例中,啟動模塊ModuleA負責設置ASP.NET?Core 的請求管道:

          [DependsOn(typeof(ModuleB),?typeof(ModuleC))]
          public?class?ModuleA?:?AbpModule
          {
          ????//...
          ????public?override?void?OnApplicationInitialization(ApplicationInitializationContext?context)
          ????{
          ????????var?app?=?context.GetApplicationBuilder();
          ????????var?env?=?context.GetEnvironment();
          ????????
          ????????app.UseRouting();
          ????????if?(env.IsDevelopment())
          ????????{
          ????????????app.UseDeveloperExceptionPage();
          ????????}
          ????????app.UseEndpoints(endpoints?=>
          ????????{
          ????????????endpoints.MapControllers();
          ????????});
          ????}
          }

          [代碼塊和之前ASP.NET Core的?Startup類?創(chuàng)建請求管道相同。context.GetApplicationBuilder()context.GetEnvironment()用于從依賴注入中獲IApplicationBuilderIWebHostEnvironment服務。

          最后,我們在Startup里將ASP.NET Core 和 ABP 框架進行集成:

          public?class?Startup
          {

          ????public?void?ConfigureServices(IServiceCollection?services)
          ????
          {
          ????????services.AddApplication();
          ????}
          ????public?void?Configure(IApplicationBuilder?app)
          ????
          {
          ????????app.InitializeApplication();
          ????}
          }

          services.AddApplication()方法由 ABP 框架定義,用于ABP的模塊配置。它按順序執(zhí)行了所有模塊的ConfigureServices方法。而app.InitializeApplication()方法也是由 ABP 框架定義,它也是按照模塊依賴的順序來執(zhí)行所有模塊的OnApplicationInitialization方法。

          ConfigureServicesOnApplicationInitialization方法是模塊類中最常用的方法。

          模塊生命周期

          AbpModule中定義的生命周期方法,除了上面看到的ConfigureServicesOnApplicationInitialization,下面羅列其他生命周期相關方法:

          • PreConfigureServices: 這個方法在ConfigureServices方法之前被調(diào)用。它允許您配置服務之前執(zhí)行的代碼。
          • ConfigureServices:這是配置模塊和注冊服務的主要方法。
          • PostConfigureServices: 該方法在ConfigureServices之后調(diào)用(包括依賴于您模塊的模塊),這里可以配置服務后執(zhí)行的代碼。
          • OnPreApplicationInitialization: 這個方法在OnApplicationInitialization之前被調(diào)用。在這個階段,您可以從依賴注入中解析服務,因為服務已經(jīng)被初始化。
          • OnApplicationInitialization:此方法用來配置 ASP.NET Core 請求管道并初始化您的服務。
          • OnPostApplicationInitialization: 這個方法在初始化階段后被調(diào)用。
          • OnApplicationShutdown:您可以根據(jù)需要自己實現(xiàn)模塊的關閉邏輯。帶Pre…Post…前綴的方法與原始方法具有相同的目的。它們提供了一種在模塊之前或之后執(zhí)行的一些配置/初始化代碼,一般情況下我們很少使用到。

          異步生命周期方法

          本節(jié)介紹的生命周期方法是同步的。在編寫本書時,ABP 框架團隊正努力在 框架 5.1 版本引入異步生命周期方法。

          如前所述,模塊類主要包含注冊和配置與該模塊相關的服務的代碼。在下一節(jié)中,我們將介紹如何使用 ABP 框架注冊服務。

          二、使用依賴注入系統(tǒng)


          .NET 原生依賴注入

          依賴注入是一種獲取類的依賴的技術,它將創(chuàng)建類與使用該類分開。

          假設我們有一個UserRegistrationService類,它調(diào)用SmsService類來發(fā)送驗證短信,如下:

          public?class?UserRegistrationService
          {
          ????private?readonly?SmsService?_smsService;
          ????public?UserRegistrationService(SmsService?smsService)
          ????{
          ????????_smsService?=?smsService;
          ????}
          ????public?async?Task?RegisterAsync(
          ????????string?username,
          ????????string?password,
          ????????string?phoneNumber
          )

          ????{
          ????????//...save?user?in?the?database
          ????????await?_smsService.SendAsync(
          ????????????phoneNumber,
          ????????????"Your?verification?code:?1234"
          ????????);
          ????}
          }

          這里的SmsService使用構造函數(shù)注入來獲取實例。也就是說,依賴注入系統(tǒng)會自動幫我們實例化類的依賴項,并將它們賦值給我們的_smsService。

          注意:ABP采用的是ASP.NET Core原生的依賴注入框架,他自己并沒有發(fā)明依賴注入框架。

          在設計服務時,我們還要考慮另外一件重要的事情:服務生命周期。ASP.NET Core 為服務注冊提供了三個生命周期選項:

          • Transient(瞬態(tài)):每次您請求/注入服務時,都會創(chuàng)建一個新實例。
          • Scoped(范圍): 通常這由請求生命周期來評估,您只有在同一范圍內(nèi)才能共享相同的實例。
          • Singleton(單例):在應用內(nèi)有且僅有一個實例。所有請求都使用相同的實例。該對象在第一次請求創(chuàng)建。以下模塊注冊了兩個服務,一個是瞬態(tài)的,另一個是單例的:
          public?class?MyModule?:?AbpModule
          {
          ????public?override?void?ConfigureServices(ServiceConfigurationContext?context)
          ????
          {
          ????????context.Services.AddTransient();
          ????????context.Services.AddSingleton();
          ????}
          }

          context.Services的類型是IServiceCollection,它是一個擴展方法。

          在第一個示例中使用接口注冊,第二個示例使用引用類注冊為單例。

          ABP的依賴注入

          使用 ABP 框架時,您不必考慮服務注冊,這要歸功于 ABP 框架獨特的服務注冊系統(tǒng)。

          1、約定式注冊

          在 ASP.NET Core 中,所有服務需要顯式注冊到IServiceCollection,如上一節(jié)所示。這些注冊大多重復,完全可以自動化操作。

          ABP 對于以下類型采用自動注冊:

          • MVC controllers
          • Razor page models
          • View components
          • Razor components
          • SignalR hubs
          • Application services
          • Domain services
          • Repositories 以上類型均使用瞬態(tài)生命周期自動注冊。如果您還有別的類型,可以考慮接口注冊。

          2、接口注冊

          您可以實現(xiàn)以下三種接口來注冊:

          • ITransientDependency
          • IScopedDependency
          • ISingletonDependency

          例如,在下面代碼塊中,我們將服務注冊為單例:

          public?class?UserPermissionCache?:?ISingletonDependency
          {?}

          接口注冊很容易并且是推薦的方式,但與下面的屬性注冊相比,它有一定的局限性。

          3、屬性注冊

          屬性注冊更精細,下面是和屬性注冊相關的配置參數(shù)

          • Lifetime(enum): 服務的生命周期,包括Singleton,TransientScoped
          • TryRegister(bool):僅當服務尚未注冊時才注冊
          • ReplaceServices(bool):如果服務已經(jīng)注冊,則替換之前的注冊

          示例代碼:

          using?Microsoft.Extensions.DependencyInjection;
          using?Volo.Abp.DependencyInjection;
          namespace?UserManagement
          {
          ????[Dependency(ServiceLifetime.Transient,?TryRegister?=?true)]
          ????public?class?UserPermissionCache
          ????{
          ?}
          }

          4、接口屬性混合注冊

          屬性接口一起使用。如果屬性定義了屬性,屬性比接口優(yōu)先級更高。

          如果一個類可能被注入不同的類或接口,具體取決于暴露的類型。

          暴露服務

          當一個類沒有實現(xiàn)接口時,只能通過類引用注入。上一節(jié)中的UserPermissionCache類就是通過注入類引用來使用的。

          假設我們有一個抽象 SMS 發(fā)送的接口:

          public?interface?ISmsService
          {
          ????Task?SendAsync(string?phoneNumber,?string?message);
          }

          假設您要ISmsService實現(xiàn) Azure 服務:

          public?class?AzureSmsService?:?ISmsService,?ITransientDependency
          {
          ????public?async?Task?SendAsync(string?phoneNumber,?string?message)
          ????{
          ????????//TODO:?...
          ????}
          }

          這里的AzureSmsService實現(xiàn)了ISmsServiceITransientDependency兩個接口。而ITransientDependency接口才是用于自動注冊到依賴注入中的。這里的注入主要通過命名約定來實現(xiàn),因為AzureSmsServiceSmsService作為后綴結尾。我們再舉一個通過命名約定的例子,假設我們有一個實現(xiàn)多個接口的類:

          public?class?PdfExporter:?IExporter,?IPdfExporter,?ICanExport,?ITransientDependency
          {?}

          PdfExporter服務可以通過注入IPdfExporterIExporter接口來使用,也可以直接注入PdfExporter類引用來使用。但是,您不能使用ICanExport接口注入它,因為名稱PdfExporter不以CanExport為后綴。

          一旦您使用該ExposeServices屬性來暴露服務,如以下代碼塊所示:

          [ExposeServices(typeof(IPdfExporter))]
          public?class?PdfExporter:?IExporter,?IPdfExporter,?ICanExport,?ITransientDependency
          {?}

          現(xiàn)在,您只能通過注入IPdfExporter接口來使用PdfExporter類。

          我應該為每個服務定義接口嗎?

          ABP 不會強迫你這么做,但是通用接口來定義是最佳實踐:如果你想松散地耦合你的服務。比如,在單元測試中可以輕松模擬測試數(shù)據(jù)。

          這就是為什么我們將接口與實現(xiàn)物理分離(例如,我們在項目中定義Application.Contracts接口,并在Application項目中實現(xiàn)它們,或者在領域?qū)又卸x存儲庫接口,在基礎設施層中實現(xiàn)它們)。

          我們已經(jīng)了解了如何注冊和消費服務。另外,某些服務具有選項配置,您需要在使用它們之前對其進行配置。接下來的兩節(jié)將展開介紹。

          待續(xù)

          文章有點長,下篇將繼續(xù)介紹ABP的配置和選項模式,感謝你的閱讀。


          轉(zhuǎn)自:張飛洪[廈門]

          鏈接:cnblogs.com/jackyfei/p/16272230.html


          瀏覽 38
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产视频在线一区 | 91久久久精品 | 超碰91大香蕉 | 鸡巴操骚逼视频 | 亚洲高清五码视频 |