ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)第三節(jié)--abp分層體系及ABP模塊系統(tǒng)

ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS
前往博客園總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期

說(shuō)了這么久,還沒(méi)有詳細(xì)說(shuō)到abp框架,abp其實(shí)基于DDD(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))原則的細(xì)看分層如下:



再看我們項(xiàng)目解決方案如下:


  • 應(yīng)用層(Application):應(yīng)用層:進(jìn)行展現(xiàn)層與領(lǐng)域?qū)又g的協(xié)調(diào),協(xié)調(diào)業(yè)務(wù)對(duì)象來(lái)執(zhí)行特定的應(yīng)用程序的任務(wù)。它不包含業(yè)務(wù)邏輯,主要包含一些模型,abp重要的數(shù)據(jù)傳輸DTO,包括數(shù)據(jù)庫(kù)映射實(shí)體,前端視圖模型轉(zhuǎn)實(shí)體(Entity)對(duì)象,一個(gè)應(yīng)用服務(wù)方法通常被認(rèn)為是一個(gè)工作單元(Unit of Work),使用一種像AutoMapper這樣的工具來(lái)進(jìn)行實(shí)體與DTO之間的映射,前端參數(shù)傳入有限性驗(yàn)證等等
  • 領(lǐng)域?qū)?Domain):領(lǐng)域?qū)?領(lǐng)域?qū)泳褪菢I(yè)務(wù)層,是一個(gè)項(xiàng)目的核心,所有業(yè)務(wù)規(guī)則都應(yīng)該在領(lǐng)域?qū)訉?shí)現(xiàn)。包括業(yè)務(wù)對(duì)象和業(yè)務(wù)規(guī)則,這是應(yīng)用程序的核心層。
  • 實(shí)體(Entity):實(shí)體代表業(yè)務(wù)領(lǐng)域的數(shù)據(jù)和操作,在實(shí)踐中,通過(guò)用來(lái)映射成數(shù)據(jù)庫(kù)表。
  • 倉(cāng)儲(chǔ)(Repository):倉(cāng)儲(chǔ)用來(lái)操作數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)存取。倉(cāng)儲(chǔ)接口在領(lǐng)域?qū)佣x,而倉(cāng)儲(chǔ)的實(shí)現(xiàn)類應(yīng)該寫(xiě)在基礎(chǔ)設(shè)施層。
  • 領(lǐng)域服務(wù)(Domain service):當(dāng)處理的業(yè)務(wù)規(guī)則跨越兩個(gè)(及以上)實(shí)體時(shí),應(yīng)該寫(xiě)在領(lǐng)域服務(wù)方法里面。
  • 領(lǐng)域事件(Domain Event): 在領(lǐng)域?qū)幽承┨囟ㄇ闆r發(fā)生時(shí)可以觸發(fā)領(lǐng)域事件,并且在相應(yīng)地方捕獲并處理它們。
  • 工作單元(Unit of Work)工作單元是一種設(shè)計(jì)模式,用于維護(hù)一個(gè)由已經(jīng)被修改(如增加、刪除和更新等)的業(yè)務(wù)對(duì)象組成的列表。它負(fù)責(zé)協(xié)調(diào)這些業(yè)務(wù)對(duì)象的持久化工作及并發(fā)問(wèn)題。****
  • 基礎(chǔ)設(shè)施層(Infrastructure):基礎(chǔ)設(shè)施層:提供通用技術(shù)來(lái)支持更高的層。例如基礎(chǔ)設(shè)施層的倉(cāng)儲(chǔ)(Repository)可通過(guò)ORM來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)交互。當(dāng)在領(lǐng)域?qū)又袨槎x了倉(cāng)儲(chǔ)接口,應(yīng)該在基礎(chǔ)設(shè)施層中實(shí)現(xiàn)這些接口??梢允褂肙RM工具,例如EntityFramework或NHibernate。ABP的基類已經(jīng)提供了對(duì)這兩種ORM工具的支持。還有數(shù)據(jù)遷移等。
  • 展現(xiàn)層(Presentation):**展現(xiàn)層:提供試圖用于與用戶實(shí)現(xiàn)交互操作.
  • JCmsErp.WebApi:這里在abp中主要是提供接口,可以是解決方案內(nèi)部使用接口,可以是與移動(dòng)端等其他端口連接的接口.

