ASP.NET Boilerplate How To Use

Module & Startup Configuration ASP.NET Boilerplate

Overview of Module, Startup Configuration in ASP.NET Boilerplate.

Quang Trong VU
Old Dev

--

  1. Module
  2. Startup Configuration

Module

Introduction:

ASP.NET Boilerplate cung cấp hạ tầng để xây dựng các module và kết hợp chúng thành một ứng dụng. Một module có thể phụ thuộc vào một hoặc nhiều module khác. Thường thì một assembly sẽ được coi như một module.

Module Definition:

Một module được định nghĩa là một class được dẫn xuất từ /Abp/Modules/AbpModule.

public class MyBlogApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}

Class định nghĩa module này có trách nhiệm Register các Class con của nó vào DI Container thông qua Dependency Injection. Đoạn code trên thực hiện Register các class của module này theo quy ước (convention). Module này cũng có thể thực hiện configure cho Application, cho các module khác, cho những feature mới của Application…

Module Dependencies

Một module có thể phụ thuộc (dependent) module khác. Bạn cần Explicitly khai báo sự phụ thuộc này bằng DependsOn attribute.

[DependsOn(typeof(MyBlogCoreModule))]
public class MyBlogApplicationModule : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
}

Lifecycle Methods

ASP.NET Boilerplate sẽ gọi một số hàm cụ thể của module khi Application startup và shutdown. Bạn có thể override những method này để thực hiện những công việc mong muốn.

ASP.NET Boilerplate gọi những method này theo thứ tự của dependencies. Ví dụ: nếu module A phụ thuộc vào module B, thì module B sẽ được initialzed trước module A.

Thứ tự chính xác như sau: PreInitialize-B, PreInitialize-A, Initialize-B, Initialize-A, PostInitialize-BPostInitialize-A. Quy luật này áp dụng cho toàn bộ dependency graph. Method Shutdown cũng thực hiện tương tự, nhưng với thứ tự ngược lại.

  • PreInitialize: Method này được gọi đầu tiên khi Application start. Nó là một dạng go-to method, gọi ngược ra framework hoặc các module khác để thực hiện một số Start-Configuration trước khi nó (module này) được Initialize.
    Bạn có thể viết code riêng của mình ở đây, và nó sẽ được thực thi trước DI registration. Ví dụ: nếu bạn tạo một conventional registration class, bạn nên register nó ở đây sử dụng IocManager.AddConventionalRegister method.
  • Initialize: Đây là nơi Dependency Injection Registration sẽ được thực hiện. Thường dùng IocManager.RegisterAssemblyByConvention method. Bạn có thể custom lại DI Registration nếu muốn.
  • PostInitialize: Method này được gọi cuối cùng trong start process. Sẽ an toàn khi resolve (create) một dependency ở đây.
  • Shutdown: Method này được gọi khi Application shutdown.

Module Lifetime

Các module class được tự động register là Singleton.

Plugin Modules

Trong khi các module (not Plugin Module) được tìm kiếm và load khi bắt đầu chạy Startup Module và tiến hành load theo các phụ thuộc. Ngoài ra ASP.NET Boilerplate còn có thể load động các module (dynamically). Class AbpBoostraper định nghĩa PluginSource property, thuộc tính này dùng để add plugin source và load động các plugin module. Một plugin source có thể là bất kỳ class nào cài đặt IPluginSource interface. Class PluginFolderSource cài đặt interface này để get các plugin module từ các assemblies đặt trong một folder.

ASP.NET Core module của ASP.NET Boilerplate định nghĩa một option trong AddAbp extension method để add plug sources trong Startup class.

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

Chúng ta cũng có thể dùng AddFolder extension method cho một cú pháp đơn giản hơn

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

Additional Assemblies

Những implementation mặc định của IAssemblyFinderITypeFinder, implementation này được ASP.NET Boilerplate dùng để điều tra các lớp đặc trưng trong ứng dụng (specific class). Tuy nhiên chúng chỉ tìm trong các Module Assembly (AbpModule), và các Types trong những module đó. Chúng ta có thể override lại method GetAdditionalAssemblies trong module của mình để include thêm các additional assemblies.

Custom Module Methods

Module của bạn có thể có những custom method, cái sẽ được dùng bởi những module khác và phụ thuộc vào module này. Giả sử MyModule2 phụ thuộc vào MyModule1 và nó muốn gọi một method của MyModule1 trong PreInitialize method.

public class MyModule1 : AbpModule
{
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}

public void MyModuleMethod1()
{
//this is a custom method of this module
}
}

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

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

public override void PreInitialize()
{
_myModule1.MyModuleMethod1(); //Call MyModule1's method
}

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

Module Configuration

Trong khi có thể dùng custom method để cấu hình các module, nhưng chúng tôi khuyến nghi bạn sử dụng startup configuration system để định nghĩa và thiết lập cấu hình cho module.

Startup Configuration

ASP.NET Boilerplate cung cấp một model để cấu hình các module của nó khi startup.

Việc cấu hình ASP.NET Boilerplate được tạo bởi PreInitialize method trong các module cấu thành ứng dụng. Ví dụ:

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());
}
}

