Browse Source

Merge remote-tracking branch 'origin/rel-5.3' into dev

pull/12521/head
Halil İbrahim Kalkan 4 years ago
parent
commit
15b9c9dfb1
  1. 258
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/POST.md
  2. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/app-nolayers-get-started.png
  3. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/community-talks-2022.4.png
  4. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/cover-53.png
  5. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/deployment-documentation.png
  6. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/gdpr-personal-data-page.png
  7. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/gdpr-user-menu.png
  8. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/leptonx-lite-documentations.png
  9. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/oauth-external-provider.gif
  10. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-new-question.png
  11. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-question-example.png
  12. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-questions.png
  13. BIN
      docs/en/Blog-Posts/2022-05-09 v5_3_Preview/webinar.png
  14. 3
      docs/en/CLI.md
  15. 2
      docs/en/Dependency-Injection.md
  16. 219
      docs/en/Distributed-Event-Bus.md
  17. 44
      docs/en/Local-Event-Bus.md

258
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/POST.md

@ -0,0 +1,258 @@
# ABP.IO Platform 5.3 RC Has Been Released
Today, we are happy to release the [ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) version **5.3 RC** (Release Candidate). This blog post introduces the new features and important changes in this new version.
> **The planned release date for the [5.3.0 Stable](https://github.com/abpframework/abp/milestone/69) version is May 31, 2022**.
Please try this version and provide feedback for a more stable ABP version 5.3! Thank you all.
## Get Started with the 5.3 RC
Follow the steps below to try version 5.3.0 RC today:
1) **Upgrade** the ABP CLI to version `5.3.0-rc.1` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 5.3.0-rc.1
````
**or install** it if you haven't before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 5.3.0-rc.1
````
2) Create a **new application** with the `--preview` option:
````bash
abp new BookStore --preview
````
See the [ABP CLI documentation](https://docs.abp.io/en/abp/latest/CLI) for all the available options.
> You can also use the *Direct Download* tab on the [Get Started](https://abp.io/get-started) page by selecting the **Preview checkbox**.
You can use any IDE that supports .NET 6.x, like **[Visual Studio 2022](https://visualstudio.microsoft.com/downloads/)**.
## Migration Notes
There is a change in this version that may effect your applications:
* Upgraded the [AutoMapper](https://github.com/AutoMapper/AutoMapper) library to **v11.0.1**. So, you need to change your project's target SDK that use the **AutoMapper** library (typically your `*.Application` project). You can change it from `netstandard2.0` to `netstandard2.1` or `net6` if needed. You can write to [#12189](https://github.com/abpframework/abp/pull/12189) if you need any help.
## What's New with ABP Framework 5.3?
In this section, I will introduce some major features released with this version. Here is a brief list of titles explained in the next sections:
* Single-layer option added to the [*Get Started*](https://abp.io/get-started) page
* PWA Support for Startup Templates
* Introduced the `Volo.Abp.Gdpr.Abstractions` package
* Batch Publish Events from Outbox to the Event Bus
* Improvements on **eShopOnAbp** Project & E-Book Announcement
* LeptonX Lite Documentations & Project Status & Roadmap
* OpenIddict Module & Keycloack Integration
* Deployment Documentations
* Other News
### Single-layer Option on *Get Started* Page
We've created a new startup template named `app-nolayers` and [announced](https://blog.abp.io/abp/ABP.IO-Platform-5-2-RC-Has-Been-Published) it in the previous version. In this version, we've also added this startup template option to the *Get Started* page.
*You can examine the screenshot below to see how to create an `app-nolayers` template from the ["Get Started"](https://abp.io/get-started) page:*
![](./app-nolayers-get-started.png)
### PWA Support for Startup Templates
ABP v5.3 application startup template now supports PWA for Blazor WASM & Angular UIs. To create a startup template with the PWA support, you can use the `--pwa` parameter.
Example:
```bash
abp new MyProgressiveWebApp -t app -u blazor --pwa
```
### Introducing the `Volo.Abp.Gdpr.Abstractions` Package
A new `Volo.Abp.Gdpr.Abstractions` package has been added to the framework. This is an abstraction package, so doesn't contain any actual GDPR implementation. It defines some classes and interfaces to put a standard for who want to implement a GDPR module that can run in a modular or microservice system.
At that point, we are introducing the **GDPR Module** for the ABP Commercial customers and this module does the GDPR-related operations on behalf of you, such as *"Download/Delete Personal Data"*. I'll describe the **GDPR Module** later in this blog post.
> Please see the **GDPR Module** section below to learn more about this module.
### Batch Publish Events from Outbox to the Event Bus
We introduced the "Transactional Outbox & Inbox Patterns" in [**ABP v5.0**](https://blog.abp.io/abp/ABP-IO-Platform-5.0-RC-1-Has-Been-Released), it was one of the most awaited features by several software developers.
We've made some optimizations for the **Batch Event Publishing** in this version, you can examine the related development from [here](https://github.com/abpframework/abp/pull/11243). After the optimization, the results are impressive. It is enabled by default (if you have configured [event outbox](https://docs.abp.io/en/abp/latest/Distributed-Event-Bus#outbox-inbox-for-transactional-events)), so you don't need to any manual configuration.
### Improvements on eShopOnAbp Project & E-Book Announcement
There are some developments on the [eShopOnAbp project](https://github.com/abpframework/eShopOnAbp) made in this version. You can see the brief descriptions of some of the improvements below:
* Local certificates have been created to use while working in Kubernetes and also Helm Charts have been updated. See [#107](https://github.com/abpframework/eShopOnAbp/pull/107).
* The Order Management page has been created. See [#92](https://github.com/abpframework/eShopOnAbp/pull/92).
* Database migration event handlers have been removed and "Distributed Locking" is now used for database migrations. See [#85](https://github.com/abpframework/eShopOnAbp/pull/85) and [#102](https://github.com/abpframework/eShopOnAbp/pull/102).
* Switched from Ocelot to YARP as the gateway. See [#97](https://github.com/abpframework/eShopOnAbp/pull/97).
We have exciting news to share with the community, we're working on an "ABP Microservice Development" e-book. In this book, we're using the eShopOnAbp project as a reference microservice solution and we're trying to explain our experiences during the microservice application development process through this project.
We're planning to create this book in nine chapters and make it available after the third chapter is written. After that, you will be able to download this free e-book from the [abp.io](https://abp.io/) website.
### LeptonX Lite Documentations & Project Status & Roadmap
It is finally here, we've released the **1.0.0-beta.1** version for the **LeptonX Lite**.
![](./leptonx-lite-documentations.png)
Lepton X Lite documents have been written for the three UI types within this version. You can see the related documentation from the screenshot above. You can follow these documents and try the new **LeptonX Lite Theme**.
We don't suggest using the **beta.1** version on production, we highly demand you to test **LeptonX Lite** and provide feedback to us. It's really important for us to be able to release a more stable version. Thanks in advance.
For the following versions (beta.2 and RC versions), we will focus on:
* Fixing the reported bugs from the community
* Providing documentations as much as possible
* Adding new custom pages to the demo
### OpenIddict Module & Keycloack Integration
We have [announced the plan of replacing the IdentityServer](https://github.com/abpframework/abp/issues/11989). ABP currently uses **IdentityServer4** to add **OAuth** features as built-in on the server-side. However, since *IdentityServer4's support ends at the end of the year 2022*. Its replacement is Duende IdentityServer, which is not a free software anymore. (see [more](https://blog.duendesoftware.com/posts/20220111_fair_trade/))
Therefore, we've decided to completely drop the **IdentityServer4** from the ABP platform and implement the [OpenIddict](https://github.com/openiddict/openiddict-core) and install onto the startup templates.
We've implemented both open source and commercial OpenIddict modules, we plan to remove Identity Server and replace it with OpenIddict for template projects in **ABP v5.4**. Please check [#12084](https://github.com/abpframework/abp/pull/12084) to see the development made on the open-source side.
We're creating the documentation for the OpenIddict Module, if you want to have general knowledge about this module, you can check the documentation from [here](https://github.com/abpframework/abp/blob/dev/docs/en/Modules/OpenIddict.md). Currently, this is a draft documentation but it gives overall knowledge about the OpenIddict Module, we'll complete this documentation in ABP v5.4 and you'll be able to read it completely.
Currently, we are also working on Keycloak integration possibilities in parallel to the OpenIddict integration research and we've prepared some samples that you can examine. You can see [#154](https://github.com/abpframework/abp-samples/pull/154) and [#158](https://github.com/abpframework/abp-samples/pull/158).
### Deployment Documentations
Deploying an ABP-based application is not so different than deploying any .NET or ASP.NET Core application. You can deploy it to a cloud provider (e.g. Azure, AWS, Google Could) or on-premise server, IIS or any other web server. However, we wanted to prepare a "Deployment Guide" to mention the important points and considerations.
![](./deployment-documentation.png)
In the [Deploying to a Clustered Environment](https://docs.abp.io/en/abp/5.3/Deployment/Clustered-Environment) documentation, we've documented the topics that you should consider when you are developing your application to a clustered environment and explained how you can deal with these topics in your ABP-based application.
### Other News
* Global Features were only accessible from the C# code. From this version and on, Global Features can be also provided from application configurations. See [#12043](https://github.com/abpframework/abp/pull/12043).
* Getting the user's detailed information (name, surname and phone number) from external login. See [#12085](https://github.com/abpframework/abp/pull/12085).
* Date Pipes for Angular. See [#11909](https://github.com/abpframework/abp/issues/11909).
If you want to see more details, you can check [the release on GitHub](https://github.com/abpframework/abp/releases/tag/5.3.0-rc.1), which contains a list of all the issues and pull requests closed with this version.
## What's New with ABP Commercial 5.3?
### GDPR Module
> **GDPR (General Data Protection Regulation)** is a regulation in EU law on data protection and known as the toughest privacy and security law in the world. GDPR applies to any organization operating within the EU, as well as any organizations outside of the EU which offer goods or services to customers or businesses in the EU.
With this version, we are introducing the new **GDPR Module**. This was one of the most awaited features, so we've prioritized it and implemented it in this version.
The GDPR Module is pre-installed in the [startup templates](https://docs.abp.io/en/commercial/5.3/startup-templates/index) for MVC. So, no need to manually install it. When you create a new startup template, you can directly use this module. We'll also implement this module for the other UI types as soon as possible and also add extra functionality such as "Cookie Consent" and more.
Currently, there are two main functions of this module and they are "Download Personal Data" and "Delete Personal Data".
![](./gdpr-user-menu.png)
There is a "Personal Data" section in the user menu as in the screenshot above and when you click on this section, you'll be redirected to the "Personal Data" page. On that page, you can either request to "Download Personal Data" or "Delete Personal Data".
![](./gdpr-personal-data-page.png)
After you've requested to download "Personal Data", you need to wait for 1 hour by default (you can configure the related option). Because the GDPR module is developed by considering the distributed systems and therefore a specific time should be passed to ensure all the published events are handled and all personal data is collected.
### CMS Kit Pro - Polling Feature
We've added a **Polling** feature to the **CMS Kit Pro** module. This feature allows you to use a questionnaire/voting system in your application easily. You can create a question, define some options for it and the poll will be created for you. You can see the example poll in the screenshot below:
![](./poll-question-example.png)
Also, there is an admin side of the Polling Feature. You can easily manage your polls in your admin (back-office) project. You can create, update, delete and show the results of the poll on the Polls page:
![](./poll-questions.png)
### OAuth Resource Owner Password as External Login Provider
> The Resource Owner Password flow allows for the exchanging of the username and password of a user for an access token. When using the resource owner password credentials grant, the user provides the credentials (username and password) directly to the application.
Now, you can login by entering a username and password from an OAuth server.
Example: Use OAuth external login provider with Keycloak:
![](./oauth-external-provider.gif)
### Suite New Features & Enhancements
In this version, there are some enhancements and new features in **Suite** and they are listed briefly below:
* It's now possible to create an **app-nolayers (Application - single layer)** template via Suite and also code-generation is supported for the **app-nolayers** template with this version.
* Suite now allows users to see and download its logs.
* Suite now allows generating code via CLI. If you have a JSON file that contains code blocks, like entity configurations, you can use the `abp suite generate` command to generate CRUD pages based on it.
Example:
```bash
abp suite generate -e C:\Users\.suite\entities\Country.json -s C:\Users\my-proj\SuiteProj\SuiteProj.sln
```
### Suite Webinar: Take a closer look at the code generation
![](./webinar.png)
We've organized a webinar for Suite and in this webinar, we've talked about ABP Suite's capabilities, important features and more...
You can watch the event from [here](https://www.youtube.com/watch?v=RFArBh60RSA&t=3s), if you haven't watched it yet.
### Docker Compose Configurations for Single Layer Startup Template
Dockerfiles, docker-compose files and build script files have been added to the Single Layer Startup Template (app-nolayers) with this version.
And this way, applications created with this template now can be deployed more easily.
### Microservice Solution Enhancements
There are some enhancements made in the Microservice Solution. You can see the list of these enhancements:
* Initial migration on the template has been updated with the small improvement that was made in the **Language Management** module.
* Database migration event handlers have been removed and "Distributed Locking" is now used for the database migrations.
### PWA Support for the Application Pro Template
Application Pro template also supports the PWA for Blazor WASM & Angular UIS. To create a startup template with the PWA support, you can use the `--pwa` parameter.
Example:
```bash
abp new MyProgressiveWebApp -t app-pro -u blazor --pwa
```
## Community News
### New ABP Community Posts
* [Anto Subash](https://twitter.com/antosubash) created a series named ["Microservice with ABP"](https://blog.antosubash.com/posts/abp-microservice-series) and shared a couple of video posts about the ABP Microservice solution.
* [Francisco Kadzi](https://github.com/CiscoNinja) has created his first ABP Community article that shows how to ["Customize ABP Angular Application UI with AdminLTE"](https://community.abp.io/posts/customize-abp-angular-application-ui-with-adminlte.-7qu1m67s).
* [Jack Fistelmann](https://github.com/nebula2) has created an article to introduce a helpful project extension to speed up development on Visual Studio. You can read the article [here](https://community.abp.io/posts/using-switch-startup-project-extension-for-visual-studio-52yyw27v).
* [Jack Fistelmann](https://github.com/nebula2) has also created an article to show how you can generate PDF files with the `Sycyber.Core` package in ABP-based applications. You can read it [here](https://community.abp.io/posts/generate-pdfs-in-an-abp-framework-project-using-scryber.core-x9yh1vfa).
* [Halil Ibrahim Kalkan](https://twitter.com/hibrahimkalkan) has created an article to show ["Dealing with Multiple Implementations of a Service in ASP.NET Core & ABP Dependency Injection"](https://community.abp.io/posts/dealing-with-multiple-implementations-of-a-service-in-asp.net-core-abp-dependency-injection-ysfp4ho2) with examples.
* [Manoj Kumar](https://community.abp.io/members/manojkumar.t@shloklabs.com) submitted a new article about how to use "ABP authentication in a Flutter application". It was a frequently asked topic, which you can read [here](https://community.abp.io/posts/flutter-web-authentication-from-abp-mp6l2ehx).
* [Engincan Veske](https://twitter.com/EngincanVeske) created a new Community Article to show "Concurrency Check/Control in ABP". You can read it [here](https://community.abp.io/posts/handle-concurrency-with-ef-core-in-an-abp-framework-project-with-asp.net-core-mvc-jlkc3w8f).
### ABP Community Talks 2022.4: How can you contribute to the open source ABP Framework? (May 10, 2022 - 17:00 UTC)
![](./community-talks-2022.4.png)
We've [asked you to pick the topic of the next Community Talks](https://twitter.com/abpframework/status/1514567683072745474?s=20&t=rJfHrB3DYDNsk2EXS8zBBQ) and you've chosen the "How to contribute to open source ABP Framework?" for the next talk topic. So, in this Community Talk, we will be talking about "How to contribute to ABP Framework" with one of the top contributors of the ABP Framework, [Ismail Yılmaz](https://github.com/iyilm4z). The event will be on **May 10, 2022, at 17:00 (UTC)** on YouTube.
> You can register for the event from [here](https://kommunity.com/volosoft/events/abp-community-talks-20224-how-to-contribute-to-the-open-source-abp-framework-d9b50664), if you haven't registered yet.
You can also [subscribe to the Volosoft channel](https://www.youtube.com/channel/UCO3XKlpvq8CA5MQNVS6b3dQ) to be informed about future ABP events and videos.
### Discord Server
We've created an official ABP Discord server so the ABP Community can interact with each other and created a blog-post to introduce it. You can read the [ABP Discord Server announcement post](https://blog.abp.io/abp/Official-ABP-Discord-Server-is-Here) to learn more about the ABP Discord Server.
Thanks to the ABP Community, **700+** people joined our Discord Server so far and it grows every day.
You can join our Discord Server from [here](https://discord.gg/abp), if you haven't yet.

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/app-nolayers-get-started.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/community-talks-2022.4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/cover-53.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/deployment-documentation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/gdpr-personal-data-page.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/gdpr-user-menu.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/leptonx-lite-documentations.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/oauth-external-provider.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-new-question.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-question-example.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/poll-questions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
docs/en/Blog-Posts/2022-05-09 v5_3_Preview/webinar.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

3
docs/en/CLI.md

@ -92,8 +92,10 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--tiered`: Creates a tiered solution where Web and Http API layers are physically separated. If not specified, it creates a layered solution which is less complex and suitable for most scenarios.
* `angular`: Angular UI. There are some additional options for this template:
* `--separate-identity-server`: The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side.
* `--pwa`: Specifies the project as Progressive Web Application.
* `blazor`: Blazor UI. There are some additional options for this template:
* `--separate-identity-server`The Identity Server project comes as a separate project and runs at a different endpoint. It separates the Identity Server from the API Host application. If not specified, you will have a single endpoint in the server side.
* `--pwa`: Specifies the project as Progressive Web Application.
* `blazor-server`: Blazor Server UI. There are some additional options for this template:
* `--tiered`: The Identity Server and the API Host project comes as separate projects and run at different endpoints. It has 3 startup projects: *HttpApi.Host*, *IdentityServer* and *Blazor* and and each runs on different endpoints. If not specified, you will have a single endpoint for your web project.
* `none`: Without UI. No front-end layer will be created. There are some additional options for this template:
@ -115,7 +117,6 @@ For more samples, go to [ABP CLI Create Solution Samples](CLI-New-Command-Sample
* `--database-provider` or `-d`: Specifies the database provider. Default provider is `ef`. Available providers:
* `ef`: Entity Framework Core.
* `mongodb`: MongoDB.
* `--pwa`: Specifies to Configure Angular or Blazor WebAssembly project as Progressive Web Application.
* `--output-folder` or `-o`: Specifies the output folder. Default value is the current directory.
* `--version` or `-v`: Specifies the ABP & template version. It can be a [release tag](https://github.com/abpframework/abp/releases) or a [branch name](https://github.com/abpframework/abp/branches). Uses the latest release if not specified. Most of the times, you will want to use the latest version.
* `--preview`: Use latest preview version.

2
docs/en/Dependency-Injection.md

@ -131,7 +131,7 @@ public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransie
If you do not specify which services to expose, ABP expose services by convention. So taking the ``TaxCalculator`` defined above:
* The class itself is exposed by default. That means you can inject it by ``TaxCalculator`` class.
* Default interfaces are exposed by default. Default interfaces are determined by naming convention. In this example, ``ICalculator`` and ``ITaxCalculator`` are default interfaces of ``TaxCalculator``, but ``ICanCalculate`` is not.
* Default interfaces are exposed by default. Default interfaces are determined by naming convention. In this example, ``ICalculator`` and ``ITaxCalculator`` are default interfaces of ``TaxCalculator``, but ``ICanCalculate`` is not. A generic interface (e.g. `ICalculator<string>`) is also considered as a default interface if the naming convention is satisfied.
### Combining All Together

219
docs/en/Distributed-Event-Bus.md

@ -20,7 +20,7 @@ For example, [pre-built application modules](Modules/Index.md) is designed to wo
There are two ways of publishing distributed events explained in the following sections.
### IDistributedEventBus
### Using IDistributedEventBus to Publish Events
`IDistributedEventBus` can be [injected](Dependency-Injection.md) and used to publish a distributed event.
@ -57,7 +57,7 @@ namespace AbpDemo
}
````
`PublishAsync` method gets a single parameter: the event object, which is responsible to hold the data related to the event. It is a simple plain class:
`PublishAsync` method gets the event object, which is responsible to hold the data related to the event. It is a simple plain class:
````csharp
using System;
@ -80,15 +80,15 @@ Even if you don't need to transfer any data, you need to create a class (which i
#### Event Name
`EventName` attribute is optional, but suggested. If you don't declare it, the event name will be the full name of the event class, `AbpDemo.StockCountChangedEto` in this case.
`EventName` attribute is optional, but suggested. If you don't declare it for an event type (ETO class), the event name will be the full name of the event class, `AbpDemo.StockCountChangedEto` in this case.
#### About Serialization for the Event Objects
Event transfer objects **must be serializable** since they will be serialized/deserialized to JSON or other format when it is transferred to out of the process.
Event transfer objects (ETOs) **must be serializable** since they will be serialized/deserialized to JSON or other format when it is transferred to out of the process.
Avoid circular references, polymorphism, private setters and provide default (empty) constructors if you have any other constructor as a good practice (while some serializers may tolerate it), just like the DTOs.
### Inside Entity / Aggregate Root Classes
### Publishing Events Inside Entity / Aggregate Root Classes
[Entities](Entities.md) can not inject services via dependency injection, but it is very common to publish distributed events inside entity / aggregate root classes.
@ -294,4 +294,211 @@ This example;
* Adds a selector to allow to publish the create, update and delete events for the `Product` entity.
* Configure to use the `ProductEto` as the event transfer object to publish for the `Product` related events.
> Distributed event system use the [object to object mapping](Object-To-Object-Mapping.md) system to map `Product` objects to `ProductEto` objects. So, you need to configure the object mapping (`Product` -> `ProductEto`) too. You can check the [object to object mapping document](Object-To-Object-Mapping.md) to learn how to do it.
> Distributed event system use the [object to object mapping](Object-To-Object-Mapping.md) system to map `Product` objects to `ProductEto` objects. So, you need to configure the object mapping (`Product` -> `ProductEto`) too. You can check the [object to object mapping document](Object-To-Object-Mapping.md) to learn how to do it.
## Transaction and Exception Handling
Distributed event bus works in-process (since default implementation is `LocalDistributedEventBus`) unless you configure an actual provider (e.g. [Kafka](Distributed-Event-Bus-Kafka-Integration.md) or [Redis](Distributed-Event-Bus-RabbitMQ-Integration.md)). In-process event bus always executes event handlers in the same [unit of work](Unit-Of-Work.md) scope that you publishes the events in. That means, if an event handler throws an exception, then the related unit of work (the database transaction) is rolled back. In this way, your application logic and event handling logic becomes transactional (atomic) and consistent. If you want to ignore errors in an event handler, you must use a `try-catch` block in your handler and shouldn't re-throw the exception.
When you switch to an actual distributed event bus provider (e.g. [Kafka](Distributed-Event-Bus-Kafka-Integration.md) or [Redis](Distributed-Event-Bus-RabbitMQ-Integration.md)), then the event handlers will be executed in different processes/applications as their purpose is to create distributed systems. In this case, the only way to implement transactional event publishing is to use the outbox/inbox patterns as explained in the *Outbox / Inbox for Transactional Events* section.
If you don't configure outbox/inbox pattern or use the `LocalDistributedEventBus`, then events are published at the end of the unit of work by default, just before the unit of work is completed (that means throwing exception in an event handler still rollbacks the unit of work), even if you publish them in the middle of unit of work. If you want to immediately publish the event, you can set `onUnitOfWorkComplete` to `false` while using `IDistributedEventBus.PublishAsync` method.
> Keeping the default behavior is recommended unless you don't have a unique requirement. `onUnitOfWorkComplete` option is not available when you publish events inside entity / aggregate root classes (see the *Publishing Events Inside Entity / Aggregate Root Classes* section).
## Outbox / Inbox for Transactional Events
The **[transactional outbox pattern](https://microservices.io/patterns/data/transactional-outbox.html)** is used to publishing distributed events within the **same transaction** that manipulates the application's database. When you enable outbox, distributed events are saved into the database inside the same transaction with your data changes, then sent to the actual message broker by a separate [background worker](Background-Workers.md) with a re-try system. In this way, it ensures the consistency between your database state and the published events.
The **transactional inbox pattern**, on the other hand, saves incoming events into database first. Then (in a [background worker](Background-Workers.md)) executes the event handler in a transactional manner and removes the event from the inbox queue in the same transaction. It ensures that the event is only executed one time by keeping the processed messages for a while and discarding the duplicate events received from the message broker.
Enabling the event outbox and inbox systems require a few manual steps for your application. Please apply the instructions in the following sections to make them running.
> Outbox and Inbox can be separately enabled and configured, so you may only use one of them if you want.
### Pre-requirements
* The outbox/inbox system uses the distributed lock system to handle concurrency when you run multiple instances of your application/service. So, you should **configure the distributed lock system** with one of the providers as [explained in this document](Distributed-Locking.md).
* The outbox/inbox system supports [Entity Framework Core](Entity-Framework-Core.md) (EF Core) and [MongoDB](MongoDB.md) **database providers** out of the box. So, your applications should use one of these database providers. For other database providers, see the *Implementing a Custom Database Provider* section.
> If you are using MongoDB, be sure that you enabled multi-document database transactions that was introduced in MongoDB version 4.0. See the *Transactions* section of the [MongoDB](MongoDB.md) document.
### Enabling event outbox
Open your `DbContext` class (EF Core or MongoDB), implement the `IHasEventOutbox` interface. You should end up by adding a `DbSet` property into your `DbContext` class:
```csharp
public DbSet<OutgoingEventRecord> OutgoingEvents { get; set; }
```
Add the following lines inside the `OnModelCreating` method of your `DbContext` class (only for EF Core):
```csharp
builder.ConfigureEventOutbox();
```
For EF Core, use the standard `Add-Migration` and `Update-Database` commands to apply changes into your database (you can skip this step for MongoDB). If you want to use the command-line terminal, run the following commands in the root directory of the database integration project:
```bash
dotnet ef migrations add "Added_Event_Outbox"
dotnet ef database update
```
Finally, write the following configuration code inside the `ConfigureServices` method of your [module class](Module-Development-Basics.md) (replace `YourDbContext` with your own `DbContext` class):
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure(config =>
{
config.UseDbContext<YourDbContext>();
});
});
````
### Enabling event inbox
Open your `DbContext` class (EF Core or MongoDB), implement the `IHasEventInbox` interface. You should end up by adding a `DbSet` property into your `DbContext` class:
```csharp
public DbSet<IncomingEventRecord> IncomingEvents { get; set; }
```
Add the following lines inside the `OnModelCreating` method of your `DbContext` class (only for EF Core):
```csharp
builder.ConfigureEventInbox();
```
For EF Core, use the standard `Add-Migration` and `Update-Database` commands to apply changes into your database (you can skip this step for MongoDB). If you want to use the command-line terminal, run the following commands in the root directory of the database integration project:
```bash
dotnet ef migrations add "Added_Event_Inbox"
dotnet ef database update
```
Finally, write the following configuration code inside the `ConfigureServices` method of your [module class](Module-Development-Basics.md) (replace `YourDbContext` with your own `DbContext` class):
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Inboxes.Configure(config =>
{
config.UseDbContext<YourDbContext>();
});
});
````
### Additional Configuration
> The default configuration will be enough for most cases. However, there are some options you may want to set for outbox and inbox.
#### Outbox configuration
Remember how outboxes are configured:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure(config =>
{
// TODO: Set options
});
});
````
Here, the following properties are available on the `config` object:
* `IsSendingEnabled` (default: `true`): You can set to `false` to disable sending outbox events to the actual event bus. If you disable this, events can still be added to outbox, but not sent. This can be helpful if you have multiple applications (or application instances) writing to outbox, but use one of them to send the events.
* `Selector`: A predicate to filter the event (ETO) types to be used for this configuration. Should return `true` to select the event. It selects all the events by default. This is especially useful if you want to ignore some ETO types from the outbox, or want to define named outbox configurations and group events within these configurations. See the *Named Configurations* section.
* `ImplementationType`: Type of the class that implements the database operations for the outbox. This is normally set when you call `UseDbContext` as shown before. See *Implementing a Custom Outbox/Inbox Database Provider* section for advanced usages.
#### Inbox configuration
Remember how inboxes are configured:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Inboxes.Configure(config =>
{
// TODO: Set options
});
});
````
Here, the following properties are available on the `config` object:
* `IsProcessingEnabled` (default: `true`): You can set to `false` to disable processing (handling) events in the inbox. If you disable this, events can still be received, but not executed. This can be helpful if you have multiple applications (or application instances), but use one of them to execute the event handlers.
* `EventSelector`: A predicate to filter the event (ETO) types to be used for this configuration. This is especially useful if you want to ignore some ETO types from the inbox, or want to define named inbox configurations and group events within these configurations. See the *Named Configurations* section.
* `HandlerSelector`: A predicate to filter the event handled types (classes implementing the `IDistributedEventHandler<TEvent>` interface) to be used for this configuration. This is especially useful if you want to ignore some event handler types from inbox processing, or want to define named inbox configurations and group event handlers within these configurations. See the *Named Configurations* section.
* `ImplementationType`: Type of the class that implements the database operations for the inbox. This is normally set when you call `UseDbContext` as shown before. See *Implementing a Custom Outbox/Inbox Database Provider* section for advanced usages.
### Skipping Outbox
`IDistributedEventBus.PublishAsync` method provides an optional parameter, `useOutbox`, which is set to `true` by default. If you bypass outbox and immediately publish an event, you can set it to `false` for a specific event publishing operation.
### Advanced Topics
#### Named Configurations
> All the concepts explained in this section is also valid for inbox configurations. We will show examples only for outbox to keep the document shorter.
See the following outbox configuration code:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure(config =>
{
//TODO
});
});
````
This is equivalent of the following code:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure("Default", config =>
{
//TODO
});
});
````
`Default` is this code indicates the configuration name. If you don't specify it (like in the previous code block), `Default` is used as the configuration name.
That means you can define more than one configuration for outbox (also for inbox) with different names. ABP runs all the configured outboxes.
Multiple outboxes can be needed if your application have more than one database and you want to run different outbox queues for different databases. In this case, you can use the `Selector` option to decide the events should be handled by an outbox. See the *Additional Configurations* section above.
#### Implementing a Custom Outbox/Inbox Database Provider
If your application or service is using a database provider other than [EF Core](Entity-Framework-Core.md) and [MongoDB](MongoDB.md), you should manually integrate outbox/inbox system with your database provider.
> Outbox and Inbox table/data must be stored in the same database with your application's data (since we want to create a single database transaction that includes application's database operations and outbox/inbox table operations). Otherwise, you should care about distributed (multi-database) transaction support which is not provided by most of the vendors and may require additional configuration.
ABP provides `IEventOutbox` and `IEventInbox` abstractions as extension point for the outbox/inbox system. You can create classes by implementing these interfaces and register them to [dependency injection](Dependency-Injection.md).
Once you implement your custom event boxes, you can configure `AbpDistributedEventBusOptions` to use your event box classes:
````csharp
Configure<AbpDistributedEventBusOptions>(options =>
{
options.Outboxes.Configure(config =>
{
config.ImplementationType = typeof(MyOutbox); //Your Outbox class
});
options.Inboxes.Configure(config =>
{
config.ImplementationType = typeof(MyInbox); //Your Inbox class
});
});
````
## See Also
* [Local Event Bus](Local-Event-Bus.md)

44
docs/en/Local-Event-Bus.md

@ -6,7 +6,7 @@ The Local Event Bus allows services to publish and subscribe to **in-process eve
There are two ways of publishing local events explained in the following sections.
### ILocalEventBus
### Publishing Events Using the ILocalEventBus
`ILocalEventBus` can be [injected](Dependency-Injection.md) and used to publish a local event.
@ -64,7 +64,7 @@ namespace AbpDemo
Even if you don't need to transfer any data, you need to create a class (which is an empty class in this case).
### Inside Entity / Aggregate Root Classes
### Publishing Events Inside Entity / Aggregate Root Classes
[Entities](Entities.md) can not inject services via dependency injection, but it is very common to publish local events inside entity / aggregate root classes.
@ -109,7 +109,7 @@ namespace AbpDemo
`AggregateRoot` class defines the `AddLocalEvent` to add a new local event, that is published when the aggregate root object is saved (created, updated or deleted) into the database.
> If an entity publishes such an event, it is a good practice to change the related properties in a controlled manner, just like the example above - `StockCount` can only be changed by the `ChangeStockCount` method which guarantees publishing the event.
> Tip: If an entity publishes such an event, it is a good practice to change the related properties in a controlled manner, just like the example above - `StockCount` can only be changed by the `ChangeStockCount` method which guarantees publishing the event.
#### IGeneratesDomainEvents Interface
@ -149,10 +149,10 @@ namespace AbpDemo
}
````
That's all. `MyHandler` is **automatically discovered** by the ABP Framework and `HandleEventAsync` is called whenever a `StockCountChangedEvent` occurs. You can inject any service and perform any required logic here.
That's all. `MyHandler` is **automatically discovered** by the ABP Framework and `HandleEventAsync` is called whenever a `StockCountChangedEvent` occurs. You can inject any service and perform any required logic in your handler class.
* **Zero or more handlers** can subscribe to the same event.
* A single event handler class can **subscribe to multiple events** but implementing the `ILocalEventHandler<TEvent>` interface for each event type.
* **One or more handlers** can subscribe to the same event.
* A single event handler class can **subscribe to multiple events** by implementing the `ILocalEventHandler<TEvent>` interface for each event type.
If you perform **database operations** and use the [repositories](Repositories.md) inside the event handler, you may need to create a [unit of work](Unit-Of-Work.md), because some repository methods need to work inside an **active unit of work**. Make the handle method `virtual` and add a `[UnitOfWork]` attribute for the method, or manually use the `IUnitOfWorkManager` to create a unit of work scope.
@ -160,10 +160,11 @@ If you perform **database operations** and use the [repositories](Repositories.m
### Transaction & Exception Behavior
When an event published, subscribed event handlers are immediately executed. So;
Event handlers are always executed in the same [unit of work](Unit-Of-Work.md) scope, that means in the same database transaction with the code that published the event. If an event handler throws an exception, the unit of work (database transaction) is rolled back. So, **use try-catch yourself** in the event handler if you want to hide the error.
* If a handler **throws an exception**, it effects the code that published the event. That means it gets the exception on the `PublishAsync` call. So, **use try-catch yourself** in the event handler if you want to hide the error.
* If the event publishing code is being executed inside a [Unit Of Work](Unit-Of-Work.md) scope, the event handlers also covered by the unit of work. That means if your UOW is transactional and a handler throws an exception, the transaction is rolled back.
When you call `ILocalEventBus.PublishAsync`, the event handlers are not immediately executed. Instead, they are executed just before the current unit of work completed (an unhandled exception in the handler still rollbacks the current unit of work). If you want to immediately execute the handlers, set the optional `onUnitOfWorkComplete` parameter to `false`.
> Keeping the default behavior is recommended unless you don't have a unique requirement. `onUnitOfWorkComplete` option is not available when you publish events inside entity / aggregate root classes (see the *Publishing Events Inside Entity / Aggregate Root Classes* section).
## Pre-Built Events
@ -195,35 +196,22 @@ namespace AbpDemo
}
````
This class subscribes to the `EntityCreatedEventData<IdentityUser>`, which is published just after a user was created. You may want to send a "Welcome" email to the new user.
There are two types of these events: events with past tense and events with continuous tense.
### Events with Past Tense
This class subscribes to the `EntityCreatedEventData<IdentityUser>`, which is published just after a user was created (but before the current transaction is completed). For example, you may want to send a "Welcome" email to the new user.
Events with past tense are published when the related unit of work completed and the entity change successfully saved to the database. If you throw an exception on these event handlers, it **can not rollback** the transaction since it was already committed.
The event types are;
The pre-built event types are;
* `EntityCreatedEventData<T>` is published just after an entity was successfully created.
* `EntityUpdatedEventData<T>` is published just after an entity was successfully updated.
* `EntityDeletedEventData<T>` is published just after an entity was successfully deleted.
* `EntityChangedEventData<T>` is published just after an entity was successfully created, updated or deleted. It can be a shortcut if you need to listen any type of change - instead of subscribing to the individual events.
### Events with Continuous Tense
Events with continuous tense are published before completing the transaction (if database transaction is supported by the database provider being used). If you throw an exception on these event handlers, it **can rollback** the transaction since it is not completed yet and the change is not saved to the database.
The event types are;
* `EntityCreatingEventData<T>` is published just before saving a new entity to the database.
* `EntityUpdatingEventData<T>` is published just before an existing entity is being updated.
* `EntityDeletingEventData<T>` is published just before an entity is being deleted.
* `EntityChangingEventData<T>` is published just before an entity is being created, updated or deleted. It can be a shortcut if you need to listen any type of change - instead of subscribing to the individual events.
#### How It Was Implemented?
Pre-build events are published when you save changes to the database;
* For EF Core, they are published on `DbContext.SaveChanges`.
* For MongoDB, they are published when you call repository's `InsertAsync`, `UpdateAsync` or `DeleteAsync` methods (since MongoDB has not a change tracking system).
## See Also
* [Distributed Event Bus](Distributed-Event-Bus.md)

Loading…
Cancel
Save