二,實(shí)體(Entity)
實(shí)體是DDD(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì))的核心概念之一。Eirc Evans是這樣描述的實(shí)體的:“它根本上不是通過(guò)屬性定義的,而是通過(guò)一系列連續(xù)性和標(biāo)識(shí)定義的”。因此,實(shí)體都有Id屬性并且都存儲(chǔ)到數(shù)據(jù)庫(kù)中。一個(gè)實(shí)體一般會(huì)映射到數(shù)據(jù)庫(kù)的一張表
abp中實(shí)體是派生于Entity類,先看一下我們?cè)?strong>Core層新建的Users類

  • Users實(shí)體類,有人說(shuō)這個(gè)實(shí)體為什么沒(méi)有id,因?yàn)閁sers繼承自Entity類,Entity類已經(jīng)定義id,
    它是該Entity類的 主鍵。因此,所有實(shí)體的主鍵名都是相同的,都是Id。
  • Id(主鍵)的類型是可以改變的,默認(rèn)是int(int32)的。如果你想將Id定義為其他類型,可以在<>內(nèi)寫(xiě),比如Guid,long也是可以的。
    Entity類重寫(xiě)了等號(hào)運(yùn)算符(==),可以輕松地檢查兩個(gè)實(shí)體是否相同了(實(shí)體的Id相同則認(rèn)為它們相同)。它也定義了IsTransient方法來(lái)檢測(cè)它是否有Id。

審計(jì):

  • IHasCreationTime使得使用一個(gè)通用的屬性來(lái)描述一個(gè)實(shí)體的“創(chuàng)建時(shí)間”信息成為可能。當(dāng)實(shí)現(xiàn)了該接口的實(shí)體類插入到數(shù)據(jù)庫(kù)中時(shí),ABP會(huì)自動(dòng)地將當(dāng)前的時(shí)間設(shè)置給CreationTime。
  • ICreationAudited增加了CreatorUserId擴(kuò)展了IHasCreationTime,當(dāng)用戶保存一個(gè)新的實(shí)體的時(shí)候,會(huì)自動(dòng)把當(dāng)前的id設(shè)置為CreatorUserId,還有類似的LastModificationTime也是一樣。

當(dāng)更新實(shí)體時(shí),abp會(huì)自動(dòng)為你設(shè)置這些屬性。
軟刪除
軟刪除是將一個(gè)實(shí)體標(biāo)記為已刪除的通常使用的模式,而不是直接從數(shù)據(jù)庫(kù)中刪除。比如,你可能不想從數(shù)據(jù)庫(kù)中硬刪除一個(gè)User,因?yàn)樗赡荜P(guān)聯(lián)其他的表
ABP實(shí)現(xiàn)了開(kāi)箱即用的軟刪除模式。當(dāng)一個(gè)軟刪除實(shí)體被刪除后,ABP檢測(cè)到之后,會(huì)阻止刪除,將IsDeleted設(shè)置為true并更新數(shù)據(jù)庫(kù)中的實(shí)體。而且,它會(huì)自動(dòng)地過(guò)濾數(shù)據(jù)庫(kù)中軟刪除的實(shí)體,不會(huì)檢索(select)它們。
如果使用了軟刪除,那么你可能想存儲(chǔ)一些信息,比如何時(shí)刪除以及誰(shuí)刪除了一個(gè)實(shí)體等等