ASP.NET Boilerplate được thiết kế với quan điểm module hoá ứng dụng. Các module khác nhau có thể cấu hình ASP.NET Boilerplate. Ví dụ, các module khác nhau có thể add navigation provider để add menu item của riêng mình vào main menu. (Tham khảo mục tài liệu LocalizationNavigation của ASP.NET Boilerplate).

Replacing Built-In Services

Method Configuration.ReplaceService có thể được dùng để override một built-in service. Ví dụ, bạn có thể thay thế IAbpSession service với tuỳ chỉnh cài đặt của bạn như code dưới đây

Configuration.ReplaceService<IAbpSession, MySession>(DependencyLifeStyle.Transient);

Method ReplaceService còn có một overload có thể truyền một action để tạo một thay thế theo một cách tuỳ biến (bạn có thể dùng trực tiếp Castle Windsor với tính năng cao cấp registration API).

Cùng một service có thể được thay thế nhiều lần, nhất là trong những module khác nhau. Thằng được thay thế cuối cùng sẽ được sử dụng. Ghi nhớ các PreInitialize được thực thi theo dependency order.

Configuring Modules

Ngoài bản thân startup configuration của framework, một module có thể extend IAbpModuleConfiguration interface để cung cấp configuration points(nơi để các module khác có thể chọc tới để cấu hình cho module này?). Ví dụ

...
using Abp.Web.Configuration;
...
public override void PreInitialize()
{
Configuration.Modules.AbpWebCommon().SendAllExceptionsToClients = true;
}
...

Trong ví dụ này, chúng ta cấu hình AbpWebCommon module để send tất cả exception đến client. Ở đây AbpWebCommon mở ra một configuration point.

Không phải mọi module cần định nghĩa kiểu cấu hình này. Thường nó sẽ được dùng khi một module có thể được re-use trong những ứng dụng khác nhau và cần được cấu hình cho giai đoạn startup.

Creating Configuration for a Module

Tại sao phải tạo Configuration cho một Module? Sau khi đã mở Configuration Point giờ chúng ta cần tạo những Configuration Properties cho module mục tiêu để các module khác có thể thay đổi thông tin cấu hình của module mục tiêu này..

Giả sử chúng ta có một module tên là MyModule và nó có một vài thuộc tính cấu hình. Đầu tiên, chúng ta tạo một lớp cho những thuộc tính này.

public class MyModuleConfig
{
public bool SampleConfig1 { get; set; }

public string SampleConfig2 { get; set; }
}

Sau đó chúng ta sẽ register class này thông qua Dependency Injection trong method PreInitialize của MyModule.

IocManager.Register<MyModuleConfig>();

Nó nên được register là một Singleton giống như ví dụ này. Như vậy chúng ta đã có thể cấu hình cho MyModule từ PreInitialize method của một module khác.

Configuration.Get<MyModuleConfig>().SampleConfig1 = false;

(1) Configuring using extension method

Chúng ta sẽ tạo một extension method cho IModuleConfiguration, và sử dụng method IAbpStartupConfiguration như sau

public static class MyModuleConfigurationExtensions
{
public static MyModuleConfig MyModuleConfiguration(this IModuleConfigurations moduleConfigurations)
{
return moduleConfigurations.AbpConfiguration.Get<MyModuleConfig>();
}
}

Và bây giờ dùng extension method trên để configure cho MyModule.

Configuration.Modules.MyModuleConfiguration().SampleConfig1 = false;
Configuration.Modules.MyModuleConfiguration().SampleConfig2 = "test";

Cách này giúp dễ dàng tập hợp và tìm thông tin cấu hình module tại một điểm (Configuration.Modules…). ASP.NET Boilerplate định nghĩa các extension method cho việc cấu hình các module của nó.

(2) Configuring using injection

Tại một vài chỗ trong MyModule cần những thông tin cấu hình này. Bạn có thể inject MyModuleConfig và dùng các configured value. Ví dụ:

public class MyService : ITransientDependency
{
private readonly MyModuleConfig _configuration;

public MyService(MyModuleConfig configuration)
{
_configuration = configuration;
}

public void DoIt()
{
if (_configuration.SampleConfig2 == "test")
{
//...
}
}
}

Conclusion:

Module Definition: class kế thừa AbpModule
Module Dependencies: phải explicitly khai báo bằng DependsOn annotation.
Module Lifecycle Methods: các method được gọi khi startup application: PreInitialize, Initialize, PostInitialize. Các method được gọi khi shutdown: Shutdown.
Module Lifetime: Singleton
Plugin Module: dynamically load module
Custom Module Method: method for call by another module.
Startup-configuration: ASP.NET Boilerplate cung cấp model để load cấu hình modules khi startup. Application Configuration là tổng hợp các PreInitialize method của các Module cấu thành.
Replacing Built-in Service: bạn có thể thay thế service của mình thay cho built-in service bằng cách override lại các built-in service này và register nó qua DI.
Configuring Modules: một module có thể mở ra configuration point để module khác có thể thay đổi cấu hình của nó. Bằng việc sử dụng cấu hình qua extension method đã giúp tập trung thông tin cấu hình tại đơn điểm (Configuration.Modules…), giúp cho việc tìm kiếm và tổng hợp dễ dàng hơn.

--

--

Quang Trong VU
Old Dev
Editor for

Software Developer — Life’s a journey — Studying and Sharing