ABP是“ASP.NET Boilerplate Project (ASP.NET樣板項目)”的簡稱。
ASP.NET Boilerplate是一個用最佳實踐和流行技術開發現代WEB應用程序的新起點,它旨在成為一個通用的WEB應用程序框架和項目模板。
ABP的官方網站:http://www.aspnetboilerplate.com
ABP官方文檔:http://www.aspnetboilerplate.com/Pages/Documents
Github上的開源項目:https://github.com/aspnetboilerplate
一、如何把帶zero模塊的abp運行起來
今天我們在官網生成模版的頁面:http://www.aspnetboilerplate.com/Templates 生成一個帶zero模塊的abp解決方案。
生成完了后打開,解決目錄結構如下:
執行Code First Migrations 兩個命令:
Add-Migration “AbpZero_Installed”
Update-Databse
但總是執行失敗如下圖:
我們注意到 Data Scource 竟然是 .\\SQLEXPRESS 而不是我們想要的 localDB 。 如果我們安裝了 SQL Express,那么 database 將會安裝在 local SQL Express instance,否則 Code First 才將嘗試使用 localDB。
最好的解決辦法就是默認信任連接字符串換成標准安全連接,問題解決
信任連接
<add name="FirstCodeFirstApp" connectionString="Server=.;Database=CodeFirstApp;Integrated Security=SSPI" providerName="System.Data.SqlClient"/>
標准安全連接
<connectionStrings> <add name="Default" connectionString="Data Source =.;Initial Catalog = FirstAbpZero;User Id = sa;Password = 123;" providerName="System.Data.SqlClient" /> </connectionStrings>
運行起來用默認的用戶名:admin 密碼:123qwe 登錄,也可以自己注冊一個,但是默認租戶要填寫default;登錄頁面
注冊頁面
admin登錄后添加用戶頁面
雖然運行起來了好像和今天要說的配置關系不大,下面進入正題。
二、ABP啟動配置
配置ABP
public class SimpleTaskSystemModule : AbpModule { public override void PreInitialize() { //Add languages for your application Configuration.Localization.Languages.Add(new LanguageInfo("en", "English", "famfamfam-flag-england", true)); Configuration.Localization.Languages.Add(new LanguageInfo("tr", "Türkçe", "famfamfam-flag-tr")); //Add a localization source Configuration.Localization.Sources.Add( new XmlLocalizationSource( "SimpleTaskSystem", HttpContext.Current.Server.MapPath("~/Localization/SimpleTaskSystem") ) ); //Configure navigation/menu Configuration.Navigation.Providers.Add<SimpleTaskSystemNavigationProvider>(); } public override void Initialize() { IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly()); } }
abp框架一開始就被設計成模塊化的,不同的模塊可以通過abp框架來進行配置。舉個例子吧,不同的模塊都可以添加導航,通過導航添加菜單項到自己定義的主菜單,具體的細節大家可以參照:
本地化:http://www.aspnetboilerplate.com/Pages/Documents/Localization
導航:http://www.aspnetboilerplate.com/Pages/Documents/Navigation
重寫內置服務
可以通過Configuration.ReplaceService重寫服務,比如可以與您的自定義實現替代iabpsession服務如下圖所示:
Configuration.ReplaceService<IAbpSession, MySession>(DependencyLifeStyle.Transient);
replaceservice方法具有過載通過一個自定義的方式進行替換操作。
同樣的服務可以被替換多次(特別是在不同的模塊)。最后更換將是有效的(你知道,模塊分發方法是通過依賴順序執行)。
配置模塊
和.net框架原生的啟動配置相比較,abp有哪些不一樣呢?abp框架的模塊可以通過IAbpModuleConfigurations接口進行個性化的擴展,這樣的話,模塊配置更加簡單、方便。
示例代碼如下:
... using Abp.Web.Configuration; ... public override void PreInitialize() { Configuration.Modules.AbpWeb().SendAllExceptionsToClients = true; } ...
在上面這個例子中,我們通過配置AbpWeb模塊,發送異常到客戶端。當然了,不是每一個模塊都需要這種配置,通常情況下我們需要,是當一個模塊需要在多個不同的應用中重復使用,我們才進行這樣的配置。
為一個模塊創建配置
如下代碼,假如我們有一個命名為MyModule的模塊,並且這各模塊有一些自己的配置。那么我們首先要創建一些類,這些類定義為屬性(譯者注:屬性有自動的get和set訪問器。),代表了不同的配置。
public class MyModuleConfig { public bool SampleConfig1 { get; set; } public string SampleConfig2 { get; set; } }
接下來,我們通過依賴注入,注冊這個類。
IocManager.Register<MyModuleConfig>();
最后,我們通過創建一個擴展的方法IModuleConfigurations來得到配置的引用。如下代碼:
public static class MyModuleConfigurationExtensions { public static MyModuleConfig MyModule(this IModuleConfigurations moduleConfigurations) { return moduleConfigurations.AbpConfiguration .GetOrCreate("MyModuleConfig", () => moduleConfigurations.AbpConfiguration.IocManager.Resolve<MyModuleConfig>() ); } }
現在,在其他模塊中也可以配置我們自定義的這個MyModule模塊了。
Configuration.Modules.MyModule().SampleConfig1 = false; Configuration.Modules.MyModule().SampleConfig2 = "test";
在某種意義上,MyModule需要這些配置,你能注射MyModuleConfig並且可以使用這些值。
public class MyService : ITransientDependency { private readonly MyModuleConfig _configuration; public MyService(MyModuleConfig configuration) { _configuration = configuration; } public void DoIt() { if (_configuration.SampleConfig2 == "test") { //... } } }
這意味着,在abp框架的系統中,所有的模塊都可以集中配置。
三、ABP核心模塊配置分析
ABP的配置設計的非常巧妙,通過AbpStartupConfiguration,Castle的依賴注入,Dictionary對象和擴展方法很巧妙的實現了配置中心化。配置中心化是一個支持模塊開發的框架必備功能。
ABP中核心功能模塊中的一些功能的運行時的行為是依賴於一些外部配置的。所以ABP底層框架通過IAbpStartupConfiguration供外部模塊自定義Congfiguration。
ABP初始化階段就要被實例化的接口都放到了Startup文件夾下
ABP核心功能組件的Configuration實例化過程如下圖:
以后需要調用或修改某個組件的Configuration,只要引用其IAbpStartupConfiguration的實例Configuration即可訪問各個組件的Configuration了。
四、自定義module的Configuration 實現分析
Abp底層框架知道自己核心功能模塊,所以就很自然的給每個核心功能模塊各自定義一個Configuration接口。但是Abp底層框架並不知道自定義的module有哪些,所以也就無法給每個自定義的module都創建一個Configuration接口。那么ABP底層框架是怎么管理每個自定義的module的Configuration的呢?
仔細看代碼,IAbpStartupConfiguration繼承了IDictionaryBasedConfig,DictionaryBasedConfig實現了IDictionaryBasedConfig接口,DictionaryBasedConfig下有個dictionary,這個就是最終保存自定義的module的Configuration的地方,因為Configuration的類型未知,所以dictionary的value是object類型。
下面以AbpWebModule為例講解
1、AbpWebModule定義了自己的接口IAbpWebModuleConfiguration和AbpWebModuleConfiguration,以及AbpConfigurationExtension
2、在AbpWebModule的preInitialize方法中將接口IAbpWebModuleConfiguration和其實現AbpWebModuleConfiguration注冊到容器中。
IocManager.Register<IAbpWebModuleConfiguration, AbpWebModuleConfiguration>();
3、AbpConfigurationExtension擴展了IModuleConfigurations接口
using Abp.Web.Configuration; namespace Abp.Configuration.Startup { /// <summary> /// Defines extension methods to <see cref="IModuleConfigurations"/> to allow to configure ABP Web module. /// </summary> public static class AbpWebConfigurationExtensions { /// <summary> /// Used to configure ABP Web module. /// </summary> public static IAbpWebModuleConfiguration AbpWeb(this IModuleConfigurations configurations) { return configurations.AbpConfiguration.GetOrCreate("Modules.Abp.Web", () => configurations.AbpConfiguration.IocManager.Resolve<IAbpWebModuleConfiguration>()); } } }
這個接口是在Abp底層框架中定義和實現的。其屬性AbpConfiguration就是AbpStartupConfiguration實例。通過AbpStartupConfiguration的getorCreate方法(具體通過DictionaryBasedConfig來實現)就可以獲取到AbpWebModule自定義的AbpWebModuleConfiguration的實例了。
namespace Abp.Configuration.Startup { internal class ModuleConfigurations : IModuleConfigurations { public IAbpStartupConfiguration AbpConfiguration { get; private set; } public ModuleConfigurations(IAbpStartupConfiguration abpConfiguration) { AbpConfiguration = abpConfiguration; } } }
具體訪問方式如下,Configuration.Modules就是IModuleConfigurations的實例。通過其擴展方法AbpWeb訪問AbpWebModuleConfiguration
Configuration.Modules.AbpWeb.SendAllExceptionsToClients=True;