在JCmsErp.Application創(chuàng)建一個(gè)Users文件夾,然后創(chuàng)建UserinfoDto,DTO是用于Core和 Web間的數(shù)據(jù)傳輸對(duì)象.有了實(shí)體了為什么還要DTO呢

  1. DTO保證了層與層的分離,web層改變不影響core層,core做改變也不影響web.
  2. 數(shù)據(jù)保護(hù),不然敏感或者不需要的數(shù)據(jù)暴露于web層,不被別人窺見(jiàn)如密碼,銀行賬號(hào),身份證等敏感信息
  3. 序列化,序列化集合,但是子集不序列化,當(dāng)首次用到子集的時(shí)候才序列化.
  4. 惰性加載
  5. DTO數(shù)據(jù)驗(yàn)證
  6. abp還有一些擴(kuò)展的接口,擴(kuò)展性好,降低耦合度,使表現(xiàn)層和邏輯層之間耦合度降低.

這里Serializable就是支持序列化的標(biāo)簽, [AutoMapFrom(typeof(Users))]是指和Users之間雙向自動(dòng)轉(zhuǎn)化的標(biāo)簽,并不需要每個(gè)字段都去手動(dòng)匹配.ABP提供了若干特性和擴(kuò)展方法來(lái)定義映射。首先,要將Abp.AutoMapper nuget包添加到項(xiàng)目中。然后,AutoMap特性是雙向映射方式, AutoMapFromAutoMapTo是單向映射方式。最后,使用MapTo擴(kuò)展方法將一個(gè)對(duì)象映射到另一個(gè)對(duì)象

ABP模塊系統(tǒng)簡(jiǎn)介

ABP框架提供了創(chuàng)建和組裝模塊的基礎(chǔ),一個(gè)模塊能夠依賴于另一個(gè)模塊。在通常情況下,一個(gè)程序集就可以看成是一個(gè)模塊。在ABP框架中,一個(gè)模塊通過(guò)一個(gè)類來(lái)定義,而這個(gè)類要繼承自AbpModule。

模塊系統(tǒng)當(dāng)前專注于服務(wù)端而不是客戶端。

譯者注:
如果學(xué)習(xí)過(guò)Orchard的朋友,應(yīng)該知道m(xù)odule模塊的強(qiáng)大了。模塊的本質(zhì)就是可重用性,你可以在任意的地方去調(diào)用,而且通過(guò)實(shí)現(xiàn)模塊,你寫(xiě)的模塊也可以給別人用。.net可以通過(guò)反射獲取一個(gè)程序集中的類以及方法。

1.3.2 定義模塊

Assembly程序集:Assembly是一個(gè)用來(lái)包含程序的名稱,版本號(hào),自我描述,文件關(guān)聯(lián)關(guān)系和文件位置等信息的一個(gè)集合。最簡(jiǎn)單的理解就是:一個(gè)你自己寫(xiě)的類庫(kù)生成的dll就可以看做是一個(gè)程序集,這個(gè)程序集可以包括很多類,類又包括很多方法等。

一個(gè)派生自 AbpModule 的類就是模塊的定義。我們正在開(kāi)發(fā)一個(gè)博客模塊,該模塊可以被使用在不同的應(yīng)用程序中。最簡(jiǎn)單的模塊定義示例如下:

public class MyBlogApplicationModule : AbpModule //定義
{
    public override void Initialize() //初始化
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
        //這行代碼的寫(xiě)法基本上是不變的。它的作用是把當(dāng)前程序集的特定類或接口注冊(cè)到依賴注入容器中。
    }
}

如果需要的話,模塊類負(fù)責(zé)類的依賴注入(通常可以像上面一樣做)。我們能配置應(yīng)用程序和其它模塊,添加新的功能到應(yīng)用程序等等。

1.3.3 方法的生命周期

在一個(gè)應(yīng)用中,ABP框架調(diào)用了Module模塊的一些指定的方法來(lái)進(jìn)行啟動(dòng)和關(guān)閉模塊的操作。我們可以重載這些方法來(lái)完成我們自己的任務(wù)。

ABP框架通過(guò)依賴關(guān)系的順序來(lái)調(diào)用這些方法,假如:模塊A依賴于模塊B,那么模塊B要在模塊A之前初始化,模塊啟動(dòng)的方法順序如下:

  1. PreInitialize-B
  • PreInitialize-A
  • Initialize-B
  • Initialize-A
  • PostInitialize-B
  • PostInitialize-A

下面是具體方法的說(shuō)明:

PreInitialize

預(yù)初始化:當(dāng)應(yīng)用啟動(dòng)后,第一次運(yùn)行會(huì)先調(diào)用這個(gè)方法。在初始化(Initialize)方法調(diào)用之前,該方法通常是用來(lái)配置框架以及其它模塊。

在依賴注入注冊(cè)之前,你可以在這個(gè)方法中指定你需要注入的自定義啟動(dòng)類。例如:加入你創(chuàng)建了某個(gè)符合約定的注冊(cè)類,你應(yīng)該使用 IocManager.AddConventionalRegisterer 方法在這里注冊(cè)它。

Initialize

初始化:在這個(gè)方法中一般是來(lái)進(jìn)行依賴注入的注冊(cè),一般我們通過(guò)IocManager.RegisterAssemblyByConvention這個(gè)方法來(lái)實(shí)現(xiàn)。如果你想實(shí)現(xiàn)自定義的依賴注入,那么請(qǐng)參考依賴注入的相關(guān)文檔。

PostInitialize

提交初始化:最后一個(gè)方法,這個(gè)方法用來(lái)解析依賴關(guān)系。

Shutdown

關(guān)閉:當(dāng)應(yīng)用關(guān)閉以后,這個(gè)方法被調(diào)用。

1.3.4 模塊依賴

Abp框架會(huì)自動(dòng)解析模塊之間的依賴關(guān)系,但是我們還是建議你通過(guò)重載GetDependencies方法來(lái)明確的聲明依賴關(guān)系。

[DependsOn(typeof(MyBlogCoreModule))]//通過(guò)注解來(lái)定義依賴關(guān)系
public class MyBlogApplicationModule : AbpModule
{
    public override void Initialize()
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
    }
}

例如上面的代碼,我們就聲明了MyBlogApplicationModule和MyBlogCoreModule的依賴關(guān)系,MyBlogApplicationModule這個(gè)應(yīng)用模塊依賴于MyBlogCoreModule核心模塊,并且,MyBlogCoreModule核心模塊會(huì)在MyBlogApplicationModule模塊之前進(jìn)行初始化。

ABP可以從 startup module 遞歸的解析依賴關(guān)系,并按需初始化它們。最后初始化的模塊是啟動(dòng)模塊(startup module)。

1.3.5 插件模塊

當(dāng)模塊從啟動(dòng)模塊以及其依賴關(guān)系進(jìn)行調(diào)查發(fā)現(xiàn)的時(shí)候,ABP也能夠動(dòng)態(tài)的加載其它指定模塊。AbpBootstrapper 類定義了 PlugInSources 屬性,我們能用該屬性添加需要?jiǎng)討B(tài)加載的模塊。插件源可以是任何實(shí)現(xiàn)了 IPlugInSource 接口的類。FolderPlugInSource 類實(shí)現(xiàn)了該接口,它可以被用來(lái)加載指定文件夾下的程序集。

ASP.NET Core

ABP的ASP.NET Core模塊也可以動(dòng)態(tài)加載模塊,你只需要在 Startup 類中使用已定義的擴(kuò)展方法 AddAbp,如下所示:

services.AddAbp<MyStartupModule>(options =>
{
    options.PlugInSources.Add(new FolderPlugInSource(@"C:\MyPlugIns"));
});

我們可以使用擴(kuò)展方法 AddFolder 更方便的實(shí)現(xiàn)上述功能:

services.AddAbp<MyStartupModule>(options =>
{
    options.PlugInSources.AddFolder(@"C:\MyPlugIns");
});

了解更多關(guān)于Startup類的信息,請(qǐng)查看 ASP.NET 文檔

ASP.NET MVC,Web API

