日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

基于DDD的.NET开发框架 - ABP模块设计

發(fā)布時間:2024/4/13 asp.net 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于DDD的.NET开发框架 - ABP模块设计 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

返回ABP系列

ABP是“ASP.NET Boilerplate Project (ASP.NET樣板項目)”的簡稱。

ASP.NET Boilerplate是一個用最佳實踐和流行技術(shù)開發(fā)現(xiàn)代WEB應(yīng)用程序的新起點,它旨在成為一個通用的WEB應(yīng)用程序框架和項目模板。

ABP的官方網(wǎng)站:http://www.aspnetboilerplate.com

ABP官方文檔:http://www.aspnetboilerplate.com/Pages/Documents

Github上的開源項目:https://github.com/aspnetboilerplate

一、摘要

研究過orchard和nopcommerce的都應(yīng)該知道模塊概念,ABP的模塊也和他們是一回事。實現(xiàn)原理也都一樣:應(yīng)用程序一般都是先定義模塊接口,然后把模塊編譯的dll放到固定的目錄中(ABP只能放到bin下),應(yīng)用程序主程序通過加載那些實現(xiàn)了插件接口的dll來實現(xiàn)插件的使用。

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

nopcommerce插件實現(xiàn)可以到:ASP.NET MVC5 插件化機制簡單實現(xiàn)了解下。

二、基本概念

下面的例子,我們開發(fā)一個可以在多個不同應(yīng)用中被調(diào)用MybolgApplication模塊,代碼如下:

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

ABP框架會掃描所有的程序集,并且發(fā)現(xiàn)AbpModule類中所有已經(jīng)導(dǎo)入的所有類,如果你已經(jīng)創(chuàng)建了包含多個程序集的應(yīng)用,對于ABP,我們的建議是為每一個程序集創(chuàng)建一個Module(模塊)。

生命周期:

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

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


1、PreInitialize-B
2、PreInitialize-A
3、Initialize-B
4、Initialize-A
5、PostInitialize-B
6、PostInitialize-A

下面是具體方法的說明:

PreInitialize 預(yù)初始化:當(dāng)應(yīng)用啟動后,第一次會調(diào)用這個方法。在依賴注入注冊之前,你可以在這個方法中指定自己的特別代碼。舉個例子吧:假如你創(chuàng)建了一個傳統(tǒng)的登記類,那么你要先注冊這個類(使用IocManager對登記類進(jìn)行注冊),你可以注冊事件到IOC容器。

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

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

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

模塊依賴:

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

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

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

自定義的模塊方法:

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

public class MyModule1 : AbpModule {public override void Initialize() //初始化模塊 {IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());//這里,進(jìn)行依賴注入的注冊。 }public void MyModuleMethod1(){//這里寫自定義的方法。 } }[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());} }

就這樣,就把模塊1注入到了模塊2,因此,模塊2就能調(diào)用模塊1的方法了。

三、基本原理

1、獲取bin下全部dll

/// <summary>/// 獲取bin下全部dll/// </summary>public List<Assembly> GetAllAssemblies(){var allReferencedAssemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList();var dllFiles = Directory.GetFiles(HttpRuntime.AppDomainAppPath + "bin\\", "*.dll", SearchOption.TopDirectoryOnly).ToList();return dllFiles.Select(dllFile => allReferencedAssemblies.FirstOrDefault(asm => AssemblyName.ReferenceMatchesDefinition(asm.GetName(), AssemblyName.GetAssemblyName(dllFile)))).Where(locatedAssembly => locatedAssembly != null).ToList();}

2、判斷是否繼承了AbpModule接口

/// <summary>/// 判斷與AbpModule的Types是否有關(guān)/// </summary>public static bool IsAbpModule(Type type){returntype.IsClass &&!type.IsAbstract &&typeof(AbpModule).IsAssignableFrom(type);}

3、循環(huán)相關(guān)的依賴,把他們填在到modules集合中

#region 循環(huán)相關(guān)的依賴,把他們填在到modules集合中private static ICollection<Type> AddMissingDependedModules(ICollection<Type> allModules){var initialModules = allModules.ToList();foreach (var module in initialModules){FillDependedModules(module, allModules);}return allModules;}private static void FillDependedModules(Type module, ICollection<Type> allModules){foreach (var dependedModule in AbpModule.FindDependedModuleTypes(module)){if (allModules.Contains(dependedModule)) continue;allModules.Add(dependedModule);FillDependedModules(dependedModule, allModules);}}public static List<Type> FindDependedModuleTypes(Type moduleType){if (!IsAbpModule(moduleType)){throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);}var list = new List<Type>();if (!moduleType.IsDefined(typeof (DependsOnAttribute), true)) return list;var dependsOnAttributes = moduleType.GetCustomAttributes(typeof(DependsOnAttribute), true).Cast<DependsOnAttribute>();list.AddRange(dependsOnAttributes.SelectMany(dependsOnAttribute => dependsOnAttribute.DependedModuleTypes));return list;}#endregion

?4、控制反轉(zhuǎn)

using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Abp.Configuration.Startup; using Abp.Dependency; using Castle.Core.Logging;namespace Abp.Modules {/// <summary>/// This class is used to manage modules./// </summary>internal class AbpModuleManager : IAbpModuleManager{public ILogger Logger { get; set; }private readonly AbpModuleCollection _modules;private readonly IIocManager _iocManager;private readonly IModuleFinder _moduleFinder;public AbpModuleManager(IIocManager iocManager, IModuleFinder moduleFinder){_modules = new AbpModuleCollection();_iocManager = iocManager;_moduleFinder = moduleFinder;Logger = NullLogger.Instance;}/// <summary>/// 初始化模塊/// </summary>public virtual void InitializeModules(){LoadAll(); //加載所有var sortedModules = _modules.GetSortedModuleListByDependency();//初始化Modules的事件sortedModules.ForEach(module => module.Instance.PreInitialize());sortedModules.ForEach(module => module.Instance.Initialize());sortedModules.ForEach(module => module.Instance.PostInitialize());}/// <summary>/// 關(guān)閉模塊/// </summary>public virtual void ShutdownModules(){var sortedModules = _modules.GetSortedModuleListByDependency();sortedModules.Reverse();sortedModules.ForEach(sm => sm.Instance.Shutdown());}/// <summary>/// /// </summary>private void LoadAll(){Logger.Debug("Loading Abp modules...");var moduleTypes = AddMissingDependedModules(_moduleFinder.FindAll());Logger.Debug("Found " + moduleTypes.Count + " ABP modules in total.");//注冊到IOC容器foreach (var moduleType in moduleTypes){if (!AbpModule.IsAbpModule(moduleType)){throw new AbpInitializationException("This type is not an ABP module: " + moduleType.AssemblyQualifiedName);}if (!_iocManager.IsRegistered(moduleType)){_iocManager.Register(moduleType);}}//模塊添加到_modules中foreach (var moduleType in moduleTypes){var moduleObject = (AbpModule)_iocManager.Resolve(moduleType);moduleObject.IocManager = _iocManager;moduleObject.Configuration = _iocManager.Resolve<IAbpStartupConfiguration>();_modules.Add(new AbpModuleInfo(moduleObject));Logger.DebugFormat("Loaded module: " + moduleType.AssemblyQualifiedName);}EnsureKernelModuleToBeFirst();SetDependencies();Logger.DebugFormat("{0} modules loaded.", _modules.Count);}/// <summary>/// AbpKernelModule must be the first module/// </summary>private void EnsureKernelModuleToBeFirst(){var kernelModuleIndex = _modules.FindIndex(m => m.Type == typeof (AbpKernelModule));if (kernelModuleIndex > 0){var kernelModule = _modules[kernelModuleIndex];_modules.RemoveAt(kernelModuleIndex);_modules.Insert(0, kernelModule);}}private void SetDependencies(){foreach (var moduleInfo in _modules){//Set dependencies according to assembly dependencyforeach (var referencedAssemblyName in moduleInfo.Assembly.GetReferencedAssemblies()){var referencedAssembly = Assembly.Load(referencedAssemblyName);var dependedModuleList = _modules.Where(m => m.Assembly == referencedAssembly).ToList();if (dependedModuleList.Count > 0){moduleInfo.Dependencies.AddRange(dependedModuleList);}}//Set dependencies for defined DependsOnAttribute attribute(s).foreach (var dependedModuleType in AbpModule.FindDependedModuleTypes(moduleInfo.Type)){var dependedModuleInfo = _modules.FirstOrDefault(m => m.Type == dependedModuleType);if (dependedModuleInfo == null){throw new AbpInitializationException("Could not find a depended module " + dependedModuleType.AssemblyQualifiedName + " for " + moduleInfo.Type.AssemblyQualifiedName);}if ((moduleInfo.Dependencies.FirstOrDefault(dm => dm.Type == dependedModuleType) == null)){moduleInfo.Dependencies.Add(dependedModuleInfo);}}}}private static ICollection<Type> AddMissingDependedModules(ICollection<Type> allModules){var initialModules = allModules.ToList();foreach (var module in initialModules){FillDependedModules(module, allModules);}return allModules;}private static void FillDependedModules(Type module, ICollection<Type> allModules){foreach (var dependedModule in AbpModule.FindDependedModuleTypes(module)){if (!allModules.Contains(dependedModule)){allModules.Add(dependedModule);FillDependedModules(dependedModule, allModules);}}}} }

?

四、ABP底層如何描述Module

AbpModule:模塊抽象類

AbpModuleInfo:模塊信息

AbpModuleCollection:AbpModuleInfo的集合

IAbpModuleManager:模塊管理接口

AbpModuleManager:模塊管理類實現(xiàn)模塊管理接口

IModuleFinder:負(fù)責(zé)找所有模塊的接口

DefaultModuleFinder:實現(xiàn)IModuleFinder接口

DependsOnAttribute:用來定義ABP模塊依賴其他模塊

AbpModuleInfo用于封裝AbpModule的基本信息。?AbpModuleCollection則是AbpModuleInfo的集合。

五、Module注冊到ABP底層流程

Abp底層框架發(fā)現(xiàn)Module是從AbpBootstrapper在執(zhí)行Initialize方法的時候開始的,該方法會調(diào)用IAbpModuleManager實例的InitializeModules方法,這個方法接著調(diào)用DefaultModuleFinder的FindAll方法(該方法用于過濾出AbpModule的assembly),而FindAll方法調(diào)用TypeFinder得到所有的assembly. 所以只要你定義的assembly中有一個繼承至AbpModule的類,并且該assembly被引用到你的項目中,那么這個Module就可以說會被Abp底層框架集成了。

總結(jié)

以上是生活随笔為你收集整理的基于DDD的.NET开发框架 - ABP模块设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。