From 6e7667ffd69483b93a3b5e5174d556a3a4a2e080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 13 Apr 2022 14:55:41 +0300 Subject: [PATCH] Revised the distributed event documents --- ...-Application-Modules-Extending-Entities.md | 59 +++---------------- docs/en/Distributed-Event-Bus.md | 40 +++++-------- 2 files changed, 25 insertions(+), 74 deletions(-) diff --git a/docs/en/Customizing-Application-Modules-Extending-Entities.md b/docs/en/Customizing-Application-Modules-Extending-Entities.md index e1cb02e849..a3c9ae4e9a 100644 --- a/docs/en/Customizing-Application-Modules-Extending-Entities.md +++ b/docs/en/Customizing-Application-Modules-Extending-Entities.md @@ -109,68 +109,27 @@ public class MyLocalIdentityUserChangeEventHandler : [Distributed Event Bus](Distributed-Event-Bus.md) system is a way to publish an event in one application and receive the event in the same or different application running on the same or different server. -Assume that you want to get informed when a `IdentityUser` entity created, updated or deleted. You can create a class like below: +Assume that you want to get informed when `Tenant` entity (of the [Tenant Management](Modules/Tenant-Management.md) module) has created. In this case, you can subscribe to the `EntityCreatedEto` event as shown in the following example: ````csharp -public class MyDistributedIdentityUserChangeEventHandler : - IDistributedEventHandler>, - IDistributedEventHandler>, - IDistributedEventHandler>, +public class MyDistributedEventHandler : + IDistributedEventHandler>, ITransientDependency { - public async Task HandleEventAsync(EntityCreatedEto eventData) + public async Task HandleEventAsync(EntityCreatedEto eventData) { - if (eventData.Entity.EntityType == "Volo.Abp.Identity.IdentityUser") - { - var userId = Guid.Parse(eventData.Entity.KeysAsString); - //...handle the "created" event - } - } - - public async Task HandleEventAsync(EntityUpdatedEto eventData) - { - if (eventData.Entity.EntityType == "Volo.Abp.Identity.IdentityUser") - { - var userId = Guid.Parse(eventData.Entity.KeysAsString); - //...handle the "updated" event - } - } - - public async Task HandleEventAsync(EntityDeletedEto eventData) - { - if (eventData.Entity.EntityType == "Volo.Abp.Identity.IdentityUser") - { - var userId = Guid.Parse(eventData.Entity.KeysAsString); - //...handle the "deleted" event - } - } -} -```` - -* It implements multiple `IDistributedEventHandler` interfaces: **Created**, **Updated** and **Deleted**. Because, the distributed event bus system publishes events individually. There is no "Changed" event like the local event bus. -* It subscribes to `EntityEto`, which is a generic event class that is **automatically published** for all type of entities by the ABP framework. This is why it checks the **entity type** (checking the entity type as string since we assume that there is no type safe reference to the `IdentityUser` entity). - -Pre-built application modules do not define specialized event types yet (like `UserEto` - "ETO" means "Event Transfer Object"). This feature is on the road map and will be available in a short term ([follow this issue](https://github.com/abpframework/abp/issues/3033)). Once it is implemented, you will be able to subscribe to individual entity types. Example: - -````csharp -public class MyDistributedIdentityUserCreatedEventHandler : - IDistributedEventHandler>, - ITransientDependency -{ - public async Task HandleEventAsync(EntityCreatedEto eventData) - { - var userId = eventData.Entity.Id; - var userName = eventData.Entity.UserName; - //...handle the "created" event + var tenantId = eventData.Entity.Id; + var tenantName = eventData.Entity.Name; + //...your custom logic } //... } ```` -* This handler is executed only when a new user has been created. +This handler is executed only when a new tenant has been created. All the pre-built ABP [application modules](Modules/Index.md) define corresponding `ETO` types for their entities. So, you can easily get informed when they changes. -> The only pre-defined specialized event class is the `UserEto`. For example, you can subscribe to the `EntityCreatedEto` to get notified when a user has created. This event also works for the Identity module. +> Notice that ABP doesn't publish distributed events for an entity by default. Because it has a cost and should be enabled by intention. See the [distributed event bus document](Distributed-Event-Bus.md) to learn more. ## See Also diff --git a/docs/en/Distributed-Event-Bus.md b/docs/en/Distributed-Event-Bus.md index d542ef5325..387fece078 100644 --- a/docs/en/Distributed-Event-Bus.md +++ b/docs/en/Distributed-Event-Bus.md @@ -228,6 +228,7 @@ namespace AbpDemo ```` * `MyHandler` implements the `IDistributedEventHandler>`. +* It is required to register your handler class to the [dependency injection](Dependency-Injection.md) system. Implementing `ITransient` like in this example is an easy way. ### Configuration @@ -242,10 +243,10 @@ Configure(options => options.AutoEventSelectors.AddAll(); //Enable for a single entity - options.AutoEventSelectors.Add(); + options.AutoEventSelectors.Add(); //Enable for all entities in a namespace (and child namespaces) - options.AutoEventSelectors.AddNamespace("Volo.Abp.Identity"); + options.AutoEventSelectors.AddNamespace("MyProject.Products"); //Custom predicate expression that should return true to select a type options.AutoEventSelectors.Add( @@ -265,10 +266,21 @@ Once you enable **auto events** for an entity, ABP Framework starts to publish e * `EntityType` (`string`): Full name (including namespace) of the entity class. * `KeysAsString` (`string`): Primary key(s) of the changed entity. If it has a single key, this property will be the primary key value. For a composite key, it will contain all keys separated by `,` (comma). -So, you can implement the `IDistributedEventHandler>` to subscribe the events. However, it is not a good approach to subscribe to such a generic event. You can define the corresponding ETO for the entity type. +So, you can implement the `IDistributedEventHandler>` to subscribe the update events. However, it is not a good approach to subscribe to such a generic event, because you handle the update events for all entities in a single handler (since they all use the same ETO object). You can define the corresponding ETO type for the entity type. **Example: Declare to use `ProductEto` for the `Product` entity** +````csharp +public class ProductEto +{ + public Guid Id { get; set; } + public string Name { get; set; } + public float Price { get; set; } +} +```` + +Then you can use the `AbpDistributedEntityEventOptions.EtoMappings` option to map your `Product` entity to the `ProductEto`: + ````csharp Configure(options => { @@ -282,24 +294,4 @@ 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 mapping. You can check the object to object mapping document for all options, but the following example shows how to configure it with the [AutoMapper](https://automapper.org/) library. - -**Example: Configure `Product` to `ProductEto` mapping using the AutoMapper** - -````csharp -using System; -using AutoMapper; -using Volo.Abp.Domain.Entities.Events.Distributed; - -namespace AbpDemo -{ - [AutoMap(typeof(Product))] - public class ProductEto : EntityEto - { - public Guid Id { get; set; } - public string Name { get; set; } - } -} -```` - -This example uses the `AutoMap` attribute of the AutoMapper to configure the mapping. You could create a profile class instead. Please refer to the AutoMapper document for more options. \ No newline at end of file +> 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. \ No newline at end of file