對(duì)于經(jīng)典的ASP.NET MVC應(yīng)用,我們可以在 global.asax 重寫(xiě) Application_Start 方法來(lái)添加插件文件夾,如下所示:

public class MvcApplication : AbpWebApplication<MyStartupModule>
{
    protected override void Application_Start(object sender, EventArgs e)
    {
        AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns");
        //...
        base.Application_Start(sender, e);
    }
}

插件中的控制器

如果你的模塊包括了MVC或者Web API控制器,ASP.NET不能發(fā)現(xiàn)這些控制器。為了克服這個(gè)問(wèn)題,你可以在 global.asax 中添加代碼來(lái)實(shí)現(xiàn),如下所示:

using System.Web;
using Abp.PlugIns;
using Abp.Web;
using MyDemoApp.Web;

[assembly: PreApplicationStartMethod(typeof(PreStarter), "Start")]

namespace MyDemoApp.Web
{
    public class MvcApplication : AbpWebApplication<MyStartupModule>
    {
    }

    public static class PreStarter
    {
        public static void Start()
        {
            //...
            MvcApplication.AbpBootstrapper.PlugInSources.AddFolder(@"C:\MyPlugIns\");
            MvcApplication.AbpBootstrapper.PlugInSources.AddToBuildManager();
        }
    }
}

Additional Assemblies

對(duì)于IAssemblyFinder和ITypeFinder的默認(rèn)實(shí)現(xiàn)(這兩個(gè)接口的實(shí)現(xiàn)被ABP用來(lái)在應(yīng)用程序中發(fā)現(xiàn)指定的類)僅僅只用來(lái)查找模塊程序集以及在這些程序集中所使用的類型。我們可以在我們的模塊中重寫(xiě) GetAdditionalAssemblies 方法來(lái)包含附加程序集。

1.3.6 自定義的模塊方法

我們自己定義的模塊中可能有方法被其他依賴于當(dāng)前模塊的模塊調(diào)用,下面的例子,假設(shè)模塊2依賴于模塊1,并且想在預(yù)初始化的時(shí)候調(diào)用模塊1的方法。這樣,就把模塊1注入到了模塊2,因此,模塊2就能調(diào)用模塊1的方法了。

譯者注:
ABP的模塊系統(tǒng)與Orchard的模塊有類似之處,但還是有比較大的差別。Orchard的框架修改了ASP.NET程序集的默認(rèn)加載方式(模塊的DLL沒(méi)有放在Bin文件夾下,是放在WEB項(xiàng)目根文件夾下面的Modules文件夾下),實(shí)現(xiàn)了功能模塊的熱插拔,而ABP的模塊程序集還是放在Bin文件夾下的,沒(méi)有實(shí)現(xiàn)熱插拔。

public class MyModule1 : AbpModule
{
    public override void Initialize() //初始化模塊
    {
        IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());//這里,進(jìn)行依賴注入的注冊(cè)。
    }

    public void MyModuleMethod1()
    {
        //這里寫(xiě)自定義的方法。
    }
}

[DependsOn(typeof(MyModule1))]
public class MyModule2 : AbpModule
{
    private readonly MyModule1 _myModule1;

    public MyModule2(MyModule1 myModule1)
    {
        _myModule1 = myModule1;
    }

    public override void PreInitialize()
    {
        _myModule1.MyModuleMethod1(); //調(diào)用MyModuleMethod1的方法。
    }

    public override void Initialize()
    {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
     }
}

在這里,我們通過(guò)構(gòu)造函數(shù)注入MyModule1到MyModule2,所以MyModule2能夠調(diào)用MyModule1的自定義方法。當(dāng)且僅當(dāng)MyModule2依賴于MyModule1才是可能的。

1.3.7 模塊配置

雖然自定義模塊可以被用來(lái)配置模塊,但是,作者建議使用啟動(dòng)配置來(lái)定義和配置模塊。

1.3.8 模塊生命周期

所有的模塊類都被自動(dòng)的注冊(cè)為單例模式。

返回簡(jiǎn)書(shū)總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
前往博客園總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容