From 0022b8b473410d26ca9fb2b80c915823a7ea64ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 25 Aug 2021 14:11:29 +0300 Subject: [PATCH 01/14] Made initial sample application --- test/DistEvents/DistDemoApp/DemoService.cs | 29 +++++++++ .../DistEvents/DistDemoApp/DistDemoApp.csproj | 26 ++++++++ .../DistDemoApp/DistDemoAppModule.cs | 28 +++++++++ .../20210825110134_Initial.Designer.cs | 61 +++++++++++++++++++ .../Migrations/20210825110134_Initial.cs | 33 ++++++++++ .../Migrations/TodoDbContextModelSnapshot.cs | 59 ++++++++++++++++++ test/DistEvents/DistDemoApp/Program.cs | 29 +++++++++ test/DistEvents/DistDemoApp/TodoDbContext.cs | 27 ++++++++ .../DistDemoApp/TodoDbContextFactory.cs | 29 +++++++++ test/DistEvents/DistDemoApp/TodoItem.cs | 15 +++++ test/DistEvents/DistDemoApp/appsettings.json | 5 ++ test/DistEvents/DistEventsDemo.sln | 16 +++++ 12 files changed, 357 insertions(+) create mode 100644 test/DistEvents/DistDemoApp/DemoService.cs create mode 100644 test/DistEvents/DistDemoApp/DistDemoApp.csproj create mode 100644 test/DistEvents/DistDemoApp/DistDemoAppModule.cs create mode 100644 test/DistEvents/DistDemoApp/Migrations/20210825110134_Initial.Designer.cs create mode 100644 test/DistEvents/DistDemoApp/Migrations/20210825110134_Initial.cs create mode 100644 test/DistEvents/DistDemoApp/Migrations/TodoDbContextModelSnapshot.cs create mode 100644 test/DistEvents/DistDemoApp/Program.cs create mode 100644 test/DistEvents/DistDemoApp/TodoDbContext.cs create mode 100644 test/DistEvents/DistDemoApp/TodoDbContextFactory.cs create mode 100644 test/DistEvents/DistDemoApp/TodoItem.cs create mode 100644 test/DistEvents/DistDemoApp/appsettings.json create mode 100644 test/DistEvents/DistEventsDemo.sln diff --git a/test/DistEvents/DistDemoApp/DemoService.cs b/test/DistEvents/DistDemoApp/DemoService.cs new file mode 100644 index 0000000000..c970485252 --- /dev/null +++ b/test/DistEvents/DistDemoApp/DemoService.cs @@ -0,0 +1,29 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; + +namespace DistDemoApp +{ + public class DemoService : ITransientDependency + { + private readonly IRepository _todoItemRepository; + + public DemoService(IRepository todoItemRepository) + { + _todoItemRepository = todoItemRepository; + } + + public async Task CreateTodoItemAsync() + { + var todoItem = await _todoItemRepository.InsertAsync( + new TodoItem + { + Text = "todo item " + DateTime.Now.Ticks + } + ); + + Console.WriteLine("Created a new todo item: " + todoItem); + } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/DistDemoApp.csproj b/test/DistEvents/DistDemoApp/DistDemoApp.csproj new file mode 100644 index 0000000000..4d88277e64 --- /dev/null +++ b/test/DistEvents/DistDemoApp/DistDemoApp.csproj @@ -0,0 +1,26 @@ + + + + Exe + net5.0 + + + + + + + + + + runtime; build; native; contentfiles; analyzers + compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native + + + + + + Always + + + + diff --git a/test/DistEvents/DistDemoApp/DistDemoAppModule.cs b/test/DistEvents/DistDemoApp/DistDemoAppModule.cs new file mode 100644 index 0000000000..a9b5b23dc7 --- /dev/null +++ b/test/DistEvents/DistDemoApp/DistDemoAppModule.cs @@ -0,0 +1,28 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Autofac; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.SqlServer; +using Volo.Abp.Modularity; + +namespace DistDemoApp +{ + [DependsOn( + typeof(AbpEntityFrameworkCoreSqlServerModule), + typeof(AbpAutofacModule) + )] + public class DistDemoAppModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAbpDbContext(options => + { + options.AddDefaultRepositories(); + }); + + Configure(options => + { + options.UseSqlServer(); + }); + } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/Migrations/20210825110134_Initial.Designer.cs b/test/DistEvents/DistDemoApp/Migrations/20210825110134_Initial.Designer.cs new file mode 100644 index 0000000000..990ef3e967 --- /dev/null +++ b/test/DistEvents/DistDemoApp/Migrations/20210825110134_Initial.Designer.cs @@ -0,0 +1,61 @@ +// +using System; +using DistDemoApp; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +namespace DistDemoApp.Migrations +{ + [DbContext(typeof(TodoDbContext))] + [Migration("20210825110134_Initial")] + partial class Initial + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.9") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("DistDemoApp.TodoItem", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("TodoItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/test/DistEvents/DistDemoApp/Migrations/20210825110134_Initial.cs b/test/DistEvents/DistDemoApp/Migrations/20210825110134_Initial.cs new file mode 100644 index 0000000000..b84d1f433f --- /dev/null +++ b/test/DistEvents/DistDemoApp/Migrations/20210825110134_Initial.cs @@ -0,0 +1,33 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace DistDemoApp.Migrations +{ + public partial class Initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "TodoItems", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Text = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true), + CreationTime = table.Column(type: "datetime2", nullable: false), + CreatorId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TodoItems", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "TodoItems"); + } + } +} diff --git a/test/DistEvents/DistDemoApp/Migrations/TodoDbContextModelSnapshot.cs b/test/DistEvents/DistDemoApp/Migrations/TodoDbContextModelSnapshot.cs new file mode 100644 index 0000000000..c930e469f1 --- /dev/null +++ b/test/DistEvents/DistDemoApp/Migrations/TodoDbContextModelSnapshot.cs @@ -0,0 +1,59 @@ +// +using System; +using DistDemoApp; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +namespace DistDemoApp.Migrations +{ + [DbContext(typeof(TodoDbContext))] + partial class TodoDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.9") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("DistDemoApp.TodoItem", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("TodoItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/test/DistEvents/DistDemoApp/Program.cs b/test/DistEvents/DistDemoApp/Program.cs new file mode 100644 index 0000000000..230bef5982 --- /dev/null +++ b/test/DistEvents/DistDemoApp/Program.cs @@ -0,0 +1,29 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; + +namespace DistDemoApp +{ + class Program + { + static async Task Main(string[] args) + { + using (var application = AbpApplicationFactory.Create(opts => + { + opts.UseAutofac(); + })) + { + application.Initialize(); + + var demoService = application.ServiceProvider.GetRequiredService(); + await demoService.CreateTodoItemAsync(); + + //Console.WriteLine("Press ENTER to exit"); + //Console.ReadLine(); + + application.Shutdown(); + } + } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/TodoDbContext.cs b/test/DistEvents/DistDemoApp/TodoDbContext.cs new file mode 100644 index 0000000000..5963f7c6ca --- /dev/null +++ b/test/DistEvents/DistDemoApp/TodoDbContext.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Entities; +using Volo.Abp.EntityFrameworkCore; + +namespace DistDemoApp +{ + public class TodoDbContext : AbpDbContext + { + public DbSet TodoItems { get; set; } + + public TodoDbContext(DbContextOptions options) + : base(options) + { + + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity(b => + { + b.Property(x => x.Text).IsRequired().HasMaxLength(128); + }); + } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/TodoDbContextFactory.cs b/test/DistEvents/DistDemoApp/TodoDbContextFactory.cs new file mode 100644 index 0000000000..97be637acc --- /dev/null +++ b/test/DistEvents/DistDemoApp/TodoDbContextFactory.cs @@ -0,0 +1,29 @@ +using System.IO; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; + +namespace DistDemoApp +{ + public class TodoDbContextFactory : IDesignTimeDbContextFactory + { + public TodoDbContext CreateDbContext(string[] args) + { + var configuration = BuildConfiguration(); + + var builder = new DbContextOptionsBuilder() + .UseSqlServer(configuration.GetConnectionString("Default")); + + return new TodoDbContext(builder.Options); + } + + private static IConfigurationRoot BuildConfiguration() + { + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false); + + return builder.Build(); + } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/TodoItem.cs b/test/DistEvents/DistDemoApp/TodoItem.cs new file mode 100644 index 0000000000..9257791efd --- /dev/null +++ b/test/DistEvents/DistDemoApp/TodoItem.cs @@ -0,0 +1,15 @@ +using System; +using Volo.Abp.Domain.Entities.Auditing; + +namespace DistDemoApp +{ + public class TodoItem : CreationAuditedAggregateRoot + { + public string Text { get; set; } + + public override string ToString() + { + return $"{base.ToString()}, Text = {Text}"; + } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/appsettings.json b/test/DistEvents/DistDemoApp/appsettings.json new file mode 100644 index 0000000000..6bb7ba54ca --- /dev/null +++ b/test/DistEvents/DistDemoApp/appsettings.json @@ -0,0 +1,5 @@ +{ + "ConnectionStrings": { + "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=DistEventsDemo;Trusted_Connection=True" + } +} \ No newline at end of file diff --git a/test/DistEvents/DistEventsDemo.sln b/test/DistEvents/DistEventsDemo.sln new file mode 100644 index 0000000000..de7a36535a --- /dev/null +++ b/test/DistEvents/DistEventsDemo.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DistDemoApp", "DistDemoApp\DistDemoApp.csproj", "{10DBC6BC-1269-4C68-9F6C-12209A3FBF5B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {10DBC6BC-1269-4C68-9F6C-12209A3FBF5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10DBC6BC-1269-4C68-9F6C-12209A3FBF5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10DBC6BC-1269-4C68-9F6C-12209A3FBF5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10DBC6BC-1269-4C68-9F6C-12209A3FBF5B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal From 16829423d47edf7f5ce5aeec323a3b711140203b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 25 Aug 2021 14:45:57 +0300 Subject: [PATCH 02/14] Added todo summary --- .../DistDemoApp/DistDemoAppModule.cs | 7 ++ ...0825112717_Added_Summary_Table.Designer.cs | 95 +++++++++++++++++++ .../20210825112717_Added_Summary_Table.cs | 34 +++++++ .../Migrations/TodoDbContextModelSnapshot.cs | 34 +++++++ test/DistEvents/DistDemoApp/Program.cs | 4 +- test/DistEvents/DistDemoApp/TodoDbContext.cs | 1 + .../DistDemoApp/TodoEventHandler.cs | 63 ++++++++++++ test/DistEvents/DistDemoApp/TodoItemEto.cs | 12 +++ .../DistDemoApp/TodoItemObjectMapper.cs | 24 +++++ test/DistEvents/DistDemoApp/TodoSummary.cs | 41 ++++++++ 10 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 test/DistEvents/DistDemoApp/Migrations/20210825112717_Added_Summary_Table.Designer.cs create mode 100644 test/DistEvents/DistDemoApp/Migrations/20210825112717_Added_Summary_Table.cs create mode 100644 test/DistEvents/DistDemoApp/TodoEventHandler.cs create mode 100644 test/DistEvents/DistDemoApp/TodoItemEto.cs create mode 100644 test/DistEvents/DistDemoApp/TodoItemObjectMapper.cs create mode 100644 test/DistEvents/DistDemoApp/TodoSummary.cs diff --git a/test/DistEvents/DistDemoApp/DistDemoAppModule.cs b/test/DistEvents/DistDemoApp/DistDemoAppModule.cs index a9b5b23dc7..14abd87b4c 100644 --- a/test/DistEvents/DistDemoApp/DistDemoAppModule.cs +++ b/test/DistEvents/DistDemoApp/DistDemoAppModule.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Autofac; +using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.SqlServer; using Volo.Abp.Modularity; @@ -23,6 +24,12 @@ namespace DistDemoApp { options.UseSqlServer(); }); + + Configure(options => + { + options.EtoMappings.Add(); + options.AutoEventSelectors.Add(); + }); } } } \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/Migrations/20210825112717_Added_Summary_Table.Designer.cs b/test/DistEvents/DistDemoApp/Migrations/20210825112717_Added_Summary_Table.Designer.cs new file mode 100644 index 0000000000..4c2cf9abbb --- /dev/null +++ b/test/DistEvents/DistDemoApp/Migrations/20210825112717_Added_Summary_Table.Designer.cs @@ -0,0 +1,95 @@ +// +using System; +using DistDemoApp; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; + +namespace DistDemoApp.Migrations +{ + [DbContext(typeof(TodoDbContext))] + [Migration("20210825112717_Added_Summary_Table")] + partial class Added_Summary_Table + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.9") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("DistDemoApp.TodoItem", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Text") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("TodoItems"); + }); + + modelBuilder.Entity("DistDemoApp.TodoSummary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Day") + .HasColumnType("tinyint"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Month") + .HasColumnType("tinyint"); + + b.Property("TotalCount") + .HasColumnType("int"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("TodoSummaries"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/test/DistEvents/DistDemoApp/Migrations/20210825112717_Added_Summary_Table.cs b/test/DistEvents/DistDemoApp/Migrations/20210825112717_Added_Summary_Table.cs new file mode 100644 index 0000000000..7a7f167470 --- /dev/null +++ b/test/DistEvents/DistDemoApp/Migrations/20210825112717_Added_Summary_Table.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace DistDemoApp.Migrations +{ + public partial class Added_Summary_Table : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "TodoSummaries", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Year = table.Column(type: "int", nullable: false), + Month = table.Column(type: "tinyint", nullable: false), + Day = table.Column(type: "tinyint", nullable: false), + TotalCount = table.Column(type: "int", nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_TodoSummaries", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "TodoSummaries"); + } + } +} diff --git a/test/DistEvents/DistDemoApp/Migrations/TodoDbContextModelSnapshot.cs b/test/DistEvents/DistDemoApp/Migrations/TodoDbContextModelSnapshot.cs index c930e469f1..99f0f92ab7 100644 --- a/test/DistEvents/DistDemoApp/Migrations/TodoDbContextModelSnapshot.cs +++ b/test/DistEvents/DistDemoApp/Migrations/TodoDbContextModelSnapshot.cs @@ -53,6 +53,40 @@ namespace DistDemoApp.Migrations b.ToTable("TodoItems"); }); + + modelBuilder.Entity("DistDemoApp.TodoSummary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Day") + .HasColumnType("tinyint"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Month") + .HasColumnType("tinyint"); + + b.Property("TotalCount") + .HasColumnType("int"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("TodoSummaries"); + }); #pragma warning restore 612, 618 } } diff --git a/test/DistEvents/DistDemoApp/Program.cs b/test/DistEvents/DistDemoApp/Program.cs index 230bef5982..bf60cac7e5 100644 --- a/test/DistEvents/DistDemoApp/Program.cs +++ b/test/DistEvents/DistDemoApp/Program.cs @@ -19,8 +19,8 @@ namespace DistDemoApp var demoService = application.ServiceProvider.GetRequiredService(); await demoService.CreateTodoItemAsync(); - //Console.WriteLine("Press ENTER to exit"); - //Console.ReadLine(); + Console.WriteLine("Press ENTER to exit"); + Console.ReadLine(); application.Shutdown(); } diff --git a/test/DistEvents/DistDemoApp/TodoDbContext.cs b/test/DistEvents/DistDemoApp/TodoDbContext.cs index 5963f7c6ca..000f18c802 100644 --- a/test/DistEvents/DistDemoApp/TodoDbContext.cs +++ b/test/DistEvents/DistDemoApp/TodoDbContext.cs @@ -7,6 +7,7 @@ namespace DistDemoApp public class TodoDbContext : AbpDbContext { public DbSet TodoItems { get; set; } + public DbSet TodoSummaries { get; set; } public TodoDbContext(DbContextOptions options) : base(options) diff --git a/test/DistEvents/DistDemoApp/TodoEventHandler.cs b/test/DistEvents/DistDemoApp/TodoEventHandler.cs new file mode 100644 index 0000000000..b48031aefd --- /dev/null +++ b/test/DistEvents/DistDemoApp/TodoEventHandler.cs @@ -0,0 +1,63 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Uow; + +namespace DistDemoApp +{ + public class TodoEventHandler : + IDistributedEventHandler>, + IDistributedEventHandler>, + ITransientDependency + { + private readonly IRepository _todoSummaryRepository; + + public TodoEventHandler(IRepository todoSummaryRepository) + { + _todoSummaryRepository = todoSummaryRepository; + } + + [UnitOfWork] + public virtual async Task HandleEventAsync(EntityCreatedEto eventData) + { + var dateTime = eventData.Entity.CreationTime; + var todoSummary = await _todoSummaryRepository.FindAsync( + x => x.Year == dateTime.Year && + x.Month == dateTime.Month && + x.Day == dateTime.Day + ); + + if (todoSummary == null) + { + await _todoSummaryRepository.InsertAsync(new TodoSummary(dateTime)); + } + else + { + todoSummary.Increase(); + await _todoSummaryRepository.UpdateAsync(todoSummary); + } + + Console.WriteLine("Increased total count: " + todoSummary); + } + + public async Task HandleEventAsync(EntityDeletedEto eventData) + { + var dateTime = eventData.Entity.CreationTime; + var todoSummary = await _todoSummaryRepository.FirstOrDefaultAsync( + x => x.Year == dateTime.Year && + x.Month == dateTime.Month && + x.Day == dateTime.Day + ); + + if (todoSummary != null) + { + todoSummary.Decrease(); + await _todoSummaryRepository.UpdateAsync(todoSummary); + Console.WriteLine("Decreased total count: " + todoSummary); + } + } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/TodoItemEto.cs b/test/DistEvents/DistDemoApp/TodoItemEto.cs new file mode 100644 index 0000000000..d593a10347 --- /dev/null +++ b/test/DistEvents/DistDemoApp/TodoItemEto.cs @@ -0,0 +1,12 @@ +using System; +using Volo.Abp.EventBus; + +namespace DistDemoApp +{ + [EventName("todo-item")] + public class TodoItemEto + { + public DateTime CreationTime { get; set; } + public string Text { get; set; } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/TodoItemObjectMapper.cs b/test/DistEvents/DistDemoApp/TodoItemObjectMapper.cs new file mode 100644 index 0000000000..167c8e114f --- /dev/null +++ b/test/DistEvents/DistDemoApp/TodoItemObjectMapper.cs @@ -0,0 +1,24 @@ +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; + +namespace DistDemoApp +{ + public class TodoItemObjectMapper : IObjectMapper, ISingletonDependency + { + public TodoItemEto Map(TodoItem source) + { + return new TodoItemEto + { + Text = source.Text, + CreationTime = source.CreationTime + }; + } + + public TodoItemEto Map(TodoItem source, TodoItemEto destination) + { + destination.Text = source.Text; + destination.CreationTime = source.CreationTime; + return destination; + } + } +} \ No newline at end of file diff --git a/test/DistEvents/DistDemoApp/TodoSummary.cs b/test/DistEvents/DistDemoApp/TodoSummary.cs new file mode 100644 index 0000000000..b0e3b395c2 --- /dev/null +++ b/test/DistEvents/DistDemoApp/TodoSummary.cs @@ -0,0 +1,41 @@ +using System; +using Volo.Abp.Domain.Entities; + +namespace DistDemoApp +{ + public class TodoSummary : AggregateRoot + { + public int Year { get; private set; } + public byte Month { get; private set; } + public byte Day { get; private set; } + public int TotalCount { get; private set; } + + private TodoSummary() + { + + } + + public TodoSummary(DateTime dateTime, int initialCount = 1) + { + Year = dateTime.Year; + Month = (byte)dateTime.Month; + Day = (byte)dateTime.Day; + TotalCount = initialCount; + } + + public void Increase(int amount = 1) + { + TotalCount += amount; + } + + public void Decrease(int amount = 1) + { + TotalCount -= amount; + } + + public override string ToString() + { + return $"{base.ToString()}, {Year}-{Month:2}-{Day:2}: {TotalCount}"; + } + } +} \ No newline at end of file From 889a48cc858290e597f711393ed38ca4541ae56c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 25 Aug 2021 14:55:31 +0300 Subject: [PATCH 03/14] added logging --- .../DistEvents/DistDemoApp/DistDemoApp.csproj | 10 +++- .../DistDemoApp/DistDemoAppModule.cs | 2 + .../DistDemoApp/MyProjectNameHostedService.cs | 39 ++++++++++++ test/DistEvents/DistDemoApp/Program.cs | 60 ++++++++++++++----- .../DistDemoApp/TodoEventHandler.cs | 2 +- test/DistEvents/DistDemoApp/TodoSummary.cs | 2 +- 6 files changed, 96 insertions(+), 19 deletions(-) create mode 100644 test/DistEvents/DistDemoApp/MyProjectNameHostedService.cs diff --git a/test/DistEvents/DistDemoApp/DistDemoApp.csproj b/test/DistEvents/DistDemoApp/DistDemoApp.csproj index 4d88277e64..9695a92f04 100644 --- a/test/DistEvents/DistDemoApp/DistDemoApp.csproj +++ b/test/DistEvents/DistDemoApp/DistDemoApp.csproj @@ -4,7 +4,15 @@ Exe net5.0 - + + + + + + + + + diff --git a/test/DistEvents/DistDemoApp/DistDemoAppModule.cs b/test/DistEvents/DistDemoApp/DistDemoAppModule.cs index 14abd87b4c..f69f9c2380 100644 --- a/test/DistEvents/DistDemoApp/DistDemoAppModule.cs +++ b/test/DistEvents/DistDemoApp/DistDemoAppModule.cs @@ -15,6 +15,8 @@ namespace DistDemoApp { public override void ConfigureServices(ServiceConfigurationContext context) { + context.Services.AddHostedService(); + context.Services.AddAbpDbContext(options => { options.AddDefaultRepositories(); diff --git a/test/DistEvents/DistDemoApp/MyProjectNameHostedService.cs b/test/DistEvents/DistDemoApp/MyProjectNameHostedService.cs new file mode 100644 index 0000000000..7522d9fe9d --- /dev/null +++ b/test/DistEvents/DistDemoApp/MyProjectNameHostedService.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; +using Volo.Abp; + +namespace DistDemoApp +{ + public class MyProjectNameHostedService : IHostedService + { + private readonly IAbpApplicationWithExternalServiceProvider _application; + private readonly IServiceProvider _serviceProvider; + private readonly DemoService _demoService; + + public MyProjectNameHostedService( + IAbpApplicationWithExternalServiceProvider application, + IServiceProvider serviceProvider, + DemoService demoService) + { + _application = application; + _serviceProvider = serviceProvider; + _demoService = demoService; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + _application.Initialize(_serviceProvider); + + await _demoService.CreateTodoItemAsync(); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + _application.Shutdown(); + + return Task.CompletedTask; + } + } +} diff --git a/test/DistEvents/DistDemoApp/Program.cs b/test/DistEvents/DistDemoApp/Program.cs index bf60cac7e5..499d0c0aeb 100644 --- a/test/DistEvents/DistDemoApp/Program.cs +++ b/test/DistEvents/DistDemoApp/Program.cs @@ -1,29 +1,57 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using Volo.Abp; +using Microsoft.Extensions.Hosting; +using Serilog; +using Serilog.Events; namespace DistDemoApp { - class Program + public class Program { - static async Task Main(string[] args) + public static async Task Main(string[] args) { - using (var application = AbpApplicationFactory.Create(opts => + Log.Logger = new LoggerConfiguration() +#if DEBUG + .MinimumLevel.Debug() +#else + .MinimumLevel.Information() +#endif + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .Enrich.FromLogContext() + .WriteTo.Async(c => c.File("Logs/logs.txt")) + .WriteTo.Async(c => c.Console()) + .CreateLogger(); + + try { - opts.UseAutofac(); - })) + Log.Information("Starting console host."); + await CreateHostBuilder(args).RunConsoleAsync(); + return 0; + } + catch (Exception ex) { - application.Initialize(); - - var demoService = application.ServiceProvider.GetRequiredService(); - await demoService.CreateTodoItemAsync(); - - Console.WriteLine("Press ENTER to exit"); - Console.ReadLine(); - - application.Shutdown(); + Log.Fatal(ex, "Host terminated unexpectedly!"); + return 1; } + finally + { + Log.CloseAndFlush(); + } + } + + internal static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .UseAutofac() + .UseSerilog() + .ConfigureAppConfiguration((context, config) => + { + //setup your additional configuration sources + }) + .ConfigureServices((hostContext, services) => + { + services.AddApplication(); + }); } -} \ No newline at end of file +} diff --git a/test/DistEvents/DistDemoApp/TodoEventHandler.cs b/test/DistEvents/DistDemoApp/TodoEventHandler.cs index b48031aefd..e54278c459 100644 --- a/test/DistEvents/DistDemoApp/TodoEventHandler.cs +++ b/test/DistEvents/DistDemoApp/TodoEventHandler.cs @@ -32,7 +32,7 @@ namespace DistDemoApp if (todoSummary == null) { - await _todoSummaryRepository.InsertAsync(new TodoSummary(dateTime)); + todoSummary = await _todoSummaryRepository.InsertAsync(new TodoSummary(dateTime)); } else { diff --git a/test/DistEvents/DistDemoApp/TodoSummary.cs b/test/DistEvents/DistDemoApp/TodoSummary.cs index b0e3b395c2..70eaee1847 100644 --- a/test/DistEvents/DistDemoApp/TodoSummary.cs +++ b/test/DistEvents/DistDemoApp/TodoSummary.cs @@ -35,7 +35,7 @@ namespace DistDemoApp public override string ToString() { - return $"{base.ToString()}, {Year}-{Month:2}-{Day:2}: {TotalCount}"; + return $"{base.ToString()}, {Year}-{Month:00}-{Day:00}: {TotalCount}"; } } } \ No newline at end of file From a09ccde7db0bc2ce9b77a1f0a003a0e9abcab689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 25 Aug 2021 15:09:39 +0300 Subject: [PATCH 04/14] Update Program.cs --- test/DistEvents/DistDemoApp/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/DistEvents/DistDemoApp/Program.cs b/test/DistEvents/DistDemoApp/Program.cs index 499d0c0aeb..676a07e357 100644 --- a/test/DistEvents/DistDemoApp/Program.cs +++ b/test/DistEvents/DistDemoApp/Program.cs @@ -17,7 +17,7 @@ namespace DistDemoApp #else .MinimumLevel.Information() #endif - .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .Enrich.FromLogContext() .WriteTo.Async(c => c.File("Logs/logs.txt")) .WriteTo.Async(c => c.Console()) From 8217bf59f61719d5f3d6a0518f5f81ad093a451f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 25 Aug 2021 16:36:26 +0300 Subject: [PATCH 05/14] Introduced AddLocalEvent and AddDistributedEvent methods on IUnitOfWork --- .../Volo/Abp/Uow/ChildUnitOfWork.cs | 10 +++ .../Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs | 4 ++ .../Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs | 11 ++++ .../Abp/Uow/NullUnitOfWorkEventPublisher.cs | 19 ++++++ .../Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs | 63 ++++++++++++++++--- .../Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs | 10 ++- .../DistDemoApp/TodoEventHandler.cs | 4 +- 7 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs create mode 100644 framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs index 882c8d6a70..d1157c3fd8 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs @@ -76,6 +76,16 @@ namespace Volo.Abp.Uow _parent.OnCompleted(handler); } + public void AddLocalEvent(object eventData) + { + _parent.AddLocalEvent(eventData); + } + + public void AddDistributedEvent(object eventData) + { + _parent.AddDistributedEvent(eventData); + } + public IDatabaseApi FindDatabaseApi(string key) { return _parent.FindDatabaseApi(key); diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs index ee5baa58bc..ed3e185b72 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs @@ -42,5 +42,9 @@ namespace Volo.Abp.Uow Task RollbackAsync(CancellationToken cancellationToken = default); void OnCompleted(Func handler); + + void AddLocalEvent(object eventData); + + void AddDistributedEvent(object eventData); } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs new file mode 100644 index 0000000000..1f4c65165f --- /dev/null +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Volo.Abp.Uow +{ + public interface IUnitOfWorkEventPublisher + { + Task PublishLocalEventsAsync(IEnumerable localEvents); + Task PublishDistributedEventsAsync(IEnumerable distributedEvents); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs new file mode 100644 index 0000000000..d7ec5436fe --- /dev/null +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Uow +{ + public class NullUnitOfWorkEventPublisher : IUnitOfWorkEventPublisher, ISingletonDependency + { + public Task PublishLocalEventsAsync(IEnumerable localEvents) + { + return Task.CompletedTask; + } + + public Task PublishDistributedEventsAsync(IEnumerable distributedEvents) + { + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index 7b4f8fda33..8634075d94 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Linq; using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; @@ -33,11 +35,14 @@ namespace Volo.Abp.Uow public string ReservationName { get; set; } protected List> CompletedHandlers { get; } = new List>(); + protected ICollection DistributedEvents { get; } = new Collection(); + protected ICollection LocalEvents { get; } = new Collection(); public event EventHandler Failed; public event EventHandler Disposed; public IServiceProvider ServiceProvider { get; } + protected IUnitOfWorkEventPublisher UnitOfWorkEventPublisher { get; } [NotNull] public Dictionary Items { get; } @@ -50,9 +55,13 @@ namespace Volo.Abp.Uow private bool _isCompleting; private bool _isRolledback; - public UnitOfWork(IServiceProvider serviceProvider, IOptions options) + public UnitOfWork( + IServiceProvider serviceProvider, + IUnitOfWorkEventPublisher unitOfWorkEventPublisher, + IOptions options) { ServiceProvider = serviceProvider; + UnitOfWorkEventPublisher = unitOfWorkEventPublisher; _defaultOptions = options.Value; _databaseApis = new Dictionary(); @@ -103,12 +112,12 @@ namespace Volo.Abp.Uow } } - public IReadOnlyList GetAllActiveDatabaseApis() + public virtual IReadOnlyList GetAllActiveDatabaseApis() { return _databaseApis.Values.ToImmutableList(); } - public IReadOnlyList GetAllActiveTransactionApis() + public virtual IReadOnlyList GetAllActiveTransactionApis() { return _transactionApis.Values.ToImmutableList(); } @@ -126,6 +135,30 @@ namespace Volo.Abp.Uow { _isCompleting = true; await SaveChangesAsync(cancellationToken); + + while (LocalEvents.Any() || DistributedEvents.Any()) + { + if (LocalEvents.Any()) + { + var localEventsToBePublished = LocalEvents.ToArray(); + LocalEvents.Clear(); + await UnitOfWorkEventPublisher.PublishLocalEventsAsync( + localEventsToBePublished + ); + } + + if (DistributedEvents.Any()) + { + var distributedEventsToBePublished = DistributedEvents.ToArray(); + DistributedEvents.Clear(); + await UnitOfWorkEventPublisher.PublishDistributedEventsAsync( + distributedEventsToBePublished + ); + } + + await SaveChangesAsync(cancellationToken); + } + await CommitTransactionsAsync(); IsCompleted = true; await OnCompletedAsync(); @@ -149,12 +182,12 @@ namespace Volo.Abp.Uow await RollbackAllAsync(cancellationToken); } - public IDatabaseApi FindDatabaseApi(string key) + public virtual IDatabaseApi FindDatabaseApi(string key) { return _databaseApis.GetOrDefault(key); } - public void AddDatabaseApi(string key, IDatabaseApi api) + public virtual void AddDatabaseApi(string key, IDatabaseApi api) { Check.NotNull(key, nameof(key)); Check.NotNull(api, nameof(api)); @@ -167,7 +200,7 @@ namespace Volo.Abp.Uow _databaseApis.Add(key, api); } - public IDatabaseApi GetOrAddDatabaseApi(string key, Func factory) + public virtual IDatabaseApi GetOrAddDatabaseApi(string key, Func factory) { Check.NotNull(key, nameof(key)); Check.NotNull(factory, nameof(factory)); @@ -175,14 +208,14 @@ namespace Volo.Abp.Uow return _databaseApis.GetOrAdd(key, factory); } - public ITransactionApi FindTransactionApi(string key) + public virtual ITransactionApi FindTransactionApi(string key) { Check.NotNull(key, nameof(key)); return _transactionApis.GetOrDefault(key); } - public void AddTransactionApi(string key, ITransactionApi api) + public virtual void AddTransactionApi(string key, ITransactionApi api) { Check.NotNull(key, nameof(key)); Check.NotNull(api, nameof(api)); @@ -195,7 +228,7 @@ namespace Volo.Abp.Uow _transactionApis.Add(key, api); } - public ITransactionApi GetOrAddTransactionApi(string key, Func factory) + public virtual ITransactionApi GetOrAddTransactionApi(string key, Func factory) { Check.NotNull(key, nameof(key)); Check.NotNull(factory, nameof(factory)); @@ -203,11 +236,21 @@ namespace Volo.Abp.Uow return _transactionApis.GetOrAdd(key, factory); } - public void OnCompleted(Func handler) + public virtual void OnCompleted(Func handler) { CompletedHandlers.Add(handler); } + public virtual void AddLocalEvent(object eventData) + { + LocalEvents.Add(eventData); + } + + public virtual void AddDistributedEvent(object eventData) + { + DistributedEvents.Add(eventData); + } + protected virtual async Task OnCompletedAsync() { foreach (var handler in CompletedHandlers) diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs index 3b9ec55e75..bf0d0c8781 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Uow/TestUnitOfWork.cs @@ -13,8 +13,14 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow { private readonly TestUnitOfWorkConfig _config; - public TestUnitOfWork(IServiceProvider serviceProvider, IOptions options, TestUnitOfWorkConfig config) - : base(serviceProvider, options) + public TestUnitOfWork( + IServiceProvider serviceProvider, + IUnitOfWorkEventPublisher unitOfWorkEventPublisher, + IOptions options, TestUnitOfWorkConfig config) + : base( + serviceProvider, + unitOfWorkEventPublisher, + options) { _config = config; } diff --git a/test/DistEvents/DistDemoApp/TodoEventHandler.cs b/test/DistEvents/DistDemoApp/TodoEventHandler.cs index e54278c459..73c7040732 100644 --- a/test/DistEvents/DistDemoApp/TodoEventHandler.cs +++ b/test/DistEvents/DistDemoApp/TodoEventHandler.cs @@ -39,8 +39,10 @@ namespace DistDemoApp todoSummary.Increase(); await _todoSummaryRepository.UpdateAsync(todoSummary); } - + Console.WriteLine("Increased total count: " + todoSummary); + + throw new ApplicationException("Thrown to rollback the UOW!"); } public async Task HandleEventAsync(EntityDeletedEto eventData) From 39ac36e6af9c11d8357d7102ca4900547f39c720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 25 Aug 2021 21:33:36 +0300 Subject: [PATCH 06/14] Public entity events always in the same unit of work while the uow is being completed. --- .../Events/EntityChangeEventHelper.cs | 186 ++++++------------ .../Events/IEntityChangeEventHelper.cs | 6 +- .../Events/NullEntityChangeEventHelper.cs | 15 -- .../Abp/EventBus/UnitOfWorkEventPublisher.cs | 40 ++++ .../MemoryDb/MemoryDbRepository.cs | 6 +- .../Repositories/MongoDB/MongoDbRepository.cs | 6 +- .../Volo/Abp/Uow/ChildUnitOfWork.cs | 14 +- .../Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs | 12 +- .../Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs | 4 +- .../Abp/Uow/NullUnitOfWorkEventPublisher.cs | 4 +- .../Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs | 40 +++- .../Volo/Abp/Uow/UnitOfWorkEventRecord.cs | 25 +++ 12 files changed, 186 insertions(+), 172 deletions(-) create mode 100644 framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/UnitOfWorkEventPublisher.cs create mode 100644 framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs index 2747257001..4c81f859d0 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; @@ -21,6 +20,8 @@ namespace Volo.Abp.Domain.Entities.Events /// public class EntityChangeEventHelper : IEntityChangeEventHelper, ITransientDependency { + private const string UnitOfWorkEventRecordEntityPropName = "_Abp_Entity"; + public ILogger Logger { get; set; } public ILocalEventBus LocalEventBus { get; set; } public IDistributedEventBus DistributedEventBus { get; set; } @@ -45,14 +46,9 @@ namespace Volo.Abp.Domain.Entities.Events public async Task TriggerEventsAsync(EntityChangeReport changeReport) { - await TriggerEventsInternalAsync(changeReport); - - if (changeReport.IsEmpty() || UnitOfWorkManager.Current == null) - { - return; - } - - await UnitOfWorkManager.Current.SaveChangesAsync(); + await TriggerEntityChangeEvents(changeReport.ChangedEntities); + await TriggerLocalEvents(changeReport.DomainEvents); + await TriggerDistributedEvents(changeReport.DistributedEvents); } public virtual async Task TriggerEntityCreatingEventAsync(object entity) @@ -61,19 +57,17 @@ namespace Volo.Abp.Domain.Entities.Events LocalEventBus, typeof(EntityCreatingEventData<>), entity, - entity, - true + entity ); } - public virtual async Task TriggerEntityCreatedEventOnUowCompletedAsync(object entity) + public virtual async Task TriggerEntityCreatedEventAsync(object entity) { await TriggerEventWithEntity( LocalEventBus, typeof(EntityCreatedEventData<>), entity, - entity, - false + entity ); if (ShouldPublishDistributedEventForEntity(entity)) @@ -85,8 +79,7 @@ namespace Volo.Abp.Domain.Entities.Events DistributedEventBus, typeof(EntityCreatedEto<>), eto, - entity, - false + entity ); } } @@ -109,19 +102,17 @@ namespace Volo.Abp.Domain.Entities.Events LocalEventBus, typeof(EntityUpdatingEventData<>), entity, - entity, - true + entity ); } - public virtual async Task TriggerEntityUpdatedEventOnUowCompletedAsync(object entity) + public virtual async Task TriggerEntityUpdatedEventAsync(object entity) { await TriggerEventWithEntity( LocalEventBus, typeof(EntityUpdatedEventData<>), entity, - entity, - false + entity ); if (ShouldPublishDistributedEventForEntity(entity)) @@ -133,8 +124,7 @@ namespace Volo.Abp.Domain.Entities.Events DistributedEventBus, typeof(EntityUpdatedEto<>), eto, - entity, - false + entity ); } } @@ -146,19 +136,17 @@ namespace Volo.Abp.Domain.Entities.Events LocalEventBus, typeof(EntityDeletingEventData<>), entity, - entity, - true + entity ); } - public virtual async Task TriggerEntityDeletedEventOnUowCompletedAsync(object entity) + public virtual async Task TriggerEntityDeletedEventAsync(object entity) { await TriggerEventWithEntity( LocalEventBus, typeof(EntityDeletedEventData<>), entity, - entity, - false + entity ); if (ShouldPublishDistributedEventForEntity(entity)) @@ -170,20 +158,12 @@ namespace Volo.Abp.Domain.Entities.Events DistributedEventBus, typeof(EntityDeletedEto<>), eto, - entity, - false + entity ); } } } - protected virtual async Task TriggerEventsInternalAsync(EntityChangeReport changeReport) - { - await TriggerEntityChangeEvents(changeReport.ChangedEntities); - await TriggerLocalEvents(changeReport.DomainEvents); - await TriggerDistributedEvents(changeReport.DistributedEvents); - } - protected virtual async Task TriggerEntityChangeEvents(List changedEntities) { foreach (var changedEntity in changedEntities) @@ -192,15 +172,15 @@ namespace Volo.Abp.Domain.Entities.Events { case EntityChangeType.Created: await TriggerEntityCreatingEventAsync(changedEntity.Entity); - await TriggerEntityCreatedEventOnUowCompletedAsync(changedEntity.Entity); + await TriggerEntityCreatedEventAsync(changedEntity.Entity); break; case EntityChangeType.Updated: await TriggerEntityUpdatingEventAsync(changedEntity.Entity); - await TriggerEntityUpdatedEventOnUowCompletedAsync(changedEntity.Entity); + await TriggerEntityUpdatedEventAsync(changedEntity.Entity); break; case EntityChangeType.Deleted: await TriggerEntityDeletingEventAsync(changedEntity.Entity); - await TriggerEntityDeletedEventOnUowCompletedAsync(changedEntity.Entity); + await TriggerEntityDeletedEventAsync(changedEntity.Entity); break; default: throw new AbpException("Unknown EntityChangeType: " + changedEntity.ChangeType); @@ -229,120 +209,68 @@ namespace Volo.Abp.Domain.Entities.Events IEventBus eventPublisher, Type genericEventType, object entityOrEto, - object originalEntity, - bool triggerInCurrentUnitOfWork) + object originalEntity) { var entityType = ProxyHelper.UnProxy(entityOrEto).GetType(); var eventType = genericEventType.MakeGenericType(entityType); + var eventData = Activator.CreateInstance(eventType, entityOrEto); var currentUow = UnitOfWorkManager.Current; - - if (triggerInCurrentUnitOfWork || currentUow == null) + + if (currentUow == null) { await eventPublisher.PublishAsync( eventType, - Activator.CreateInstance(eventType, entityOrEto) + eventData ); return; } - - var eventList = GetEventList(currentUow); - var isFirstEvent = !eventList.Any(); - - eventList.AddUniqueEvent(eventPublisher, eventType, entityOrEto, originalEntity); - - /* Register to OnCompleted if this is the first item. - * Other items will already be in the list once the UOW completes. + + var eventRecord = new UnitOfWorkEventRecord(eventType, eventData) + { + Properties = + { + { UnitOfWorkEventRecordEntityPropName, originalEntity }, + } + }; + + /* We are trying to eliminate same events for the same entity. + * In this way, for example, we don't trigger update event for an entity multiple times + * even if it is updated multiple times in the current UOW. */ - if (isFirstEvent) + + if (eventPublisher == DistributedEventBus) { - currentUow.OnCompleted( - async () => - { - foreach (var eventEntry in eventList) - { - try - { - await eventEntry.EventBus.PublishAsync( - eventEntry.EventType, - Activator.CreateInstance(eventEntry.EventType, eventEntry.EntityOrEto) - ); - } - catch (Exception ex) - { - Logger.LogError( - $"Caught an exception while publishing the event '{eventType.FullName}' for the entity '{entityOrEto}'"); - Logger.LogException(ex); - } - } - } + currentUow.AddOrReplaceDistributedEvent( + eventRecord, + otherRecord => IsSameEntityEventRecord(eventRecord, otherRecord) ); } - } - - private EntityChangeEventList GetEventList(IUnitOfWork currentUow) - { - return (EntityChangeEventList) currentUow.Items.GetOrAdd( - "AbpEntityChangeEventList", - () => new EntityChangeEventList() - ); - } - - private class EntityChangeEventList : List - { - public void AddUniqueEvent(IEventBus eventBus, Type eventType, object entityOrEto, object originalEntity) + else { - var newEntry = new EntityChangeEventEntry(eventBus, eventType, entityOrEto, originalEntity); - - //Latest "same" event overrides the previous events. - for (var i = 0; i < Count; i++) - { - if (this[i].IsSameEvent(newEntry)) - { - this[i] = newEntry; - return; - } - } - - //If this is a "new" event, add to the end - Add(newEntry); + currentUow.AddOrReplaceLocalEvent( + eventRecord, + otherRecord => IsSameEntityEventRecord(eventRecord, otherRecord) + ); } } - private class EntityChangeEventEntry + public bool IsSameEntityEventRecord(UnitOfWorkEventRecord record1, UnitOfWorkEventRecord record2) { - public IEventBus EventBus { get; } - - public Type EventType { get; } - - public object EntityOrEto { get; } - - public object OriginalEntity { get; } - - public EntityChangeEventEntry(IEventBus eventBus, Type eventType, object entityOrEto, object originalEntity) + if (record1.EventType != record2.EventType) { - EventType = eventType; - EntityOrEto = entityOrEto; - OriginalEntity = originalEntity; - EventBus = eventBus; + return false; } - public bool IsSameEvent(EntityChangeEventEntry otherEntry) - { - if (EventBus != otherEntry.EventBus || EventType != otherEntry.EventType) - { - return false; - } - - var originalEntityRef = OriginalEntity as IEntity; - var otherOriginalEntityRef = otherEntry.OriginalEntity as IEntity; - if (originalEntityRef == null || otherOriginalEntityRef == null) - { - return false; - } + var record1OriginalEntity = record1.Properties.GetOrDefault(UnitOfWorkEventRecordEntityPropName) as IEntity; + var record2OriginalEntity = record2.Properties.GetOrDefault(UnitOfWorkEventRecordEntityPropName) as IEntity; - return EntityHelper.EntityEquals(originalEntityRef, otherOriginalEntityRef); + if (record1OriginalEntity == null || record2OriginalEntity == null) + { + return false; } + + return EntityHelper.EntityEquals(record1OriginalEntity, record2OriginalEntity); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs index 59fa72ba09..c13cb94453 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs @@ -10,12 +10,12 @@ namespace Volo.Abp.Domain.Entities.Events Task TriggerEventsAsync(EntityChangeReport changeReport); Task TriggerEntityCreatingEventAsync(object entity); - Task TriggerEntityCreatedEventOnUowCompletedAsync(object entity); + Task TriggerEntityCreatedEventAsync(object entity); Task TriggerEntityUpdatingEventAsync(object entity); - Task TriggerEntityUpdatedEventOnUowCompletedAsync(object entity); + Task TriggerEntityUpdatedEventAsync(object entity); Task TriggerEntityDeletingEventAsync(object entity); - Task TriggerEntityDeletedEventOnUowCompletedAsync(object entity); + Task TriggerEntityDeletedEventAsync(object entity); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs index 85b660ed08..c4b1f66a92 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs @@ -27,11 +27,6 @@ namespace Volo.Abp.Domain.Entities.Events return Task.CompletedTask; } - public Task TriggerEntityCreatedEventOnUowCompletedAsync(object entity) - { - return Task.CompletedTask; - } - public Task TriggerEntityUpdatingEventAsync(object entity) { return Task.CompletedTask; @@ -42,11 +37,6 @@ namespace Volo.Abp.Domain.Entities.Events return Task.CompletedTask; } - public Task TriggerEntityUpdatedEventOnUowCompletedAsync(object entity) - { - return Task.CompletedTask; - } - public Task TriggerEntityDeletingEventAsync(object entity) { return Task.CompletedTask; @@ -57,11 +47,6 @@ namespace Volo.Abp.Domain.Entities.Events return Task.CompletedTask; } - public Task TriggerEntityDeletedEventOnUowCompletedAsync(object entity) - { - return Task.CompletedTask; - } - public Task TriggerEventsAsync(EntityChangeReport changeReport) { return Task.CompletedTask; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/UnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/UnitOfWorkEventPublisher.cs new file mode 100644 index 0000000000..fd8d3aec2d --- /dev/null +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/UnitOfWorkEventPublisher.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.EventBus.Local; +using Volo.Abp.Uow; + +namespace Volo.Abp.EventBus +{ + [Dependency(ReplaceServices = true)] + public class UnitOfWorkEventPublisher : IUnitOfWorkEventPublisher, ITransientDependency + { + private readonly ILocalEventBus _localEventBus; + private readonly IDistributedEventBus _distributedEventBus; + + public UnitOfWorkEventPublisher( + ILocalEventBus localEventBus, + IDistributedEventBus distributedEventBus) + { + _localEventBus = localEventBus; + _distributedEventBus = distributedEventBus; + } + + public async Task PublishLocalEventsAsync(IEnumerable localEvents) + { + foreach (var localEvent in localEvents) + { + await _localEventBus.PublishAsync(localEvent.EventType, localEvent.EventData); + } + } + + public async Task PublishDistributedEventsAsync(IEnumerable distributedEvents) + { + foreach (var distributedEvent in distributedEvents) + { + await _distributedEventBus.PublishAsync(distributedEvent.EventType, distributedEvent.EventData); + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index b915e968ca..8451a5ab79 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -145,20 +145,20 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb protected virtual async Task TriggerEntityCreateEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityCreatedEventOnUowCompletedAsync(entity); await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityCreatedEventAsync(entity); } protected virtual async Task TriggerEntityUpdateEventsAsync(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompletedAsync(entity); await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityUpdatedEventAsync(entity); } protected virtual async Task TriggerEntityDeleteEventsAsync(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompletedAsync(entity); await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityDeletedEventAsync(entity); } protected virtual async Task ApplyAbpConceptsForAddedEntityAsync(TEntity entity) diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 99e732cf9c..303e7917e4 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -579,14 +579,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB private async Task TriggerEntityCreateEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityCreatedEventOnUowCompletedAsync(entity); await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityCreatedEventAsync(entity); } protected virtual async Task TriggerEntityUpdateEventsAsync(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompletedAsync(entity); await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityUpdatedEventAsync(entity); } protected virtual async Task ApplyAbpConceptsForDeletedEntityAsync(TEntity entity) @@ -598,8 +598,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB protected virtual async Task TriggerEntityDeleteEventsAsync(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompletedAsync(entity); await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity); + await EntityChangeEventHelper.TriggerEntityDeletedEventAsync(entity); } protected virtual void CheckAndSetId(TEntity entity) diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs index d1157c3fd8..1f7b07f1c5 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/ChildUnitOfWork.cs @@ -76,16 +76,20 @@ namespace Volo.Abp.Uow _parent.OnCompleted(handler); } - public void AddLocalEvent(object eventData) + public void AddOrReplaceLocalEvent( + UnitOfWorkEventRecord eventRecord, + Predicate replacementSelector = null) { - _parent.AddLocalEvent(eventData); + _parent.AddOrReplaceLocalEvent(eventRecord, replacementSelector); } - public void AddDistributedEvent(object eventData) + public void AddOrReplaceDistributedEvent( + UnitOfWorkEventRecord eventRecord, + Predicate replacementSelector = null) { - _parent.AddDistributedEvent(eventData); + _parent.AddOrReplaceDistributedEvent(eventRecord, replacementSelector); } - + public IDatabaseApi FindDatabaseApi(string key) { return _parent.FindDatabaseApi(key); diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs index ed3e185b72..0b8a96297e 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWork.cs @@ -43,8 +43,14 @@ namespace Volo.Abp.Uow void OnCompleted(Func handler); - void AddLocalEvent(object eventData); - - void AddDistributedEvent(object eventData); + void AddOrReplaceLocalEvent( + UnitOfWorkEventRecord eventRecord, + Predicate replacementSelector = null + ); + + void AddOrReplaceDistributedEvent( + UnitOfWorkEventRecord eventRecord, + Predicate replacementSelector = null + ); } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs index 1f4c65165f..521174f36f 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs @@ -5,7 +5,7 @@ namespace Volo.Abp.Uow { public interface IUnitOfWorkEventPublisher { - Task PublishLocalEventsAsync(IEnumerable localEvents); - Task PublishDistributedEventsAsync(IEnumerable distributedEvents); + Task PublishLocalEventsAsync(IEnumerable localEvents); + Task PublishDistributedEventsAsync(IEnumerable distributedEvents); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs index d7ec5436fe..533695f902 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/NullUnitOfWorkEventPublisher.cs @@ -6,12 +6,12 @@ namespace Volo.Abp.Uow { public class NullUnitOfWorkEventPublisher : IUnitOfWorkEventPublisher, ISingletonDependency { - public Task PublishLocalEventsAsync(IEnumerable localEvents) + public Task PublishLocalEventsAsync(IEnumerable localEvents) { return Task.CompletedTask; } - public Task PublishDistributedEventsAsync(IEnumerable distributedEvents) + public Task PublishDistributedEventsAsync(IEnumerable distributedEvents) { return Task.CompletedTask; } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index 8634075d94..d04addbd58 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Collections.ObjectModel; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -35,8 +34,8 @@ namespace Volo.Abp.Uow public string ReservationName { get; set; } protected List> CompletedHandlers { get; } = new List>(); - protected ICollection DistributedEvents { get; } = new Collection(); - protected ICollection LocalEvents { get; } = new Collection(); + protected List DistributedEvents { get; } = new List(); + protected List LocalEvents { get; } = new List(); public event EventHandler Failed; public event EventHandler Disposed; @@ -241,14 +240,41 @@ namespace Volo.Abp.Uow CompletedHandlers.Add(handler); } - public virtual void AddLocalEvent(object eventData) + public virtual void AddOrReplaceLocalEvent( + UnitOfWorkEventRecord eventRecord, + Predicate replacementSelector = null) { - LocalEvents.Add(eventData); + AddOrReplaceEvent(LocalEvents, eventRecord, replacementSelector); } - public virtual void AddDistributedEvent(object eventData) + public virtual void AddOrReplaceDistributedEvent( + UnitOfWorkEventRecord eventRecord, + Predicate replacementSelector = null) { - DistributedEvents.Add(eventData); + AddOrReplaceEvent(DistributedEvents, eventRecord, replacementSelector); + } + + public virtual void AddOrReplaceEvent( + List eventRecords, + UnitOfWorkEventRecord eventRecord, + Predicate replacementSelector = null) + { + if (replacementSelector == null) + { + eventRecords.Add(eventRecord); + } + else + { + var foundIndex = eventRecords.FindIndex(replacementSelector); + if (foundIndex < 0) + { + eventRecords.Add(eventRecord); + } + else + { + eventRecords[foundIndex] = eventRecord; + } + } } protected virtual async Task OnCompletedAsync() diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs new file mode 100644 index 0000000000..2fcfb69f5c --- /dev/null +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.Uow +{ + public class UnitOfWorkEventRecord + { + public object EventData { get; } + + public Type EventType { get; } + + /// + /// Extra properties can be used if needed. + /// + public Dictionary Properties { get; } = new Dictionary(); + + public UnitOfWorkEventRecord( + Type eventType, + object eventData) + { + EventType = eventType; + EventData = eventData; + } + } +} \ No newline at end of file From 9cee59940270ddb41a21823b3ca34cc4a500fff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 26 Aug 2021 08:04:51 +0300 Subject: [PATCH 07/14] Update RabbitMqDistributedEventBus.cs --- .../Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index 541fce1334..76322ee43d 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -196,7 +196,6 @@ namespace Volo.Abp.EventBus.RabbitMq public Task PublishAsync(Type eventType, object eventData, IBasicProperties properties, Dictionary headersArguments = null) { - var eventName = EventNameAttribute.GetNameOrDefault(eventType); var body = Serializer.Serialize(eventData); From e18313e9ebc964ec17fd5f13593fda762c898bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 26 Aug 2021 10:34:57 +0300 Subject: [PATCH 08/14] Added unit test: Should_Rollback_Uow_If_Event_Handler_Throws_Exception --- .../DomainEvents/DomainEvents_Tests.cs | 10 +++++-- .../Abp/TestApp/Testing/DomainEvents_Tests.cs | 28 +++++++++++++++++++ .../Abp/TestApp/Testing/TestAppTestBase.cs | 1 - 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/DomainEvents/DomainEvents_Tests.cs b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/DomainEvents/DomainEvents_Tests.cs index 52af309369..eae88cab0a 100644 --- a/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/DomainEvents/DomainEvents_Tests.cs +++ b/framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/DomainEvents/DomainEvents_Tests.cs @@ -1,9 +1,15 @@ -using Volo.Abp.TestApp.Testing; +using System.Threading.Tasks; +using Volo.Abp.TestApp.Testing; +using Xunit; namespace Volo.Abp.MemoryDb.DomainEvents { public class DomainEvents_Tests : DomainEvents_Tests { - + [Fact(Skip = "MemoryDB doesn't support transactions.")] + public override Task Should_Rollback_Uow_If_Event_Handler_Throws_Exception() + { + return base.Should_Rollback_Uow_If_Event_Handler_Throws_Exception(); + } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs index 3ca7eaf8e4..cdaf60a649 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs @@ -2,11 +2,13 @@ using System.Linq; using System.Threading.Tasks; using Shouldly; +using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Repositories; using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Local; using Volo.Abp.Modularity; using Volo.Abp.TestApp.Domain; +using Volo.Abp.Uow; using Xunit; namespace Volo.Abp.TestApp.Testing @@ -25,6 +27,32 @@ namespace Volo.Abp.TestApp.Testing DistributedEventBus = GetRequiredService(); } + [Fact] + public virtual async Task Should_Rollback_Uow_If_Event_Handler_Throws_Exception() + { + (await PersonRepository.FindAsync(x => x.Name == "TestPerson1")).ShouldBeNull(); + + LocalEventBus.Subscribe>(data => + { + data.Entity.Name.ShouldBe("TestPerson1"); + throw new ApplicationException("Just to rollback the UOW"); + }); + + var exception = await Assert.ThrowsAsync(async () => + { + await WithUnitOfWorkAsync(new AbpUnitOfWorkOptions{IsTransactional = true}, async () => + { + await PersonRepository.InsertAsync( + new Person(Guid.NewGuid(), "TestPerson1", 42) + ); + }); + }); + + exception.Message.ShouldBe("Just to rollback the UOW"); + + (await PersonRepository.FindAsync(x => x.Name == "TestPerson1")).ShouldBeNull(); + } + [Fact] public async Task Should_Trigger_Domain_Events_For_Aggregate_Root() { diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs index f21cc7371b..0fdcd5a2ba 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/TestAppTestBase.cs @@ -31,7 +31,6 @@ namespace Volo.Abp.TestApp.Testing using (var uow = uowManager.Begin(options)) { await action(); - await uow.CompleteAsync(); } } From b966ec77171f2d1939d1106791a65e078fd22791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 26 Aug 2021 12:09:49 +0300 Subject: [PATCH 09/14] Add events to UOW to be published on complete. --- .../Events/EntityChangeEventHelper.cs | 3 +- .../Kafka/KafkaDistributedEventBus.cs | 11 ++++-- .../RabbitMq/RabbitMqDistributedEventBus.cs | 11 ++++-- .../Rebus/RebusDistributedEventBus.cs | 11 ++++-- .../Distributed/LocalDistributedEventBus.cs | 8 ++--- .../Distributed/NullDistributedEventBus.cs | 4 +-- .../Volo/Abp/EventBus/EventBusBase.cs | 27 +++++++++++++-- .../Volo/Abp/EventBus/IEventBus.cs | 6 ++-- .../Volo/Abp/EventBus/Local/LocalEventBus.cs | 11 ++++-- .../Abp/EventBus/Local/NullLocalEventBus.cs | 4 +-- .../Abp/EventBus/UnitOfWorkEventPublisher.cs | 4 +-- .../Abp/TestApp/Testing/DomainEvents_Tests.cs | 34 +++++++++++++++++++ 12 files changed, 110 insertions(+), 24 deletions(-) diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs index 4c81f859d0..87b62efe6e 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -220,7 +220,8 @@ namespace Volo.Abp.Domain.Entities.Events { await eventPublisher.PublishAsync( eventType, - eventData + eventData, + onUnitOfWorkComplete: false ); return; diff --git a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs index 0b228d676c..0be3a326b6 100644 --- a/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Kafka/Volo/Abp/EventBus/Kafka/KafkaDistributedEventBus.cs @@ -12,6 +12,7 @@ using Volo.Abp.EventBus.Distributed; using Volo.Abp.Kafka; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; +using Volo.Abp.Uow; namespace Volo.Abp.EventBus.Kafka { @@ -33,6 +34,7 @@ namespace Volo.Abp.EventBus.Kafka public KafkaDistributedEventBus( IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, IOptions abpKafkaEventBusOptions, IKafkaMessageConsumerFactory messageConsumerFactory, IOptions abpDistributedEventBusOptions, @@ -40,7 +42,7 @@ namespace Volo.Abp.EventBus.Kafka IProducerPool producerPool, IEventErrorHandler errorHandler, IOptions abpEventBusOptions) - : base(serviceScopeFactory, currentTenant, errorHandler) + : base(serviceScopeFactory, currentTenant, unitOfWorkManager, errorHandler) { AbpKafkaEventBusOptions = abpKafkaEventBusOptions.Value; AbpDistributedEventBusOptions = abpDistributedEventBusOptions.Value; @@ -165,11 +167,16 @@ namespace Volo.Abp.EventBus.Kafka GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); } - public override async Task PublishAsync(Type eventType, object eventData) + protected override async Task PublishToEventBusAsync(Type eventType, object eventData) { await PublishAsync(eventType, eventData, new Headers {{"messageId", Serializer.Serialize(Guid.NewGuid())}}, null); } + protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord) + { + unitOfWork.AddOrReplaceDistributedEvent(eventRecord); + } + public virtual async Task PublishAsync(Type eventType, object eventData, Headers headers, Dictionary headersArguments) { await PublishAsync(AbpKafkaEventBusOptions.TopicName, eventType, eventData, headers, headersArguments); diff --git a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs index 76322ee43d..f5e3682a7a 100644 --- a/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.RabbitMQ/Volo/Abp/EventBus/RabbitMq/RabbitMqDistributedEventBus.cs @@ -13,6 +13,7 @@ using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.RabbitMQ; using Volo.Abp.Threading; +using Volo.Abp.Uow; namespace Volo.Abp.EventBus.RabbitMq { @@ -44,9 +45,10 @@ namespace Volo.Abp.EventBus.RabbitMq IOptions distributedEventBusOptions, IRabbitMqMessageConsumerFactory messageConsumerFactory, ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, IEventErrorHandler errorHandler, IOptions abpEventBusOptions) - : base(serviceScopeFactory, currentTenant, errorHandler) + : base(serviceScopeFactory, currentTenant, unitOfWorkManager, errorHandler) { ConnectionPool = connectionPool; Serializer = serializer; @@ -189,11 +191,16 @@ namespace Volo.Abp.EventBus.RabbitMq GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); } - public override async Task PublishAsync(Type eventType, object eventData) + protected override async Task PublishToEventBusAsync(Type eventType, object eventData) { await PublishAsync(eventType, eventData, null); } + protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord) + { + unitOfWork.AddOrReplaceDistributedEvent(eventRecord); + } + public Task PublishAsync(Type eventType, object eventData, IBasicProperties properties, Dictionary headersArguments = null) { var eventName = EventNameAttribute.GetNameOrDefault(eventType); diff --git a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs index 97bedaf8fb..0206b5fefc 100644 --- a/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus.Rebus/Volo/Abp/EventBus/Rebus/RebusDistributedEventBus.cs @@ -10,6 +10,7 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; +using Volo.Abp.Uow; namespace Volo.Abp.EventBus.Rebus { @@ -28,11 +29,12 @@ namespace Volo.Abp.EventBus.Rebus public RebusDistributedEventBus( IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, IBus rebus, IOptions abpDistributedEventBusOptions, IOptions abpEventBusRebusOptions, IEventErrorHandler errorHandler) : - base(serviceScopeFactory, currentTenant, errorHandler) + base(serviceScopeFactory, currentTenant, unitOfWorkManager, errorHandler) { Rebus = rebus; AbpRebusEventBusOptions = abpEventBusRebusOptions.Value; @@ -125,11 +127,16 @@ namespace Volo.Abp.EventBus.Rebus return Subscribe(typeof(TEvent), handler); } - public override async Task PublishAsync(Type eventType, object eventData) + protected override async Task PublishToEventBusAsync(Type eventType, object eventData) { await AbpRebusEventBusOptions.Publish(Rebus, eventType, eventData); } + protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord) + { + unitOfWork.AddOrReplaceDistributedEvent(eventRecord); + } + private List GetOrCreateHandlerFactories(Type eventType) { return HandlerFactories.GetOrAdd( 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 0d0ea6b107..3ee3700a0d 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 @@ -122,15 +122,15 @@ namespace Volo.Abp.EventBus.Distributed _localEventBus.UnsubscribeAll(eventType); } - public Task PublishAsync(TEvent eventData) + public Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true) where TEvent : class { - return _localEventBus.PublishAsync(eventData); + return _localEventBus.PublishAsync(eventData, onUnitOfWorkComplete); } - public Task PublishAsync(Type eventType, object eventData) + public Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true) { - return _localEventBus.PublishAsync(eventType, eventData); + return _localEventBus.PublishAsync(eventType, eventData, onUnitOfWorkComplete); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/NullDistributedEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/NullDistributedEventBus.cs index cfec832893..60be7a147c 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/NullDistributedEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Distributed/NullDistributedEventBus.cs @@ -77,12 +77,12 @@ namespace Volo.Abp.EventBus.Distributed } - public Task PublishAsync(TEvent eventData) where TEvent : class + public Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true) where TEvent : class { return Task.CompletedTask; } - public Task PublishAsync(Type eventType, object eventData) + public Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true) { return Task.CompletedTask; } diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index 78d226538e..b5318b48ef 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs @@ -10,6 +10,7 @@ using Volo.Abp.Collections; using Volo.Abp.EventBus.Distributed; using Volo.Abp.MultiTenancy; using Volo.Abp.Reflection; +using Volo.Abp.Uow; namespace Volo.Abp.EventBus { @@ -18,16 +19,20 @@ namespace Volo.Abp.EventBus protected IServiceScopeFactory ServiceScopeFactory { get; } protected ICurrentTenant CurrentTenant { get; } + + protected IUnitOfWorkManager UnitOfWorkManager { get; } protected IEventErrorHandler ErrorHandler { get; } protected EventBusBase( IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, IEventErrorHandler errorHandler) { ServiceScopeFactory = serviceScopeFactory; CurrentTenant = currentTenant; + UnitOfWorkManager = unitOfWorkManager; ErrorHandler = errorHandler; } @@ -87,13 +92,29 @@ namespace Volo.Abp.EventBus public abstract void UnsubscribeAll(Type eventType); /// - public virtual Task PublishAsync(TEvent eventData) where TEvent : class + public Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true) where TEvent : class { - return PublishAsync(typeof(TEvent), eventData); + return PublishAsync(typeof(TEvent), eventData, onUnitOfWorkComplete); } /// - public abstract Task PublishAsync(Type eventType, object eventData); + public async Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true) + { + if (onUnitOfWorkComplete && UnitOfWorkManager.Current != null) + { + AddToUnitOfWork( + UnitOfWorkManager.Current, + new UnitOfWorkEventRecord(eventType, eventData) + ); + return; + } + + await PublishToEventBusAsync(eventType, eventData); + } + + protected abstract Task PublishToEventBusAsync(Type eventType, object eventData); + + protected abstract void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord); public virtual async Task TriggerHandlersAsync(Type eventType, object eventData, Action onErrorAction = null) { diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs index d28b3ab2a4..6fb424c550 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/IEventBus.cs @@ -10,8 +10,9 @@ namespace Volo.Abp.EventBus /// /// Event type /// Related data for the event + /// True, to publish the event at the end of the current unit of work, if available /// The task to handle async operation - Task PublishAsync(TEvent eventData) + Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true) where TEvent : class; /// @@ -19,8 +20,9 @@ namespace Volo.Abp.EventBus /// /// Event type /// Related data for the event + /// True, to publish the event at the end of the current unit of work, if available /// The task to handle async operation - Task PublishAsync(Type eventType, object eventData); + Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true); /// /// Registers to an event. diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs index 3dc6045250..77bf5b43bd 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/LocalEventBus.cs @@ -12,6 +12,7 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; using Volo.Abp.Threading; using Volo.Abp.Json; +using Volo.Abp.Uow; namespace Volo.Abp.EventBus.Local { @@ -34,8 +35,9 @@ namespace Volo.Abp.EventBus.Local IOptions options, IServiceScopeFactory serviceScopeFactory, ICurrentTenant currentTenant, + IUnitOfWorkManager unitOfWorkManager, IEventErrorHandler errorHandler) - : base(serviceScopeFactory, currentTenant, errorHandler) + : base(serviceScopeFactory, currentTenant, unitOfWorkManager, errorHandler) { Options = options.Value; Logger = NullLogger.Instance; @@ -120,11 +122,16 @@ namespace Volo.Abp.EventBus.Local GetOrCreateHandlerFactories(eventType).Locking(factories => factories.Clear()); } - public override async Task PublishAsync(Type eventType, object eventData) + protected override async Task PublishToEventBusAsync(Type eventType, object eventData) { await PublishAsync(new LocalEventMessage(Guid.NewGuid(), eventData, eventType)); } + protected override void AddToUnitOfWork(IUnitOfWork unitOfWork, UnitOfWorkEventRecord eventRecord) + { + unitOfWork.AddOrReplaceLocalEvent(eventRecord); + } + public virtual async Task PublishAsync(LocalEventMessage localEventMessage) { await TriggerHandlersAsync(localEventMessage.EventType, localEventMessage.EventData, errorContext => diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/NullLocalEventBus.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/NullLocalEventBus.cs index 5c74af2195..f3eab30dc1 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/NullLocalEventBus.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/Local/NullLocalEventBus.cs @@ -77,12 +77,12 @@ namespace Volo.Abp.EventBus.Local } - public Task PublishAsync(TEvent eventData) where TEvent : class + public Task PublishAsync(TEvent eventData, bool onUnitOfWorkComplete = true) where TEvent : class { return Task.CompletedTask; } - public Task PublishAsync(Type eventType, object eventData) + public Task PublishAsync(Type eventType, object eventData, bool onUnitOfWorkComplete = true) { return Task.CompletedTask; } diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/UnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/UnitOfWorkEventPublisher.cs index fd8d3aec2d..65e271afa8 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/UnitOfWorkEventPublisher.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/UnitOfWorkEventPublisher.cs @@ -25,7 +25,7 @@ namespace Volo.Abp.EventBus { foreach (var localEvent in localEvents) { - await _localEventBus.PublishAsync(localEvent.EventType, localEvent.EventData); + await _localEventBus.PublishAsync(localEvent.EventType, localEvent.EventData, onUnitOfWorkComplete: false); } } @@ -33,7 +33,7 @@ namespace Volo.Abp.EventBus { foreach (var distributedEvent in distributedEvents) { - await _distributedEventBus.PublishAsync(distributedEvent.EventType, distributedEvent.EventData); + await _distributedEventBus.PublishAsync(distributedEvent.EventType, distributedEvent.EventData, onUnitOfWorkComplete: false); } } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs index cdaf60a649..ef789f57f5 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs @@ -27,6 +27,35 @@ namespace Volo.Abp.TestApp.Testing DistributedEventBus = GetRequiredService(); } + [Fact] + public virtual async Task Should_Publish_Events_In_Order() + { + bool entityCreatedEventHandled = false; + + LocalEventBus.Subscribe>(data => + { + data.Entity.Name.ShouldBe("TestPerson1"); + entityCreatedEventHandled = true; + return Task.CompletedTask; + }); + + LocalEventBus.Subscribe(data => + { + data.Value.ShouldBe("42"); + entityCreatedEventHandled.ShouldBe(true); + return Task.CompletedTask; + }); + + await WithUnitOfWorkAsync(new AbpUnitOfWorkOptions{IsTransactional = true}, async () => + { + await PersonRepository.InsertAsync( + new Person(Guid.NewGuid(), "TestPerson1", 42) + ); + + await LocalEventBus.PublishAsync(new MyCustomEventData { Value = "42" }); + }); + } + [Fact] public virtual async Task Should_Rollback_Uow_If_Event_Handler_Throws_Exception() { @@ -91,5 +120,10 @@ namespace Volo.Abp.TestApp.Testing isLocalEventTriggered.ShouldBeTrue(); isDistributedEventTriggered.ShouldBeTrue(); } + + private class MyCustomEventData + { + public string Value { get; set; } + } } } \ No newline at end of file From 258cf783f798819d248c530105c53ba1a7b4ade9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 27 Aug 2021 16:31:03 +0300 Subject: [PATCH 10/14] Events should be published and handled in the right order. --- .../Abp/Domain/Entities/BasicAggregateRoot.cs | 25 +-- .../Abp/Domain/Entities/DomainEventRecord.cs | 15 ++ .../Entities/Events/DomainEventEntry.cs | 5 +- .../Events/EntityChangeEventHelper.cs | 91 ++------- .../Entities/Events/EntityChangeReport.cs | 32 ---- .../Entities/Events/EntityEventReport.cs | 22 +++ .../Events/IEntityChangeEventHelper.cs | 16 +- .../Events/NullEntityChangeEventHelper.cs | 26 +-- .../Domain/Entities/IGeneratesDomainEvents.cs | 4 +- .../Abp/EntityFrameworkCore/AbpDbContext.cs | 176 ++++++++++++------ .../Volo/Abp/EventBus/EventBusBase.cs | 2 +- .../MemoryDb/MemoryDbRepository.cs | 47 ++--- .../Repositories/MongoDB/MongoDbRepository.cs | 53 +++--- .../Volo/Abp/Uow/AmbientUnitOfWork.cs | 13 ++ .../Volo/Abp/Uow/EventOrderGenerator.cs | 14 ++ .../Volo/Abp/Uow/IAmbientUnitOfWork.cs | 2 +- .../Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs | 4 +- .../Volo/Abp/Uow/UnitOfWorkEventRecord.cs | 6 +- .../Volo/Abp/Uow/UnitOfWorkManager.cs | 15 +- .../Abp/TestApp/Testing/DomainEvents_Tests.cs | 63 ++++++- .../Testing/EntityChangeEvents_Tests.cs | 14 +- 21 files changed, 368 insertions(+), 277 deletions(-) create mode 100644 framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/DomainEventRecord.cs delete mode 100644 framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs create mode 100644 framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityEventReport.cs create mode 100644 framework/src/Volo.Abp.Uow/Volo/Abp/Uow/EventOrderGenerator.cs diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs index 42b0ba1320..a4a90d1504 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/BasicAggregateRoot.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using Volo.Abp.Uow; namespace Volo.Abp.Domain.Entities { @@ -9,15 +10,15 @@ namespace Volo.Abp.Domain.Entities IAggregateRoot, IGeneratesDomainEvents { - private readonly ICollection _distributedEvents = new Collection(); - private readonly ICollection _localEvents = new Collection(); + private readonly ICollection _distributedEvents = new Collection(); + private readonly ICollection _localEvents = new Collection(); - public virtual IEnumerable GetLocalEvents() + public virtual IEnumerable GetLocalEvents() { return _localEvents; } - public virtual IEnumerable GetDistributedEvents() + public virtual IEnumerable GetDistributedEvents() { return _distributedEvents; } @@ -34,12 +35,12 @@ namespace Volo.Abp.Domain.Entities protected virtual void AddLocalEvent(object eventData) { - _localEvents.Add(eventData); + _localEvents.Add(new DomainEventRecord(eventData, EventOrderGenerator.GetNext())); } protected virtual void AddDistributedEvent(object eventData) { - _distributedEvents.Add(eventData); + _distributedEvents.Add(new DomainEventRecord(eventData, EventOrderGenerator.GetNext())); } } @@ -48,8 +49,8 @@ namespace Volo.Abp.Domain.Entities IAggregateRoot, IGeneratesDomainEvents { - private readonly ICollection _distributedEvents = new Collection(); - private readonly ICollection _localEvents = new Collection(); + private readonly ICollection _distributedEvents = new Collection(); + private readonly ICollection _localEvents = new Collection(); protected BasicAggregateRoot() { @@ -62,12 +63,12 @@ namespace Volo.Abp.Domain.Entities } - public virtual IEnumerable GetLocalEvents() + public virtual IEnumerable GetLocalEvents() { return _localEvents; } - public virtual IEnumerable GetDistributedEvents() + public virtual IEnumerable GetDistributedEvents() { return _distributedEvents; } @@ -84,12 +85,12 @@ namespace Volo.Abp.Domain.Entities protected virtual void AddLocalEvent(object eventData) { - _localEvents.Add(eventData); + _localEvents.Add(new DomainEventRecord(eventData, EventOrderGenerator.GetNext())); } protected virtual void AddDistributedEvent(object eventData) { - _distributedEvents.Add(eventData); + _distributedEvents.Add(new DomainEventRecord(eventData, EventOrderGenerator.GetNext())); } } } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/DomainEventRecord.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/DomainEventRecord.cs new file mode 100644 index 0000000000..bfe8988417 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/DomainEventRecord.cs @@ -0,0 +1,15 @@ +namespace Volo.Abp.Domain.Entities +{ + public class DomainEventRecord + { + public object EventData { get; } + + public long EventOrder { get; } + + public DomainEventRecord(object eventData, long eventOrder) + { + EventData = eventData; + EventOrder = eventOrder; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/DomainEventEntry.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/DomainEventEntry.cs index e0b645d1c5..5400a2f199 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/DomainEventEntry.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/DomainEventEntry.cs @@ -8,11 +8,14 @@ namespace Volo.Abp.Domain.Entities.Events public object SourceEntity { get; } public object EventData { get; } + + public long EventOrder { get; } - public DomainEventEntry(object sourceEntity, object eventData) + public DomainEventEntry(object sourceEntity, object eventData, long eventOrder) { SourceEntity = sourceEntity; EventData = eventData; + EventOrder = eventOrder; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs index 87b62efe6e..9fc5c1e90d 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; -using Volo.Abp.Auditing; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities.Events.Distributed; using Volo.Abp.DynamicProxy; @@ -44,16 +42,9 @@ namespace Volo.Abp.Domain.Entities.Events Logger = NullLogger.Instance; } - public async Task TriggerEventsAsync(EntityChangeReport changeReport) + public virtual void PublishEntityCreatingEvent(object entity) { - await TriggerEntityChangeEvents(changeReport.ChangedEntities); - await TriggerLocalEvents(changeReport.DomainEvents); - await TriggerDistributedEvents(changeReport.DistributedEvents); - } - - public virtual async Task TriggerEntityCreatingEventAsync(object entity) - { - await TriggerEventWithEntity( + TriggerEventWithEntity( LocalEventBus, typeof(EntityCreatingEventData<>), entity, @@ -61,9 +52,9 @@ namespace Volo.Abp.Domain.Entities.Events ); } - public virtual async Task TriggerEntityCreatedEventAsync(object entity) + public virtual void PublishEntityCreatedEvent(object entity) { - await TriggerEventWithEntity( + TriggerEventWithEntity( LocalEventBus, typeof(EntityCreatedEventData<>), entity, @@ -75,7 +66,7 @@ namespace Volo.Abp.Domain.Entities.Events var eto = EntityToEtoMapper.Map(entity); if (eto != null) { - await TriggerEventWithEntity( + TriggerEventWithEntity( DistributedEventBus, typeof(EntityCreatedEto<>), eto, @@ -96,9 +87,9 @@ namespace Volo.Abp.Domain.Entities.Events ); } - public virtual async Task TriggerEntityUpdatingEventAsync(object entity) + public virtual void PublishEntityUpdatingEvent(object entity) { - await TriggerEventWithEntity( + TriggerEventWithEntity( LocalEventBus, typeof(EntityUpdatingEventData<>), entity, @@ -106,9 +97,9 @@ namespace Volo.Abp.Domain.Entities.Events ); } - public virtual async Task TriggerEntityUpdatedEventAsync(object entity) + public virtual void PublishEntityUpdatedEvent(object entity) { - await TriggerEventWithEntity( + TriggerEventWithEntity( LocalEventBus, typeof(EntityUpdatedEventData<>), entity, @@ -120,7 +111,7 @@ namespace Volo.Abp.Domain.Entities.Events var eto = EntityToEtoMapper.Map(entity); if (eto != null) { - await TriggerEventWithEntity( + TriggerEventWithEntity( DistributedEventBus, typeof(EntityUpdatedEto<>), eto, @@ -130,9 +121,9 @@ namespace Volo.Abp.Domain.Entities.Events } } - public virtual async Task TriggerEntityDeletingEventAsync(object entity) + public virtual void PublishEntityDeletingEvent(object entity) { - await TriggerEventWithEntity( + TriggerEventWithEntity( LocalEventBus, typeof(EntityDeletingEventData<>), entity, @@ -140,9 +131,9 @@ namespace Volo.Abp.Domain.Entities.Events ); } - public virtual async Task TriggerEntityDeletedEventAsync(object entity) + public virtual void PublishEntityDeletedEvent(object entity) { - await TriggerEventWithEntity( + TriggerEventWithEntity( LocalEventBus, typeof(EntityDeletedEventData<>), entity, @@ -154,7 +145,7 @@ namespace Volo.Abp.Domain.Entities.Events var eto = EntityToEtoMapper.Map(entity); if (eto != null) { - await TriggerEventWithEntity( + TriggerEventWithEntity( DistributedEventBus, typeof(EntityDeletedEto<>), eto, @@ -164,48 +155,7 @@ namespace Volo.Abp.Domain.Entities.Events } } - protected virtual async Task TriggerEntityChangeEvents(List changedEntities) - { - foreach (var changedEntity in changedEntities) - { - switch (changedEntity.ChangeType) - { - case EntityChangeType.Created: - await TriggerEntityCreatingEventAsync(changedEntity.Entity); - await TriggerEntityCreatedEventAsync(changedEntity.Entity); - break; - case EntityChangeType.Updated: - await TriggerEntityUpdatingEventAsync(changedEntity.Entity); - await TriggerEntityUpdatedEventAsync(changedEntity.Entity); - break; - case EntityChangeType.Deleted: - await TriggerEntityDeletingEventAsync(changedEntity.Entity); - await TriggerEntityDeletedEventAsync(changedEntity.Entity); - break; - default: - throw new AbpException("Unknown EntityChangeType: " + changedEntity.ChangeType); - } - } - } - - protected virtual async Task TriggerLocalEvents(List localEvents) - { - foreach (var localEvent in localEvents) - { - await LocalEventBus.PublishAsync(localEvent.EventData.GetType(), localEvent.EventData); - } - } - - protected virtual async Task TriggerDistributedEvents(List distributedEvents) - { - foreach (var distributedEvent in distributedEvents) - { - await DistributedEventBus.PublishAsync(distributedEvent.EventData.GetType(), - distributedEvent.EventData); - } - } - - protected virtual async Task TriggerEventWithEntity( + protected virtual void TriggerEventWithEntity( IEventBus eventPublisher, Type genericEventType, object entityOrEto, @@ -218,16 +168,11 @@ namespace Volo.Abp.Domain.Entities.Events if (currentUow == null) { - await eventPublisher.PublishAsync( - eventType, - eventData, - onUnitOfWorkComplete: false - ); - + Logger.LogWarning("UnitOfWorkManager.Current is null! Can not publish the event."); return; } - var eventRecord = new UnitOfWorkEventRecord(eventType, eventData) + var eventRecord = new UnitOfWorkEventRecord(eventType, eventData, EventOrderGenerator.GetNext()) { Properties = { diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs deleted file mode 100644 index 921de844c7..0000000000 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeReport.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Abp.Domain.Entities.Events -{ - public class EntityChangeReport - { - public List ChangedEntities { get; } - - public List DomainEvents { get; } - - public List DistributedEvents { get; } - - public EntityChangeReport() - { - ChangedEntities = new List(); - DomainEvents = new List(); - DistributedEvents = new List(); - } - - public bool IsEmpty() - { - return ChangedEntities.Count <= 0 && - DomainEvents.Count <= 0 && - DistributedEvents.Count <= 0; - } - - public override string ToString() - { - return $"[EntityChangeReport] ChangedEntities: {ChangedEntities.Count}, DomainEvents: {DomainEvents.Count}, DistributedEvents: {DistributedEvents.Count}"; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityEventReport.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityEventReport.cs new file mode 100644 index 0000000000..093a389206 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityEventReport.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Domain.Entities.Events +{ + public class EntityEventReport + { + public List DomainEvents { get; } + + public List DistributedEvents { get; } + + public EntityEventReport() + { + DomainEvents = new List(); + DistributedEvents = new List(); + } + + public override string ToString() + { + return $"[{nameof(EntityEventReport)}] DomainEvents: {DomainEvents.Count}, DistributedEvents: {DistributedEvents.Count}"; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs index c13cb94453..1c54dc4578 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/IEntityChangeEventHelper.cs @@ -1,5 +1,3 @@ -using System.Threading.Tasks; - namespace Volo.Abp.Domain.Entities.Events { /// @@ -7,15 +5,13 @@ namespace Volo.Abp.Domain.Entities.Events /// public interface IEntityChangeEventHelper { - Task TriggerEventsAsync(EntityChangeReport changeReport); - - Task TriggerEntityCreatingEventAsync(object entity); - Task TriggerEntityCreatedEventAsync(object entity); + void PublishEntityCreatingEvent(object entity); + void PublishEntityCreatedEvent(object entity); - Task TriggerEntityUpdatingEventAsync(object entity); - Task TriggerEntityUpdatedEventAsync(object entity); + void PublishEntityUpdatingEvent(object entity); + void PublishEntityUpdatedEvent(object entity); - Task TriggerEntityDeletingEventAsync(object entity); - Task TriggerEntityDeletedEventAsync(object entity); + void PublishEntityDeletingEvent(object entity); + void PublishEntityDeletedEvent(object entity); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs index c4b1f66a92..7f8adb575e 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/NullEntityChangeEventHelper.cs @@ -1,5 +1,3 @@ -using System.Threading.Tasks; - namespace Volo.Abp.Domain.Entities.Events { /// @@ -14,42 +12,30 @@ namespace Volo.Abp.Domain.Entities.Events private NullEntityChangeEventHelper() { - - } - - public Task TriggerEntityCreatingEventAsync(object entity) - { - return Task.CompletedTask; } - public Task TriggerEntityCreatedEventAsync(object entity) + public void PublishEntityCreatingEvent(object entity) { - return Task.CompletedTask; } - public Task TriggerEntityUpdatingEventAsync(object entity) + public void PublishEntityCreatedEvent(object entity) { - return Task.CompletedTask; } - public Task TriggerEntityUpdatedEventAsync(object entity) + public void PublishEntityUpdatingEvent(object entity) { - return Task.CompletedTask; } - public Task TriggerEntityDeletingEventAsync(object entity) + public void PublishEntityUpdatedEvent(object entity) { - return Task.CompletedTask; } - public Task TriggerEntityDeletedEventAsync(object entity) + public void PublishEntityDeletingEvent(object entity) { - return Task.CompletedTask; } - public Task TriggerEventsAsync(EntityChangeReport changeReport) + public void PublishEntityDeletedEvent(object entity) { - return Task.CompletedTask; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IGeneratesDomainEvents.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IGeneratesDomainEvents.cs index 5d0d5c7959..a101f6b3e9 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IGeneratesDomainEvents.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/IGeneratesDomainEvents.cs @@ -6,9 +6,9 @@ namespace Volo.Abp.Domain.Entities public interface IGeneratesDomainEvents { - IEnumerable GetLocalEvents(); + IEnumerable GetLocalEvents(); - IEnumerable GetDistributedEvents(); + IEnumerable GetDistributedEvents(); void ClearLocalEvents(); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 9b488924e8..b86f9b83b1 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -22,6 +22,8 @@ using Volo.Abp.Domain.Repositories; using Volo.Abp.EntityFrameworkCore.EntityHistory; using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.ValueConverters; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.EventBus.Local; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; using Volo.Abp.ObjectExtending; @@ -59,6 +61,10 @@ namespace Volo.Abp.EntityFrameworkCore public IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService(); public IClock Clock => LazyServiceProvider.LazyGetRequiredService(); + + public IDistributedEventBus DistributedEventBus => LazyServiceProvider.LazyGetRequiredService(); + + public ILocalEventBus LocalEventBus => LazyServiceProvider.LazyGetRequiredService(); public ILogger> Logger => LazyServiceProvider.LazyGetService>>(NullLogger>.Instance); @@ -150,20 +156,21 @@ namespace Volo.Abp.EntityFrameworkCore try { var auditLog = AuditingManager?.Current?.Log; - List entityChangeList = null; if (auditLog != null) { entityChangeList = EntityHistoryHelper.CreateChangeList(ChangeTracker.Entries().ToList()); } - var changeReport = ApplyAbpConcepts(); - + ApplyAbpConcepts(); + + var eventReport = CreateEventReport(); + var result = await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); - - await EntityChangeEventHelper.TriggerEventsAsync(changeReport); - - if (auditLog != null) + + PublishEntityEvents(eventReport); + + if (entityChangeList != null) { EntityHistoryHelper.UpdateChangeList(entityChangeList); auditLog.EntityChanges.AddRange(entityChangeList); @@ -182,6 +189,23 @@ namespace Volo.Abp.EntityFrameworkCore } } + private void PublishEntityEvents(EntityEventReport changeReport) + { + foreach (var localEvent in changeReport.DomainEvents) + { + UnitOfWorkManager.Current?.AddOrReplaceLocalEvent( + new UnitOfWorkEventRecord(localEvent.EventData.GetType(), localEvent.EventData, localEvent.EventOrder) + ); + } + + foreach (var distributedEvent in changeReport.DistributedEvents) + { + UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent( + new UnitOfWorkEventRecord(distributedEvent.EventData.GetType(), distributedEvent.EventData, distributedEvent.EventOrder) + ); + } + } + /// /// This method will call the DbContext method directly of EF Core, which doesn't apply concepts of abp. /// @@ -202,11 +226,18 @@ namespace Volo.Abp.EntityFrameworkCore ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges; ChangeTracker.Tracked += ChangeTracker_Tracked; + ChangeTracker.StateChanged += ChangeTracker_StateChanged; } protected virtual void ChangeTracker_Tracked(object sender, EntityTrackedEventArgs e) { FillExtraPropertiesForTrackedEntities(e); + PublishEventsForTrackedEntity(e.Entry); + } + + protected virtual void ChangeTracker_StateChanged(object sender, EntityStateChangedEventArgs e) + { + PublishEventsForTrackedEntity(e.Entry); } protected virtual void FillExtraPropertiesForTrackedEntities(EntityTrackedEventArgs e) @@ -254,37 +285,107 @@ namespace Volo.Abp.EntityFrameworkCore } } } - - protected virtual EntityChangeReport ApplyAbpConcepts() + + private void PublishEventsForTrackedEntity(EntityEntry entry) { - var changeReport = new EntityChangeReport(); + switch (entry.State) + { + case EntityState.Added: + EntityChangeEventHelper.PublishEntityCreatingEvent(entry.Entity); + EntityChangeEventHelper.PublishEntityCreatedEvent(entry.Entity); + break; + case EntityState.Modified: + if (entry.Properties.Any(x => x.IsModified && x.Metadata.ValueGenerated == ValueGenerated.Never)) + { + if (entry.Entity is ISoftDelete && entry.Entity.As().IsDeleted) + { + EntityChangeEventHelper.PublishEntityDeletingEvent(entry.Entity); + EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity); + } + else + { + EntityChangeEventHelper.PublishEntityUpdatingEvent(entry.Entity); + EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity); + } + } + + break; + case EntityState.Deleted: + EntityChangeEventHelper.PublishEntityDeletingEvent(entry.Entity); + EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity); + break; + } + } + protected virtual void ApplyAbpConcepts() + { foreach (var entry in ChangeTracker.Entries().ToList()) { - ApplyAbpConcepts(entry, changeReport); + ApplyAbpConcepts(entry); } - - return changeReport; } + + protected virtual EntityEventReport CreateEventReport() + { + var eventReport = new EntityEventReport(); + + foreach (var entry in ChangeTracker.Entries().ToList()) + { + var generatesDomainEventsEntity = entry.Entity as IGeneratesDomainEvents; + if (generatesDomainEventsEntity == null) + { + continue; + } - protected virtual void ApplyAbpConcepts(EntityEntry entry, EntityChangeReport changeReport) + var localEvents = generatesDomainEventsEntity.GetLocalEvents()?.ToArray(); + if (localEvents != null && localEvents.Any()) + { + eventReport.DomainEvents.AddRange( + localEvents.Select( + eventRecord => new DomainEventEntry( + entry.Entity, + eventRecord.EventData, + eventRecord.EventOrder + ) + ) + ); + generatesDomainEventsEntity.ClearLocalEvents(); + } + + var distributedEvents = generatesDomainEventsEntity.GetDistributedEvents()?.ToArray(); + if (distributedEvents != null && distributedEvents.Any()) + { + eventReport.DistributedEvents.AddRange( + distributedEvents.Select( + eventRecord => new DomainEventEntry( + entry.Entity, + eventRecord.EventData, + eventRecord.EventOrder) + ) + ); + generatesDomainEventsEntity.ClearDistributedEvents(); + } + } + + return eventReport; + } + + protected virtual void ApplyAbpConcepts(EntityEntry entry) { switch (entry.State) { case EntityState.Added: - ApplyAbpConceptsForAddedEntity(entry, changeReport); + ApplyAbpConceptsForAddedEntity(entry); break; case EntityState.Modified: - ApplyAbpConceptsForModifiedEntity(entry, changeReport); + ApplyAbpConceptsForModifiedEntity(entry); break; case EntityState.Deleted: - ApplyAbpConceptsForDeletedEntity(entry, changeReport); + ApplyAbpConceptsForDeletedEntity(entry); break; } HandleExtraPropertiesOnSave(entry); - - AddDomainEvents(changeReport, entry.Entity); } protected virtual void HandleExtraPropertiesOnSave(EntityEntry entry) @@ -361,15 +462,14 @@ namespace Volo.Abp.EntityFrameworkCore } } - protected virtual void ApplyAbpConceptsForAddedEntity(EntityEntry entry, EntityChangeReport changeReport) + protected virtual void ApplyAbpConceptsForAddedEntity(EntityEntry entry) { CheckAndSetId(entry); SetConcurrencyStampIfNull(entry); SetCreationAuditProperties(entry); - changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Created)); } - protected virtual void ApplyAbpConceptsForModifiedEntity(EntityEntry entry, EntityChangeReport changeReport) + protected virtual void ApplyAbpConceptsForModifiedEntity(EntityEntry entry) { if (entry.State == EntityState.Modified && entry.Properties.Any(x => x.IsModified && x.Metadata.ValueGenerated == ValueGenerated.Never)) { @@ -379,24 +479,17 @@ namespace Volo.Abp.EntityFrameworkCore if (entry.Entity is ISoftDelete && entry.Entity.As().IsDeleted) { SetDeletionAuditProperties(entry); - changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted)); - } - else - { - changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Updated)); } } } - protected virtual void ApplyAbpConceptsForDeletedEntity(EntityEntry entry, EntityChangeReport changeReport) + protected virtual void ApplyAbpConceptsForDeletedEntity(EntityEntry entry) { if (TryCancelDeletionForSoftDelete(entry)) { UpdateConcurrencyStamp(entry); SetDeletionAuditProperties(entry); } - - changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted)); } protected virtual bool IsHardDeleted(EntityEntry entry) @@ -410,29 +503,6 @@ namespace Volo.Abp.EntityFrameworkCore return hardDeletedEntities.Contains(entry.Entity); } - protected virtual void AddDomainEvents(EntityChangeReport changeReport, object entityAsObj) - { - var generatesDomainEventsEntity = entityAsObj as IGeneratesDomainEvents; - if (generatesDomainEventsEntity == null) - { - return; - } - - var localEvents = generatesDomainEventsEntity.GetLocalEvents()?.ToArray(); - if (localEvents != null && localEvents.Any()) - { - changeReport.DomainEvents.AddRange(localEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData))); - generatesDomainEventsEntity.ClearLocalEvents(); - } - - var distributedEvents = generatesDomainEventsEntity.GetDistributedEvents()?.ToArray(); - if (distributedEvents != null && distributedEvents.Any()) - { - changeReport.DistributedEvents.AddRange(distributedEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData))); - generatesDomainEventsEntity.ClearDistributedEvents(); - } - } - protected virtual void UpdateConcurrencyStamp(EntityEntry entry) { var entity = entry.Entity as IHasConcurrencyStamp; diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index b5318b48ef..40c36dd8be 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs @@ -104,7 +104,7 @@ namespace Volo.Abp.EventBus { AddToUnitOfWork( UnitOfWorkManager.Current, - new UnitOfWorkEventRecord(eventType, eventData) + new UnitOfWorkEventRecord(eventType, eventData, EventOrderGenerator.GetNext()) ); return; } diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index 8451a5ab79..37c744547f 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -12,6 +12,7 @@ using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Local; using Volo.Abp.Guids; using Volo.Abp.MemoryDb; +using Volo.Abp.Uow; namespace Volo.Abp.Domain.Repositories.MemoryDb { @@ -65,7 +66,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb return ApplyDataFilters((await GetCollectionAsync()).AsQueryable()); } - protected virtual async Task TriggerDomainEventsAsync(object entity) + protected virtual void TriggerDomainEvents(object entity) { var generatesDomainEventsEntity = entity as IGeneratesDomainEvents; if (generatesDomainEventsEntity == null) @@ -78,7 +79,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { foreach (var localEvent in localEvents) { - await LocalEventBus.PublishAsync(localEvent.GetType(), localEvent); + UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(new UnitOfWorkEventRecord(localEvent.GetType(), localEvent, EventOrderGenerator.GetNext())); } generatesDomainEventsEntity.ClearLocalEvents(); @@ -89,7 +90,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { foreach (var distributedEvent in distributedEvents) { - await DistributedEventBus.PublishAsync(distributedEvent.GetType(), distributedEvent); + UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(new UnitOfWorkEventRecord(distributedEvent.GetType(), distributedEvent, EventOrderGenerator.GetNext())); } generatesDomainEventsEntity.ClearDistributedEvents(); @@ -143,37 +144,37 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb AuditPropertySetter.SetDeletionProperties(entity); } - protected virtual async Task TriggerEntityCreateEvents(TEntity entity) + protected virtual void TriggerEntityCreateEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity); - await EntityChangeEventHelper.TriggerEntityCreatedEventAsync(entity); + EntityChangeEventHelper.PublishEntityCreatingEvent(entity); + EntityChangeEventHelper.PublishEntityCreatedEvent(entity); } - protected virtual async Task TriggerEntityUpdateEventsAsync(TEntity entity) + protected virtual void TriggerEntityUpdateEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity); - await EntityChangeEventHelper.TriggerEntityUpdatedEventAsync(entity); + EntityChangeEventHelper.PublishEntityUpdatingEvent(entity); + EntityChangeEventHelper.PublishEntityUpdatedEvent(entity); } - protected virtual async Task TriggerEntityDeleteEventsAsync(TEntity entity) + protected virtual void TriggerEntityDeleteEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity); - await EntityChangeEventHelper.TriggerEntityDeletedEventAsync(entity); + EntityChangeEventHelper.PublishEntityDeletingEvent(entity); + EntityChangeEventHelper.PublishEntityDeletedEvent(entity); } - protected virtual async Task ApplyAbpConceptsForAddedEntityAsync(TEntity entity) + protected virtual void ApplyAbpConceptsForAddedEntity(TEntity entity) { CheckAndSetId(entity); SetCreationAuditProperties(entity); - await TriggerEntityCreateEvents(entity); - await TriggerDomainEventsAsync(entity); + TriggerEntityCreateEvents(entity); + TriggerDomainEvents(entity); } - protected virtual async Task ApplyAbpConceptsForDeletedEntityAsync(TEntity entity) + protected virtual void ApplyAbpConceptsForDeletedEntity(TEntity entity) { SetDeletionAuditProperties(entity); - await TriggerEntityDeleteEventsAsync(entity); - await TriggerDomainEventsAsync(entity); + TriggerEntityDeleteEvents(entity); + TriggerDomainEvents(entity); } public override async Task FindAsync( @@ -199,7 +200,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb bool autoSave = false, CancellationToken cancellationToken = default) { - await ApplyAbpConceptsForAddedEntityAsync(entity); + ApplyAbpConceptsForAddedEntity(entity); (await GetCollectionAsync()).Add(entity); @@ -216,14 +217,14 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted) { SetDeletionAuditProperties(entity); - await TriggerEntityDeleteEventsAsync(entity); + TriggerEntityDeleteEvents(entity); } else { - await TriggerEntityUpdateEventsAsync(entity); + TriggerEntityUpdateEvents(entity); } - await TriggerDomainEventsAsync(entity); + TriggerDomainEvents(entity); (await GetCollectionAsync()).Update(entity); @@ -235,7 +236,7 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb bool autoSave = false, CancellationToken cancellationToken = default) { - await ApplyAbpConceptsForDeletedEntityAsync(entity); + ApplyAbpConceptsForDeletedEntity(entity); if (entity is ISoftDelete softDeleteEntity && !IsHardDeleted(entity)) { diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index 303e7917e4..eb960ea5d0 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -17,6 +17,7 @@ using Volo.Abp.EventBus.Local; using Volo.Abp.Guids; using Volo.Abp.MongoDB; using Volo.Abp.MultiTenancy; +using Volo.Abp.Uow; namespace Volo.Abp.Domain.Repositories.MongoDB { @@ -182,14 +183,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted) { SetDeletionAuditProperties(entity); - await TriggerEntityDeleteEventsAsync(entity); + TriggerEntityDeleteEvents(entity); } else { - await TriggerEntityUpdateEventsAsync(entity); + TriggerEntityUpdateEvents(entity); } - await TriggerDomainEventsAsync(entity); + TriggerDomainEvents(entity); var oldConcurrencyStamp = SetNewConcurrencyStamp(entity); ReplaceOneResult result; @@ -235,14 +236,14 @@ namespace Volo.Abp.Domain.Repositories.MongoDB if (isSoftDeleteEntity) { SetDeletionAuditProperties(entity); - await TriggerEntityDeleteEventsAsync(entity); + TriggerEntityDeleteEvents(entity); } else { - await TriggerEntityUpdateEventsAsync(entity); + TriggerEntityUpdateEvents(entity); } - await TriggerDomainEventsAsync(entity); + TriggerDomainEvents(entity); SetNewConcurrencyStamp(entity); } @@ -295,7 +296,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && !IsHardDeleted(entity)) { ((ISoftDelete)entity).IsDeleted = true; - await ApplyAbpConceptsForDeletedEntityAsync(entity); + ApplyAbpConceptsForDeletedEntity(entity); ReplaceOneResult result; @@ -324,7 +325,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB } else { - await ApplyAbpConceptsForDeletedEntityAsync(entity); + ApplyAbpConceptsForDeletedEntity(entity); DeleteResult result; @@ -374,7 +375,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB hardDeletedEntities.Add(entity); } - await ApplyAbpConceptsForDeletedEntityAsync(entity); + ApplyAbpConceptsForDeletedEntity(entity); } var dbContext = await GetDbContextAsync(cancellationToken); @@ -573,33 +574,33 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { CheckAndSetId(entity); SetCreationAuditProperties(entity); - await TriggerEntityCreateEvents(entity); - await TriggerDomainEventsAsync(entity); + TriggerEntityCreateEvents(entity); + TriggerDomainEvents(entity); } - private async Task TriggerEntityCreateEvents(TEntity entity) + private void TriggerEntityCreateEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity); - await EntityChangeEventHelper.TriggerEntityCreatedEventAsync(entity); + EntityChangeEventHelper.PublishEntityCreatingEvent(entity); + EntityChangeEventHelper.PublishEntityCreatedEvent(entity); } - protected virtual async Task TriggerEntityUpdateEventsAsync(TEntity entity) + protected virtual void TriggerEntityUpdateEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity); - await EntityChangeEventHelper.TriggerEntityUpdatedEventAsync(entity); + EntityChangeEventHelper.PublishEntityUpdatingEvent(entity); + EntityChangeEventHelper.PublishEntityUpdatedEvent(entity); } - protected virtual async Task ApplyAbpConceptsForDeletedEntityAsync(TEntity entity) + protected virtual void ApplyAbpConceptsForDeletedEntity(TEntity entity) { SetDeletionAuditProperties(entity); - await TriggerEntityDeleteEventsAsync(entity); - await TriggerDomainEventsAsync(entity); + TriggerEntityDeleteEvents(entity); + TriggerDomainEvents(entity); } - protected virtual async Task TriggerEntityDeleteEventsAsync(TEntity entity) + protected virtual void TriggerEntityDeleteEvents(TEntity entity) { - await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity); - await EntityChangeEventHelper.TriggerEntityDeletedEventAsync(entity); + EntityChangeEventHelper.PublishEntityDeletingEvent(entity); + EntityChangeEventHelper.PublishEntityDeletedEvent(entity); } protected virtual void CheckAndSetId(TEntity entity) @@ -639,7 +640,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB AuditPropertySetter.SetDeletionProperties(entity); } - protected virtual async Task TriggerDomainEventsAsync(object entity) + protected virtual void TriggerDomainEvents(object entity) { var generatesDomainEventsEntity = entity as IGeneratesDomainEvents; if (generatesDomainEventsEntity == null) @@ -652,7 +653,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { foreach (var localEvent in localEvents) { - await LocalEventBus.PublishAsync(localEvent.GetType(), localEvent); + UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(new UnitOfWorkEventRecord(localEvent.GetType(), localEvent, EventOrderGenerator.GetNext())); } generatesDomainEventsEntity.ClearLocalEvents(); @@ -663,7 +664,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { foreach (var distributedEvent in distributedEvents) { - await DistributedEventBus.PublishAsync(distributedEvent.GetType(), distributedEvent); + UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(new UnitOfWorkEventRecord(distributedEvent.GetType(), distributedEvent, EventOrderGenerator.GetNext())); } generatesDomainEventsEntity.ClearDistributedEvents(); diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AmbientUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AmbientUnitOfWork.cs index 7b3a45b20c..3418b1d897 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AmbientUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/AmbientUnitOfWork.cs @@ -19,5 +19,18 @@ namespace Volo.Abp.Uow { _currentUow.Value = unitOfWork; } + + public IUnitOfWork GetCurrentByChecking() + { + var uow = UnitOfWork; + + //Skip reserved unit of work + while (uow != null && (uow.IsReserved || uow.IsDisposed || uow.IsCompleted)) + { + uow = uow.Outer; + } + + return uow; + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/EventOrderGenerator.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/EventOrderGenerator.cs new file mode 100644 index 0000000000..feb5dbfd08 --- /dev/null +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/EventOrderGenerator.cs @@ -0,0 +1,14 @@ +using System.Threading; + +namespace Volo.Abp.Uow +{ + public static class EventOrderGenerator + { + private static long _lastOrder; + + public static long GetNext() + { + return Interlocked.Increment(ref _lastOrder); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs index b613ccec59..524a92e63d 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IAmbientUnitOfWork.cs @@ -2,6 +2,6 @@ { public interface IAmbientUnitOfWork : IUnitOfWorkAccessor { - + IUnitOfWork GetCurrentByChecking(); } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs index d04addbd58..520fa69392 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWork.cs @@ -139,7 +139,7 @@ namespace Volo.Abp.Uow { if (LocalEvents.Any()) { - var localEventsToBePublished = LocalEvents.ToArray(); + var localEventsToBePublished = LocalEvents.OrderBy(e => e.EventOrder).ToArray(); LocalEvents.Clear(); await UnitOfWorkEventPublisher.PublishLocalEventsAsync( localEventsToBePublished @@ -148,7 +148,7 @@ namespace Volo.Abp.Uow if (DistributedEvents.Any()) { - var distributedEventsToBePublished = DistributedEvents.ToArray(); + var distributedEventsToBePublished = DistributedEvents.OrderBy(e => e.EventOrder).ToArray(); DistributedEvents.Clear(); await UnitOfWorkEventPublisher.PublishDistributedEventsAsync( distributedEventsToBePublished diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs index 2fcfb69f5c..11ae4920cd 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkEventRecord.cs @@ -9,6 +9,8 @@ namespace Volo.Abp.Uow public Type EventType { get; } + public long EventOrder { get; } + /// /// Extra properties can be used if needed. /// @@ -16,10 +18,12 @@ namespace Volo.Abp.Uow public UnitOfWorkEventRecord( Type eventType, - object eventData) + object eventData, + long eventOrder) { EventType = eventType; EventData = eventData; + EventOrder = eventOrder; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs index de0d8daa0a..9a9b3c7b38 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/UnitOfWorkManager.cs @@ -10,7 +10,7 @@ namespace Volo.Abp.Uow [Obsolete("This will be removed in next versions.")] public static AsyncLocal DisableObsoleteDbContextCreationWarning { get; } = new AsyncLocal(); - public IUnitOfWork Current => GetCurrentUnitOfWork(); + public IUnitOfWork Current => _ambientUnitOfWork.GetCurrentByChecking(); private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IAmbientUnitOfWork _ambientUnitOfWork; @@ -86,19 +86,6 @@ namespace Volo.Abp.Uow return true; } - private IUnitOfWork GetCurrentUnitOfWork() - { - var uow = _ambientUnitOfWork.UnitOfWork; - - //Skip reserved unit of work - while (uow != null && (uow.IsReserved || uow.IsDisposed || uow.IsCompleted)) - { - uow = uow.Outer; - } - - return uow; - } - private IUnitOfWork CreateNewUnitOfWork() { var scope = _serviceScopeFactory.CreateScope(); diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs index ef789f57f5..04d0dda3c4 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/DomainEvents_Tests.cs @@ -30,19 +30,65 @@ namespace Volo.Abp.TestApp.Testing [Fact] public virtual async Task Should_Publish_Events_In_Order() { - bool entityCreatedEventHandled = false; + bool testPersonCreateHandled = false; + bool douglesUpdateHandled = false; + bool douglesNameChangeHandled = false; + bool customEventHandled = false; + bool customEvent2Handled = false; LocalEventBus.Subscribe>(data => { data.Entity.Name.ShouldBe("TestPerson1"); - entityCreatedEventHandled = true; + testPersonCreateHandled = true; + douglesUpdateHandled.ShouldBeFalse(); + douglesNameChangeHandled.ShouldBeFalse(); + customEventHandled.ShouldBeFalse(); + customEvent2Handled.ShouldBeFalse(); return Task.CompletedTask; }); LocalEventBus.Subscribe(data => { data.Value.ShouldBe("42"); - entityCreatedEventHandled.ShouldBe(true); + customEventHandled = true; + testPersonCreateHandled.ShouldBeTrue(); + douglesUpdateHandled.ShouldBeFalse(); + douglesNameChangeHandled.ShouldBeFalse(); + customEvent2Handled.ShouldBeFalse(); + return Task.CompletedTask; + }); + + LocalEventBus.Subscribe(data => + { + data.OldName.ShouldBe("Douglas"); + data.Person.Name.ShouldBe("Douglas-Updated"); + douglesNameChangeHandled = true; + testPersonCreateHandled.ShouldBeTrue(); + customEventHandled.ShouldBeTrue(); + douglesUpdateHandled.ShouldBeFalse(); + customEvent2Handled.ShouldBeFalse(); + return Task.CompletedTask; + }); + + LocalEventBus.Subscribe>(data => + { + data.Entity.Name.ShouldBe("Douglas-Updated"); + douglesUpdateHandled = true; + testPersonCreateHandled.ShouldBeTrue(); + customEventHandled.ShouldBeTrue(); + douglesNameChangeHandled.ShouldBeTrue(); + customEvent2Handled.ShouldBeFalse(); + return Task.CompletedTask; + }); + + LocalEventBus.Subscribe(data => + { + data.Value.ShouldBe("44"); + customEvent2Handled = true; + testPersonCreateHandled.ShouldBeTrue(); + customEventHandled.ShouldBeTrue(); + douglesUpdateHandled.ShouldBeTrue(); + douglesNameChangeHandled.ShouldBeTrue(); return Task.CompletedTask; }); @@ -53,6 +99,12 @@ namespace Volo.Abp.TestApp.Testing ); await LocalEventBus.PublishAsync(new MyCustomEventData { Value = "42" }); + + var douglas = await PersonRepository.GetAsync(TestDataBuilder.UserDouglasId); + douglas.ChangeName("Douglas-Updated"); + await PersonRepository.UpdateAsync(douglas); + + await LocalEventBus.PublishAsync(new MyCustomEventData2 { Value = "44" }); }); } @@ -125,5 +177,10 @@ namespace Volo.Abp.TestApp.Testing { public string Value { get; set; } } + + private class MyCustomEventData2 + { + public string Value { get; set; } + } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs index cb16a46439..37fdbdedec 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs @@ -88,12 +88,16 @@ namespace Volo.Abp.TestApp.Testing [Fact] public async Task Multiple_Update_Should_Result_With_Single_Updated_Event_In_The_Same_Uow() { - var personId = Guid.NewGuid(); - await PersonRepository.InsertAsync(new Person(personId, Guid.NewGuid().ToString("D"), 42)); - + var createEventCount = 0; var updateEventCount = 0; var updatedAge = 0; + DistributedEventBus.Subscribe>(eto => + { + createEventCount++; + return Task.CompletedTask; + }); + DistributedEventBus.Subscribe>(eto => { updateEventCount++; @@ -101,6 +105,9 @@ namespace Volo.Abp.TestApp.Testing return Task.CompletedTask; }); + var personId = Guid.NewGuid(); + await PersonRepository.InsertAsync(new Person(personId, Guid.NewGuid().ToString("D"), 42)); + using (var uow = GetRequiredService().Begin()) { var person = await PersonRepository.GetAsync(personId); @@ -120,6 +127,7 @@ namespace Volo.Abp.TestApp.Testing await uow.CompleteAsync(); } + createEventCount.ShouldBe(1); updateEventCount.ShouldBe(1); updatedAge.ShouldBe(45); } From 92f09650ea8c13c4edd4f2199b5db9c02306a082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 27 Aug 2021 16:45:14 +0300 Subject: [PATCH 11/14] Fix mongo and memory db implementations for event publishing. --- .../Repositories/MemoryDb/MemoryDbRepository.cs | 16 ++++++++++++++-- .../Repositories/MongoDB/MongoDbRepository.cs | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs index 37c744547f..cf3479de67 100644 --- a/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs +++ b/framework/src/Volo.Abp.MemoryDb/Volo/Abp/Domain/Repositories/MemoryDb/MemoryDbRepository.cs @@ -79,7 +79,13 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { foreach (var localEvent in localEvents) { - UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(new UnitOfWorkEventRecord(localEvent.GetType(), localEvent, EventOrderGenerator.GetNext())); + UnitOfWorkManager.Current?.AddOrReplaceLocalEvent( + new UnitOfWorkEventRecord( + localEvent.EventData.GetType(), + localEvent.EventData, + localEvent.EventOrder + ) + ); } generatesDomainEventsEntity.ClearLocalEvents(); @@ -90,7 +96,13 @@ namespace Volo.Abp.Domain.Repositories.MemoryDb { foreach (var distributedEvent in distributedEvents) { - UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(new UnitOfWorkEventRecord(distributedEvent.GetType(), distributedEvent, EventOrderGenerator.GetNext())); + UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent( + new UnitOfWorkEventRecord( + distributedEvent.EventData.GetType(), + distributedEvent.EventData, + distributedEvent.EventOrder + ) + ); } generatesDomainEventsEntity.ClearDistributedEvents(); diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index eb960ea5d0..a40117e0ff 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -653,7 +653,13 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { foreach (var localEvent in localEvents) { - UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(new UnitOfWorkEventRecord(localEvent.GetType(), localEvent, EventOrderGenerator.GetNext())); + UnitOfWorkManager.Current?.AddOrReplaceLocalEvent( + new UnitOfWorkEventRecord( + localEvent.EventData.GetType(), + localEvent.EventData, + localEvent.EventOrder + ) + ); } generatesDomainEventsEntity.ClearLocalEvents(); @@ -664,7 +670,13 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { foreach (var distributedEvent in distributedEvents) { - UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(new UnitOfWorkEventRecord(distributedEvent.GetType(), distributedEvent, EventOrderGenerator.GetNext())); + UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent( + new UnitOfWorkEventRecord( + distributedEvent.EventData.GetType(), + distributedEvent.EventData, + distributedEvent.EventOrder + ) + ); } generatesDomainEventsEntity.ClearDistributedEvents(); From 61cac95775b8667e3587791c86234932a920f031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 27 Aug 2021 16:52:32 +0300 Subject: [PATCH 12/14] Resolved #9897: Marked EntityCreatingEventData, EntityUpdatingEventData, EntityDeletingEventData and EntityChangingEventData as obsolete. --- .../Abp/Domain/Entities/Events/EntityChangeEventHelper.cs | 6 ++++++ .../Abp/Domain/Entities/Events/EntityChangingEventData.cs | 1 + .../Abp/Domain/Entities/Events/EntityCreatingEventData.cs | 1 + .../Abp/Domain/Entities/Events/EntityDeletingEventData.cs | 1 + .../Abp/Domain/Entities/Events/EntityUpdatingEventData.cs | 1 + .../Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs | 2 ++ 6 files changed, 12 insertions(+) diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs index 9fc5c1e90d..1d16909d1f 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs @@ -46,7 +46,9 @@ namespace Volo.Abp.Domain.Entities.Events { TriggerEventWithEntity( LocalEventBus, +#pragma warning disable 618 typeof(EntityCreatingEventData<>), +#pragma warning restore 618 entity, entity ); @@ -91,7 +93,9 @@ namespace Volo.Abp.Domain.Entities.Events { TriggerEventWithEntity( LocalEventBus, +#pragma warning disable 618 typeof(EntityUpdatingEventData<>), +#pragma warning restore 618 entity, entity ); @@ -125,7 +129,9 @@ namespace Volo.Abp.Domain.Entities.Events { TriggerEventWithEntity( LocalEventBus, +#pragma warning disable 618 typeof(EntityDeletingEventData<>), +#pragma warning restore 618 entity, entity ); diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs index fb914ed46d..a965a996b7 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangingEventData.cs @@ -8,6 +8,7 @@ namespace Volo.Abp.Domain.Entities.Events /// /// Entity type [Serializable] + [Obsolete("This event is no longer needed and identical to EntityChangedEventData. Please use EntityChangedEventData instead.")] public class EntityChangingEventData : EntityEventData { /// diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs index 39ad3c4480..d5c7b21a24 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityCreatingEventData.cs @@ -7,6 +7,7 @@ namespace Volo.Abp.Domain.Entities.Events /// /// Entity type [Serializable] + [Obsolete("This event is no longer needed and identical to EntityCreatedEventData. Please use EntityCreatedEventData instead.")] public class EntityCreatingEventData : EntityChangingEventData { /// diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs index b8e336ed3e..4fd571ca7f 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityDeletingEventData.cs @@ -7,6 +7,7 @@ namespace Volo.Abp.Domain.Entities.Events /// /// Entity type [Serializable] + [Obsolete("This event is no longer needed and identical to EntityDeleteEventData. Please use EntityDeleteEventData instead.")] public class EntityDeletingEventData : EntityChangingEventData { /// diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs index 72a401fb34..74ed41c157 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityUpdatingEventData.cs @@ -7,6 +7,7 @@ namespace Volo.Abp.Domain.Entities.Events /// /// Entity type [Serializable] + [Obsolete("This event is no longer needed and identical to EntityUpdatedEventData. Please use EntityUpdatedEventData instead.")] public class EntityUpdatingEventData : EntityChangingEventData { /// diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs index 37fdbdedec..b87f23774a 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/EntityChangeEvents_Tests.cs @@ -38,7 +38,9 @@ namespace Volo.Abp.TestApp.Testing using (var uow = GetRequiredService().Begin()) { +#pragma warning disable 618 LocalEventBus.Subscribe>(data => +#pragma warning restore 618 { creatingEventTriggered.ShouldBeFalse(); createdEventTriggered.ShouldBeFalse(); From cd364b4a6d6b79f1b680af9b51ec1c376d544de2 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 30 Aug 2021 11:54:37 +0800 Subject: [PATCH 13/14] Call PublishToEventBusAsync instead of PublishAsync. --- .../src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs | 6 +++--- .../Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs index 40c36dd8be..f29a169cb5 100644 --- a/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs +++ b/framework/src/Volo.Abp.EventBus/Volo/Abp/EventBus/EventBusBase.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.EventBus protected IServiceScopeFactory ServiceScopeFactory { get; } protected ICurrentTenant CurrentTenant { get; } - + protected IUnitOfWorkManager UnitOfWorkManager { get; } protected IEventErrorHandler ErrorHandler { get; } @@ -108,7 +108,7 @@ namespace Volo.Abp.EventBus ); return; } - + await PublishToEventBusAsync(eventType, eventData); } @@ -154,7 +154,7 @@ namespace Volo.Abp.EventBus var baseEventType = eventType.GetGenericTypeDefinition().MakeGenericType(baseArg); var constructorArgs = ((IEventDataWithInheritableGenericArgument)eventData).GetConstructorArgs(); var baseEventData = Activator.CreateInstance(baseEventType, constructorArgs); - await PublishAsync(baseEventType, baseEventData); + await PublishToEventBusAsync(baseEventType, baseEventData); } } } diff --git a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs index 521174f36f..a060d2903e 100644 --- a/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs +++ b/framework/src/Volo.Abp.Uow/Volo/Abp/Uow/IUnitOfWorkEventPublisher.cs @@ -6,6 +6,7 @@ namespace Volo.Abp.Uow public interface IUnitOfWorkEventPublisher { Task PublishLocalEventsAsync(IEnumerable localEvents); + Task PublishDistributedEventsAsync(IEnumerable distributedEvents); } -} \ No newline at end of file +} From 9384be65712aa0802a3b59ec6bfbaa39f1fc31ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 1 Sep 2021 15:57:14 +0300 Subject: [PATCH 14/14] SettingCacheItemInvalidator should be backward compatible. --- .../Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs index 35d358a67d..95a6589d9a 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItemInvalidator.cs @@ -23,7 +23,7 @@ namespace Volo.Abp.SettingManagement eventData.Entity.ProviderKey ); - await Cache.RemoveAsync(cacheKey); + await Cache.RemoveAsync(cacheKey, considerUow: true); } protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)