From 58227186f8bda6f663ce1acd2ed201c31bf5cefa Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 18 Apr 2022 17:27:36 +0800 Subject: [PATCH 1/6] Add `Bootstrap-Modules.md` --- docs/en/Bootstrap-Modules.md | 128 ++++++++++++++++++ .../Getting-Started-AspNetCore-Application.md | 22 ++- docs/en/docs-nav.json | 4 + 3 files changed, 140 insertions(+), 14 deletions(-) create mode 100644 docs/en/Bootstrap-Modules.md diff --git a/docs/en/Bootstrap-Modules.md b/docs/en/Bootstrap-Modules.md new file mode 100644 index 0000000000..904197e4e3 --- /dev/null +++ b/docs/en/Bootstrap-Modules.md @@ -0,0 +1,128 @@ +# Bootstrap Modules + +ABP framework can be bootstrapped in various applications. like ASP NET Core or Console, WPF, etc. + +Modules can be started sync or async, Corresponds to various event methods in the module. We recommend using **async**, Especially if you want to make async calls in the module's methods. + +The `PreConfigureServices`, `ConfigureServices`, `PostConfigureServices`, `OnPreApplicationInitialization`, `OnApplicationInitialization`, `OnPostApplicationInitialization` methods of module have the Async version. + +> Async methods automatically call sync methods by default. + +If you use async methods in your module, please keep the same sync methods for compatibility. + +````csharp +public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) +{ + await AsyncMethod(); +} + +public override void OnApplicationInitialization(ApplicationInitializationContext context) +{ + AsyncHelper.RunSync(() => OnApplicationInitializationAsync(context)); +} +```` + +## ASP NET Core + +Bootstrap ABP by using [WebApplication](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.webapplication?view=aspnetcore-6.0) + +````csharp +var builder = WebApplication.CreateBuilder(args); +builder.Host.AddAppSettingsSecretsJson() + .UseAutofac(); + +await builder.Services.AddApplicationAsync(); +var app = builder.Build(); + +await app.InitializeApplicationAsync(); +await app.RunAsync(); +```` + +## Console + +Bootstrap ABP in Console App. + +````csharp +var abpApplication = await AbpApplicationFactory.CreateAsync(options => +{ + options.UseAutofac(); +}); + +await _abpApplication.InitializeAsync(); + +var helloWorldService = _abpApplication.ServiceProvider.GetRequiredService(); + +await helloWorldService.SayHelloAsync(); +```` + +Bootstrap ABP by using [HostedService](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-6.0&tabs=visual-studio#ihostedservice-interface) + +````csharp +public class MyHostedService : IHostedService +{ + private IAbpApplicationWithInternalServiceProvider _abpApplication; + + private readonly IConfiguration _configuration; + private readonly IHostEnvironment _hostEnvironment; + + public MyHostedService(IConfiguration configuration, IHostEnvironment hostEnvironment) + { + _configuration = configuration; + _hostEnvironment = hostEnvironment; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + _abpApplication = await AbpApplicationFactory.CreateAsync(options => + { + options.Services.ReplaceConfiguration(_configuration); + options.Services.AddSingleton(_hostEnvironment); + + options.UseAutofac(); + options.Services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog()); + }); + + await _abpApplication.InitializeAsync(); + + var helloWorldService = _abpApplication.ServiceProvider.GetRequiredService(); + + await helloWorldService.SayHelloAsync(); + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + await _abpApplication.ShutdownAsync(); + } +} +```` + +## WPF + +Bootstrap ABP on [OnStartup](https://docs.microsoft.com/en-us/dotnet/api/system.windows.application.onstartup?view=windowsdesktop-6.0) method. + +````csharp +public partial class App : Application +{ + private IAbpApplicationWithInternalServiceProvider _abpApplication; + + protected async override void OnStartup(StartupEventArgs e) + { + _abpApplication = await AbpApplicationFactory.CreateAsync(options => + { + options.UseAutofac(); + options.Services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true)); + }); + + await _abpApplication.InitializeAsync(); + + _abpApplication.Services.GetRequiredService()?.Show(); + } + + protected async override void OnExit(ExitEventArgs e) + { + await _abpApplication.ShutdownAsync(); + } +} + +```` + diff --git a/docs/en/Getting-Started-AspNetCore-Application.md b/docs/en/Getting-Started-AspNetCore-Application.md index c5b72a6c1d..ef14fd0c54 100644 --- a/docs/en/Getting-Started-AspNetCore-Application.md +++ b/docs/en/Getting-Started-AspNetCore-Application.md @@ -77,20 +77,17 @@ using BasicAspNetCoreApplication; var builder = WebApplication.CreateBuilder(args); -builder.Services.ReplaceConfiguration(builder.Configuration); - -builder.Services.AddApplication(); +await builder.Services.AddApplicationAsync(); var app = builder.Build(); -app.InitializeApplication(); - -app.Run(); +await app.InitializeApplicationAsync(); +await app.RunAsync(); ```` -``builder.Services.AddApplication();`` adds all services defined in all modules starting from the ``AppModule``. +``builder.Services.AddApplicationAsync();`` adds all services defined in all modules starting from the ``AppModule``. -``app.InitializeApplication()`` initializes and starts the application. +``app.InitializeApplicationAsync()`` initializes and starts the application. ## Run the Application! @@ -128,15 +125,12 @@ var builder = WebApplication.CreateBuilder(args); builder.Host.UseAutofac(); //Add this line -builder.Services.ReplaceConfiguration(builder.Configuration); - -builder.Services.AddApplication(); +await builder.Services.AddApplicationAsync(); var app = builder.Build(); -app.InitializeApplication(); - -app.Run(); +await app.InitializeApplicationAsync(); +await app.RunAsync(); ```` diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 8c08724b62..f553cad14a 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -426,6 +426,10 @@ "text": "Basics", "path": "Module-Development-Basics.md" }, + { + "text": "Bootstrap", + "path": "Bootstrap-Modules.md" + }, { "text": "Plug-In Modules", "path": "PlugIn-Modules.md" From 14373bb559ce23b6be5dd39fea57c932a30d2a53 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 19 Apr 2022 11:33:03 +0800 Subject: [PATCH 2/6] Add notes to the `Module-Development-Basics` --- docs/en/Module-Development-Basics.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/en/Module-Development-Basics.md b/docs/en/Module-Development-Basics.md index 63cbc31893..17c0e91808 100644 --- a/docs/en/Module-Development-Basics.md +++ b/docs/en/Module-Development-Basics.md @@ -29,6 +29,8 @@ public class BlogModule : AbpModule ``ConfigureServices`` is the main method to add your services to the dependency injection system and configure other modules. Example: +> These methods have Async versions too, and if you want to make asynchronous calls inside these methods, override the asynchronous versions instead of the synchronous ones. + ````C# public class BlogModule : AbpModule { @@ -63,6 +65,8 @@ See the [Configuration](Configuration.md) document for more about the configurat ``AbpModule`` class also defines ``PreConfigureServices`` and ``PostConfigureServices`` methods to override and write your code just before and just after ``ConfigureServices``. Notice that the code you have written into these methods will be executed before/after the ``ConfigureServices`` methods of all other modules. +> These methods have Async versions too, and if you want to make asynchronous calls inside these methods, override the asynchronous versions instead of the synchronous ones. + ### Application Initialization Once all the services of all modules are configured, the application starts by initializing all modules. In this phase, you can resolve services from ``IServiceProvider`` since it's ready and available. @@ -71,10 +75,18 @@ Once all the services of all modules are configured, the application starts by i You can override ``OnApplicationInitialization`` method to execute code while application is being started. Example: +> These methods have Async versions too, and if you want to make asynchronous calls inside these methods, override the asynchronous versions instead of the synchronous ones. + ````C# public class BlogModule : AbpModule { - //... + // Asynchronous methods call synchronous methods by default, You only need to implement one of them. + + public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + { + var myService = context.ServiceProvider.GetService(); + await myService.DoSomethingAsync(); + } public override void OnApplicationInitialization(ApplicationInitializationContext context) { From fa9babde3fae4ebde25dccd22e74bad89dbe31d7 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 27 Apr 2022 22:16:12 +0800 Subject: [PATCH 3/6] Revert "Publish event when uow completed" --- .../Distributed/LocalDistributedEventBus.cs | 56 +++------------ .../LocalDistributedEventBus_Test.cs | 70 +------------------ 2 files changed, 12 insertions(+), 114 deletions(-) diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus.cs index 1eb7689aba..64f375130b 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus.cs @@ -6,7 +6,6 @@ using Microsoft.Extensions.Options; using Volo.Abp.Collections; using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Local; -using Volo.Abp.Uow; namespace Volo.Abp.EventBus.Distributed; @@ -16,19 +15,16 @@ public class LocalDistributedEventBus : IDistributedEventBus, ISingletonDependen { private readonly ILocalEventBus _localEventBus; - protected IUnitOfWorkManager UnitOfWorkManager { get; } protected IServiceScopeFactory ServiceScopeFactory { get; } protected AbpDistributedEventBusOptions AbpDistributedEventBusOptions { get; } public LocalDistributedEventBus( ILocalEventBus localEventBus, - IUnitOfWorkManager unitOfWorkManager, IServiceScopeFactory serviceScopeFactory, IOptions distributedEventBusOptions) { _localEventBus = localEventBus; - UnitOfWorkManager = unitOfWorkManager; ServiceScopeFactory = serviceScopeFactory; AbpDistributedEventBusOptions = distributedEventBusOptions.Value; Subscribe(distributedEventBusOptions.Value.Handlers); @@ -126,56 +122,24 @@ public class LocalDistributedEventBus : IDistributedEventBus, ISingletonDependen _localEventBus.UnsubscribeAll(eventType); } - public async Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true) + public Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true) where TEvent : class { - await PublishAsync(typeof(TEvent), eventData, onUnitOfWorkComplete); + return _localEventBus.PublishAsync(eventData, onUnitOfWorkComplete); } - public async Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true) + public Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true) { - if (onUnitOfWorkComplete && UnitOfWorkManager.Current != null) - { - AddToUnitOfWork( - UnitOfWorkManager.Current, - new UnitOfWorkEventRecord(eventType, eventData, EventOrderGenerator.GetNext()) - ); - return; - } - - await _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete: false); - } - - public async Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true) - where TEvent : class - { - await PublishAsync(typeof(TEvent), eventData, onUnitOfWorkComplete, useOutbox); + return _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete); } - - public async Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true) + + public Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true) where TEvent : class { - if (onUnitOfWorkComplete && UnitOfWorkManager.Current != null) - { - AddToUnitOfWork( - UnitOfWorkManager.Current, - new UnitOfWorkEventRecord(eventType, eventData, EventOrderGenerator.GetNext(), useOutbox) - ); - return; - } - - if (useOutbox && UnitOfWorkManager.Current != null) - { - UnitOfWorkManager.Current.OnCompleted(async() => { - await _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete: false); - }); - return; - } - - await _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete: false); + return _localEventBus.PublishAsync(eventData, onUnitOfWorkComplete); } - protected virtual void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord) + public Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true, bool useOutbox = true) { - unitOfWork.AddOrReplaceDistributedEvent(eventRecord); + return _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete); } -} +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs index 497503680d..c239df38c9 100644 --- a/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs +++ b/framework/test/Volo.Abp.EventBus.Tests/Volo/Abp/EventBus/Distributed/LocalDistributedEventBus_Test.cs @@ -1,9 +1,7 @@ using System; using System.Threading.Tasks; -using Shouldly; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.MultiTenancy; -using Volo.Abp.Uow; using Xunit; namespace Volo.Abp.EventBus.Distributed; @@ -51,7 +49,7 @@ public class LocalDistributedEventBus_Test : LocalDistributedEventBusTestBase public async Task Should_Get_TenantId_From_EventEto_Extra_Property() { var tenantId = Guid.NewGuid(); - + DistributedEventBus.Subscribe(GetRequiredService()); await DistributedEventBus.PublishAsync(new MySimpleEto @@ -61,71 +59,7 @@ public class LocalDistributedEventBus_Test : LocalDistributedEventBusTestBase {"TenantId", tenantId.ToString()} } }); - + Assert.Equal(tenantId, MySimpleDistributedSingleInstanceEventHandler.TenantId); } - - [Fact] - public async Task Event_Should_Published_On_UnitOfWorkComplete() - { - var id = 0; - DistributedEventBus.Subscribe(data => - { - id = data.Value; - return Task.CompletedTask; - }); - - var unitOfWorkManager = GetRequiredService(); - using (var uow = unitOfWorkManager.Begin()) - { - await DistributedEventBus.PublishAsync(new MySimpleEventData(3), onUnitOfWorkComplete: true, useOutbox: false); - } - id.ShouldBe(0); - - using (var uow = unitOfWorkManager.Begin()) - { - await DistributedEventBus.PublishAsync(new MySimpleEventData(3), onUnitOfWorkComplete: true, useOutbox: false); - await uow.CompleteAsync(); - } - id.ShouldBe(3); - - id = 0; - using (var uow = unitOfWorkManager.Begin()) - { - await DistributedEventBus.PublishAsync(new MySimpleEventData(3), onUnitOfWorkComplete: false, useOutbox: false); - } - id.ShouldBe(3); - } - - [Fact] - public async Task Event_Should_Published_On_UnitOfWorkComplete_UseOutbox() - { - var id = 0; - DistributedEventBus.Subscribe(data => - { - id = data.Value; - return Task.CompletedTask; - }); - - var unitOfWorkManager = GetRequiredService(); - using (var uow = unitOfWorkManager.Begin()) - { - await DistributedEventBus.PublishAsync(new MySimpleEventData(3), onUnitOfWorkComplete: false, useOutbox: true); - } - id.ShouldBe(0); - - using (var uow = unitOfWorkManager.Begin()) - { - await DistributedEventBus.PublishAsync(new MySimpleEventData(3), onUnitOfWorkComplete: false, useOutbox: true); - await uow.CompleteAsync(); - } - id.ShouldBe(3); - - id = 0; - using (var uow = unitOfWorkManager.Begin()) - { - await DistributedEventBus.PublishAsync(new MySimpleEventData(3), onUnitOfWorkComplete: false, useOutbox: false); - } - id.ShouldBe(3); - } } From 207f4c141cc9993cee52f005c26467c2252a534c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 27 Apr 2022 22:14:06 +0300 Subject: [PATCH 4/6] Removed Bootstrap-Modules.md --- docs/en/{ => _deleted}/Bootstrap-Modules.md | 0 docs/en/docs-nav.json | 4 ---- 2 files changed, 4 deletions(-) rename docs/en/{ => _deleted}/Bootstrap-Modules.md (100%) diff --git a/docs/en/Bootstrap-Modules.md b/docs/en/_deleted/Bootstrap-Modules.md similarity index 100% rename from docs/en/Bootstrap-Modules.md rename to docs/en/_deleted/Bootstrap-Modules.md diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 74ebc220c7..b2061920a8 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -426,10 +426,6 @@ "text": "Basics", "path": "Module-Development-Basics.md" }, - { - "text": "Bootstrap", - "path": "Bootstrap-Modules.md" - }, { "text": "Plug-In Modules", "path": "PlugIn-Modules.md" From d85abfcaba049b6c836b4bbfb8cd3a10d9a4aaf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 27 Apr 2022 22:16:45 +0300 Subject: [PATCH 5/6] Minor fixes in document: Getting-Started-AspNetCore-Application.md --- docs/en/Getting-Started-AspNetCore-Application.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/en/Getting-Started-AspNetCore-Application.md b/docs/en/Getting-Started-AspNetCore-Application.md index ef14fd0c54..0ccd900b1f 100644 --- a/docs/en/Getting-Started-AspNetCore-Application.md +++ b/docs/en/Getting-Started-AspNetCore-Application.md @@ -95,9 +95,9 @@ That's all! Run the application, it will just work as expected. ## Using Autofac as the Dependency Injection Framework -While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, [Autofac](https://autofac.org/) provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features. +While ASP.NET Core's Dependency Injection (DI) system is fine for basic requirements, [Autofac](https://autofac.org/) provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features. -Replacing AspNet Core's DI system by Autofac and integrating to ABP is pretty easy. +Replacing ASP.NET Core's DI system by Autofac and integrating to ABP is pretty easy. 1. Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) package @@ -131,10 +131,8 @@ var app = builder.Build(); await app.InitializeApplicationAsync(); await app.RunAsync(); - ```` ## Source Code Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp-samples/tree/master/BasicAspNetCoreApplication). - From 554960d59626fc355a67f063dc6d375e3fa23844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 27 Apr 2022 22:25:05 +0300 Subject: [PATCH 6/6] Revise the Module-Development-Basics.md document. --- docs/en/Module-Development-Basics.md | 41 ++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/docs/en/Module-Development-Basics.md b/docs/en/Module-Development-Basics.md index 17c0e91808..dd01f81ff4 100644 --- a/docs/en/Module-Development-Basics.md +++ b/docs/en/Module-Development-Basics.md @@ -59,13 +59,15 @@ public class BlogModule : AbpModule } ```` +> `ConfigureServices` method has an asynchronous version too: `ConfigureServicesAsync`. If you want to make asynchronous calls (use the `await` keyword) inside this method, override the asynchronous version instead of the synchronous one. If you override both asynchronous and synchronous versions, only the asynchronous version will be executed. + See the [Configuration](Configuration.md) document for more about the configuration system. #### Pre & Post Configure Services ``AbpModule`` class also defines ``PreConfigureServices`` and ``PostConfigureServices`` methods to override and write your code just before and just after ``ConfigureServices``. Notice that the code you have written into these methods will be executed before/after the ``ConfigureServices`` methods of all other modules. -> These methods have Async versions too, and if you want to make asynchronous calls inside these methods, override the asynchronous versions instead of the synchronous ones. +> These methods have asynchronous versions too. If you want to make asynchronous calls inside these methods, override the asynchronous versions instead of the synchronous ones. ### Application Initialization @@ -73,37 +75,48 @@ Once all the services of all modules are configured, the application starts by i #### OnApplicationInitialization Method -You can override ``OnApplicationInitialization`` method to execute code while application is being started. Example: +You can override ``OnApplicationInitialization`` method to execute code while application is being started. -> These methods have Async versions too, and if you want to make asynchronous calls inside these methods, override the asynchronous versions instead of the synchronous ones. +**Example:** ````C# public class BlogModule : AbpModule { - // Asynchronous methods call synchronous methods by default, You only need to implement one of them. - - public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + public override void OnApplicationInitialization( + ApplicationInitializationContext context) { var myService = context.ServiceProvider.GetService(); - await myService.DoSomethingAsync(); + myService.DoSomething(); } +} +```` - public override void OnApplicationInitialization(ApplicationInitializationContext context) +`OnApplicationInitialization` method has an asynchronous version too. If you want to make asynchronous calls (use the `await` keyword) inside this method, override the asynchronous version instead of the synchronous one. + +**Example:** + +````csharp +public class BlogModule : AbpModule +{ + public override Task OnApplicationInitializationAsync( + ApplicationInitializationContext context) { var myService = context.ServiceProvider.GetService(); - myService.DoSomething(); + await myService.DoSomethingAsync(); } } ```` -``OnApplicationInitialization`` is generally used by the startup module to construct the middleware pipeline for ASP.NET Core applications. Example: +> If you override both asynchronous and synchronous versions, only the asynchronous version will be executed. + +``OnApplicationInitialization`` is generally used by the startup module to construct the middleware pipeline for ASP.NET Core applications. + +**Example:** ````C# [DependsOn(typeof(AbpAspNetCoreMvcModule))] public class AppModule : AbpModule { - //... - public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); @@ -125,10 +138,14 @@ You can also perform startup logic if your module requires it ``AbpModule`` class also defines ``OnPreApplicationInitialization`` and ``OnPostApplicationInitialization`` methods to override and write your code just before and just after ``OnApplicationInitialization``. Notice that the code you have written into these methods will be executed before/after the ``OnApplicationInitialization`` methods of all other modules. +> These methods have asynchronous versions too, and if you want to make asynchronous calls inside these methods, override the asynchronous versions instead of the synchronous ones. + ### Application Shutdown Lastly, you can override ``OnApplicationShutdown`` method if you want to execute some code while application is being shutdown. +> This methods has asynchronous version too. If you want to make asynchronous calls inside this method, override the asynchronous version instead of the synchronous one. + ## Module Dependencies In a modular application, it's not unusual for one module to depend upon another module(s). An Abp module must declare ``[DependsOn]`` attribute if it does have a dependency upon another module, as shown below: