From aeb898b08d852f8c2a39e4281c2ec4d371b7d045 Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Wed, 20 Oct 2021 15:05:04 +0800 Subject: [PATCH 01/39] chore: update readme --- README.md | 2 +- README.zh-cn.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ccab56434..a4cdd2607 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # MASA.Contrib -MASA.Contrib is the best practice of MASA.BuildingBlocks +The purpose of MASA.Contrib is based on [MASA.BuildingBlocks](https://github.com/masastack/MASA.BuildingBlocks) to provide open, community driven reusable components for building mesh applications. These components will be used by the [MASA Stack](https://github.com/masastack) and [MASA Labs](https://github.com/masalabs) projects. ## Structure diff --git a/README.zh-cn.md b/README.zh-cn.md index 3addfa1d9..9fa9043d3 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -1,8 +1,8 @@ -中 | [EN](README.md) +中 | [EN](README.md) # MASA.Contrib -MASA.BuildingBlocks最佳实践 +MASA.Contrib是基于[MASA.BuildingBlocks](https://github.com/masastack/MASA.BuildingBlocks)提供开放, 社区驱动的可重用组件,用于构建网格应用程序。这些组件将被[MASA Stack](https://github.com/masastack)和[MASA Labs](https://github.com/masalabs)等项目使用。 ## 结构 From c9ba05f6f09487219bcfed74a91c643444e0a36a Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Wed, 20 Oct 2021 09:44:31 +0000 Subject: [PATCH 02/39] Merge branch 'docs/contrib' of... --- LICENSE => LICENSE.txt | 0 README.md | 36 +++++++++---------- README.zh-CN.md | 36 +++++++++---------- .../README.md | 6 ++-- .../{README.zh-cn.md => README.zh-CN.md} | 10 +++--- src/DDD/MASA.Contrib.DDD.Domain/README.md | 6 ++-- .../{README.zh-cn.md => README.zh-CN.md} | 8 +++-- .../MASA.Contrib.Data.Contracts.EF/README.md | 2 ++ .../{README.zh-cn.md => RREADME.zh-CN.md} | 2 ++ .../MASA.Contrib.Dispatcher.Events/README.md | 6 ++-- .../{README.zh-cn.md => README.zh-CN.md} | 6 ++-- .../README.md | 4 ++- .../{README.zh-cn.md => README.zh-CN.md} | 6 ++-- .../README.md | 2 ++ .../{README.zh-cn.md => README.zh-CN.md} | 4 ++- .../README.md | 8 +++-- .../{README.zh-cn.md => README.zh-CN.md} | 10 +++--- .../README.md | 6 ++-- .../{README.zh-cn.md => README.zh-CN.md} | 6 ++-- 19 files changed, 98 insertions(+), 66 deletions(-) rename LICENSE => LICENSE.txt (100%) rename src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/{README.zh-cn.md => README.zh-CN.md} (88%) rename src/DDD/MASA.Contrib.DDD.Domain/{README.zh-cn.md => README.zh-CN.md} (96%) rename src/Data/MASA.Contrib.Data.Contracts.EF/{README.zh-cn.md => RREADME.zh-CN.md} (96%) rename src/Dispatcher/MASA.Contrib.Dispatcher.Events/{README.zh-cn.md => README.zh-CN.md} (98%) rename src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/{README.zh-cn.md => README.zh-CN.md} (87%) rename src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/{README.zh-cn.md => README.zh-CN.md} (94%) rename src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/{README.zh-cn.md => README.zh-CN.md} (89%) rename src/Service/MASA.Contrib.Service.MinimalAPIs/{README.zh-cn.md => README.zh-CN.md} (85%) diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/README.md b/README.md index a4cdd2607..6786c904c 100644 --- a/README.md +++ b/README.md @@ -8,25 +8,25 @@ The purpose of MASA.Contrib is based on [MASA.BuildingBlocks](https://github.com ```c# MASA.Contrib -│──solution items -│ ── nuget.config -│──src +├── solution items +│ ├── nuget.config +├── src │ ├── Data -│ │ ├── MASA.Contrib.Data.Uow.EF Unit of work -│ │ └── MASA.Contribs.Data.Contracts.EF Protocol EF version +│ │ ├── MASA.Contrib.Data.Uow.EF Unit of work +│ │ └── MASA.Contribs.Data.Contracts.EF Protocol EF version │ ├── DDD -│ │ ├── MASA.Contribs.DDD.Domain In-process and cross-process support +│ │ ├── MASA.Contribs.DDD.Domain In-process and cross-process support │ │ └── MASA.Contribs.DDD.Domain.Repository.EF │ ├── Dispatcher -│ │ ├── MASA.Contrib.Dispatcher.Events In-process event +│ │ ├── MASA.Contrib.Dispatcher.Events In-process event │ │ ├── MASA.Contrib.Dispatcher.IntegrationEvents.Dapr -│ │ └── MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF Cross-process event +│ │ └── MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF Cross-process event │ ├── ReadWriteSpliting │ │ └── CQRS -│ │ │ └── MASA.Contrib.ReadWriteSpliting.CQRS CQRS +│ │ │ └── MASA.Contrib.ReadWriteSpliting.CQRS CQRS │ ├── Service -│ │ └── MASA.Contrib.Service.MinimalAPIs Best practices for [MinimalAPI] -│──test +│ │ └── MASA.Contrib.Service.MinimalAPIs Best practices for [MinimalAPI] +├── test │ ├── MASA.Contrib.Dispatcher.Events │ │ ├── MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest │ │ ├── MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests @@ -46,7 +46,7 @@ MASA.Contrib ### 1. MinimalAPI -What is [MinimalAPI](https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis)?[Usage introduction](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/Service/MASA.Contrib.Service.MinimalAPIs/README.md) +What is [MinimalAPI](https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis)?[Usage introduction](/src/Service/MASA.Contrib.Service.MinimalAPIs/README.md) > Advantage: > @@ -54,7 +54,7 @@ What is [MinimalAPI](https://devblogs.microsoft.com/aspnet/asp-net-core-updates- ### 2. EventBus -[Usage introduction](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.md) +[Usage introduction](/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.md) > Advantage: > @@ -73,17 +73,17 @@ What is [MinimalAPI](https://devblogs.microsoft.com/aspnet/asp-net-core-updates- ### 3. CQRS -what is[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)?[Usage introduction](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.md) +what is[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)?[Usage introduction](/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.md) ### 4. IntegrationEventBus -Realize cross-process events based on Dapr。[Usage introduction](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md) +Realize cross-process events based on Dapr。[Usage introduction](/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md) > Advantage:Use the same transaction to commit the user-defined context and the log to ensure atomicity and consistency ### 5. DomainEventBus -[Usage introduction](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/DDD/MASA.Contribs.DDD.Domain/README.md) +[Usage introduction](/src/DDD/MASA.Contribs.DDD.Domain/README.md) > Advantage: > @@ -99,7 +99,7 @@ Realize cross-process events based on Dapr。[Usage introduction](http://gitlab- ### 7. Contracts.EF -Protocol based on EF implementation,[Usage introduction](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/Data/MASA.Contribs.Data.Contracts.EF/README.md) +Protocol based on EF implementation,[Usage introduction](/Data/MASA.Contribs.Data.Contracts.EF/README.md) > Advantage: > @@ -130,4 +130,4 @@ To ensure the reliability of the entire source code, the unit test coverage is a ## ☀️ License agreement -[![MASA.Contrib](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/LICENSE) +[![MASA.Contrib](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](/LICENSE.txt) diff --git a/README.zh-CN.md b/README.zh-CN.md index 9fa9043d3..05cb5ae90 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -8,25 +8,25 @@ MASA.Contrib是基于[MASA.BuildingBlocks](https://github.com/masastack/MASA.Bui ```c# MASA.Contrib -│──solution items -│ ── nuget.config -│──src +├── solution items +│ ├── nuget.config +├── src │ ├── Data -│ │ ├── MASA.Contrib.Data.Uow.EF 工作单元 -│ │ └── MASA.Contribs.Data.Contracts.EF 规约EF版 +│ │ ├── MASA.Contrib.Data.Uow.EF 工作单元 +│ │ └── MASA.Contribs.Data.Contracts.EF 规约EF版 │ ├── DDD -│ │ ├── MASA.Contribs.DDD.Domain 进程内、跨进程都支持 +│ │ ├── MASA.Contribs.DDD.Domain 进程内、跨进程都支持 │ │ └── MASA.Contribs.DDD.Domain.Repository.EF │ ├── Dispatcher -│ │ ├── MASA.Contrib.Dispatcher.Events 进程内事件 +│ │ ├── MASA.Contrib.Dispatcher.Events 进程内事件 │ │ ├── MASA.Contrib.Dispatcher.IntegrationEvents.Dapr -│ │ └── MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF 跨进程事件 +│ │ └── MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF 跨进程事件 │ ├── ReadWriteSpliting │ │ └── CQRS -│ │ │ └── MASA.Contrib.ReadWriteSpliting.CQRS CQRS +│ │ │ └── MASA.Contrib.ReadWriteSpliting.CQRS CQRS │ ├── Service -│ │ └── MASA.Contrib.Service.MinimalAPIs MinimalAPI最佳实践 -│──test +│ │ └── MASA.Contrib.Service.MinimalAPIs MinimalAPI最佳实践 +├── test │ ├── MASA.Contrib.Dispatcher.Events │ │ ├── MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest │ │ ├── MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests @@ -46,7 +46,7 @@ MASA.Contrib ### 1. MinimalAPI -什么是[MinimalAPI](https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis)?[用法介绍](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-cn.md) +什么是[MinimalAPI](https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis)?[用法介绍](/src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-cn.md) > 优势: > @@ -54,7 +54,7 @@ MASA.Contrib ### 2. EventBus -[用法介绍](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-cn.md) +[用法介绍](/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-cn.md) > 优势: > @@ -73,17 +73,17 @@ MASA.Contrib ### 3. CQRS -什么是[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)?[用法介绍](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-cn.md) +什么是[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)?[用法介绍](/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-cn.md) ### 4. IntegrationEventBus -基于Dapr实现跨进程的事件。[用法介绍](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-cn.md) +基于Dapr实现跨进程的事件。[用法介绍](/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-cn.md) > 优势:将用户自定义上下文与日志使用同一事务提交,确保原子性、一致性 ### 5. DomainEventBus -[用法介绍](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/src/DDD/MASA.Contribs.DDD.Domain/README.zh-cn.md) +[用法介绍](/src/DDD/MASA.Contribs.DDD.Domain/README.zh-cn.md) > 优势: > @@ -99,7 +99,7 @@ MASA.Contrib ### 7. Contracts.EF -基于EF实现的规约,[用法介绍](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/Data/MASA.Contribs.Data.Contracts.EF/README.zh-cn.md) +基于EF实现的规约,[用法介绍](/Data/MASA.Contribs.Data.Contracts.EF/README.zh-cn.md) > 优势: > @@ -130,5 +130,5 @@ builder.Services ## ☀️ 授权协议 -[![MASA.Contrib](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](http://gitlab-hz.lonsid.cn/MASA-Stack/Contribs/MASA.Contrib/-/tree/develop/LICENSE) +[![MASA.Contrib](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](/LICENSE.txt) diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.md b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.md index a9829bb4e..54dc8f883 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.md +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.md @@ -1,3 +1,5 @@ +[中](README.zh-CN.md) | EN + ## MASA.Contrib.DDD.Domain.Repository.EF Example: @@ -14,7 +16,7 @@ Install-Package MASA.Contrib.DDD.Domain.Repository.EF builder.Services .AddDomainEventBus(options => { - options.UseRepository();//Use the EF version of Repository to achieve + options.UseRepository();//Use the EF version of Repository to achieve } ``` @@ -51,7 +53,7 @@ public interface IProductRepository : IRepository public class ProductRepository : Repository, IProductRepository { - public Task> ItemsWithNameAsync(string name) + public Task> ItemsWithNameAsync(string name) { //Todo } diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.zh-cn.md b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.zh-CN.md similarity index 88% rename from src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.zh-cn.md rename to src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.zh-CN.md index 84d376759..3a9cf09c5 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.zh-cn.md +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/README.zh-CN.md @@ -1,3 +1,5 @@ +中 | [EN](README.md) + ## MASA.Contrib.DDD.Domain.Repository.EF 用例: @@ -14,7 +16,7 @@ Install-Package MASA.Contrib.DDD.Domain.Repository.EF builder.Services .AddDomainEventBus(options => { - options.UseRepository();//使用Repository的EF版实现 + options.UseRepository();//使用Repository的EF版实现 } ``` @@ -30,9 +32,9 @@ public class DemoService : ServiceBase { public CatalogService(IServiceCollection services) : base(services) { - + } - + public async Task CreateProduct(ProductItem product,[FromService]IRepository repository) { await repository.AddAsync(product); @@ -51,7 +53,7 @@ public interface IProductRepository : IRepository public class ProductRepository : Repository, IProductRepository { - public Task> ItemsWithNameAsync(string name) + public Task> ItemsWithNameAsync(string name) { //Todo } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/README.md b/src/DDD/MASA.Contrib.DDD.Domain/README.md index dc44c3e61..2df045361 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/README.md +++ b/src/DDD/MASA.Contrib.DDD.Domain/README.md @@ -1,3 +1,5 @@ +[中](README.zh-CN.md) | EN + ### DomainEventBus Example: @@ -46,8 +48,8 @@ public class RegisterUserDomainCommand : DomainCommand ```C# public class UserHandler { - [EventHandler] - public Task RegisterUserHandlerAsync(RegisterUserDomainCommand command) + [EventHandler] + public Task RegisterUserHandlerAsync(RegisterUserDomainCommand command) { //TODO Registered user business } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/README.zh-cn.md b/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md similarity index 96% rename from src/DDD/MASA.Contrib.DDD.Domain/README.zh-cn.md rename to src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md index bcad3c833..7293c8017 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/README.zh-cn.md +++ b/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md @@ -1,3 +1,5 @@ +中 | [EN](README.md) + ### DomainEventBus 用例: @@ -46,8 +48,8 @@ public class RegisterUserDomainCommand : DomainCommand ```C# public class UserHandler { - [EventHandler] - public Task RegisterUserHandlerAsync(RegisterUserDomainCommand command) + [EventHandler] + public Task RegisterUserHandlerAsync(RegisterUserDomainCommand command) { //TODO 注册用户业务 } @@ -114,4 +116,4 @@ public async Task RegisterUserSucceededHandlerAsync(RegisterUserSucceededIntegra { //todo } -``` \ No newline at end of file +``` diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/README.md b/src/Data/MASA.Contrib.Data.Contracts.EF/README.md index 76ba4c345..e4e2fc04e 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/README.md +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/README.md @@ -1,3 +1,5 @@ +[中](RREADME.zh-CN.md) | EN + ## Contracts.EF Example: diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-cn.md b/src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md similarity index 96% rename from src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-cn.md rename to src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md index be3fb7afc..f2e2e8357 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-cn.md +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md @@ -1,3 +1,5 @@ +中 | [EN](README.md) + ## Contracts.EF 用例: diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.md b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.md index 2ca2d1622..2755b474c 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.md +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.md @@ -1,3 +1,5 @@ +[中](README.zh-CN.md) | EN + ## EventBus Example: @@ -13,8 +15,8 @@ Install-Package MASA.Contrib.Dispatcher.Events ```c# var builder = WebApplication.CreateBuilder(args); var app = builder.Services - .AddEventBus() - //TODO + .AddEventBus() + //TODO ``` 2. Custom Event diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-cn.md b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-CN.md similarity index 98% rename from src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-cn.md rename to src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-CN.md index 7d857d060..1f53ee1e5 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-cn.md +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-CN.md @@ -1,3 +1,5 @@ +中 | [EN](README.md) + ## EventBus 用例: @@ -13,8 +15,8 @@ Install-Package MASA.Contrib.Dispatcher.Events ```c# var builder = WebApplication.CreateBuilder(args); var app = builder.Services - .AddEventBus() - //TODO + .AddEventBus() + //TODO ``` 2. 自定义Event diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md index b41714267..1f9f5ba02 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md @@ -1,3 +1,5 @@ +[中](README.zh-CN.md) | EN + ## IntegrationEventBus Example: @@ -14,7 +16,7 @@ Install-Package MASA.Contrib.Data.Uow.EF //Use UnitOfWork builder.Services .AddDaprEventBus(options=> { - options.UseUoW(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity")) + options.UseUoW(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity")) .UseEventLog(); ) }); diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-cn.md b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-CN.md similarity index 87% rename from src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-cn.md rename to src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-CN.md index ba1a819e2..485103588 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-cn.md +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-CN.md @@ -1,3 +1,5 @@ +中 | [EN](README.md) + ## IntegrationEventBus 用例: @@ -14,7 +16,7 @@ Install-Package MASA.Contrib.Data.Uow.EF //使用工作单元 builder.Services .AddDaprEventBus(options=> { - options.UseUoW(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"))//使用工作单元,推荐使用 + options.UseUoW(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"))//使用工作单元,推荐使用 .UseEventLog(); ) }); @@ -62,4 +64,4 @@ public async Task DomeIntegrationEventHandleAsync(DomeIntegrationEvent @event) { //todo } -``` \ No newline at end of file +``` diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.md b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.md index 86e87c0b1..4ab7a3c7d 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.md +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.md @@ -1,3 +1,5 @@ +[中](README.zh-CN.md) | EN + ## MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF > Provide support for sending IntegrationEvent diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.zh-cn.md b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.zh-CN.md similarity index 94% rename from src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.zh-cn.md rename to src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.zh-CN.md index 5dfeb3634..76784f8b5 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.zh-cn.md +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/README.zh-CN.md @@ -1,3 +1,5 @@ +中 | [EN](README.md) + ## MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF > 为发送IntegrationEvent提供支持 @@ -19,4 +21,4 @@ Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF } ``` -> 提示:CustomDbContext需要继承IntegrationEventLogContext \ No newline at end of file +> 提示:CustomDbContext需要继承IntegrationEventLogContext diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.md b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.md index 9ef98153e..a2cb52a95 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.md +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.md @@ -1,3 +1,5 @@ +[中](README.zh-CN.md) | EN + ## CQRS Example: @@ -18,9 +20,9 @@ Install-Package MASA.Contrib.ReadWriteSpliting.CQRS ```C# public class CatalogItemQuery : Query> { - public string Name { get; set; } = default!; + public string Name { get; set; } = default!; - public override List Result { get; set; } = default!; + public override List Result { get; set; } = default!; } ``` @@ -56,7 +58,7 @@ await eventBus.PublishAsync(new CatalogItemQuery() { Name = "Rolex" }); ```c# public class CreateCatalogItemCommand : Command { - public string Name { get; set; } = default!; + public string Name { get; set; } = default!; //todo } diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-cn.md b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-CN.md similarity index 89% rename from src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-cn.md rename to src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-CN.md index b58e20354..6b84aebe2 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-cn.md +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-CN.md @@ -1,3 +1,5 @@ +中 | [EN](README.md) + ## CQRS 用例: @@ -18,9 +20,9 @@ Install-Package MASA.Contrib.ReadWriteSpliting.CQRS ```C# public class CatalogItemQuery : Query> { - public string Name { get; set; } = default!; + public string Name { get; set; } = default!; - public override List Result { get; set; } = default!; + public override List Result { get; set; } = default!; } ``` @@ -56,7 +58,7 @@ await eventBus.PublishAsync(new CatalogItemQuery() { Name = "Rolex" }); ```c# public class CreateCatalogItemCommand : Command { - public string Name { get; set; } = default!; + public string Name { get; set; } = default!; //todo } @@ -83,4 +85,4 @@ public class CatalogCommandHandler : CommandHandler ```C# IEventBus eventBus;//通过DI得到IEventBus await eventBus.PublishAsync(new CreateCatalogItemCommand()); -``` \ No newline at end of file +``` diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/README.md b/src/Service/MASA.Contrib.Service.MinimalAPIs/README.md index 0a280b03d..6560eea7f 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/README.md +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/README.md @@ -1,3 +1,5 @@ +[中](README.zh-CN.md) | EN + ## MinimalAPI Original usage: @@ -20,7 +22,7 @@ Install-Package MASA.Contrib.Service.MinimalAPIs ```c# var builder = WebApplication.CreateBuilder(args); var app = builder.Services - .AddServices(builder); + .AddServices(builder); ``` 2. Customize Service and inherit ServiceBase @@ -28,7 +30,7 @@ var app = builder.Services ```c# public class IntegrationEventService : ServiceBase { - public IntegrationEventService(IServiceCollection services) : base(services) + public IntegrationEventService(IServiceCollection services) : base(services) { App.MapGet("/api/v1/payment/HelloWorld", HelloWorld); } diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-cn.md b/src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-CN.md similarity index 85% rename from src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-cn.md rename to src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-CN.md index 9cb242df1..ef8c8bca7 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-cn.md +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-CN.md @@ -1,3 +1,5 @@ +中 | [EN](README.md) + ## MinimalAPI 原始用法: @@ -20,7 +22,7 @@ Install-Package MASA.Contrib.Service.MinimalAPIs ```c# var builder = WebApplication.CreateBuilder(args); var app = builder.Services - .AddServices(builder); + .AddServices(builder); ``` 2. 自定义Service并继承ServiceBase,如: @@ -28,7 +30,7 @@ var app = builder.Services ```c# public class IntegrationEventService : ServiceBase { - public IntegrationEventService(IServiceCollection services) : base(services) + public IntegrationEventService(IServiceCollection services) : base(services) { App.MapGet("/api/v1/payment/HelloWorld", HelloWorld); } From ecf682afd7bc73a98b5f183d82be3a4fdf3f3170 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Fri, 22 Oct 2021 08:24:40 +0000 Subject: [PATCH 03/39] fix: Fix the problem of failing to get context after enabling soft delete --- MASA.Contrib.sln | 46 +++++++++---------- README.md | 4 +- README.zh-CN.md | 6 +-- ...SA.Contrib.DDD.Domain.Repository.EF.csproj | 2 +- .../_Imports.cs | 2 +- .../MASA.Contrib.DDD.Domain/DomainEventBus.cs | 5 ++ .../MASA.Contrib.DDD.Domain.csproj | 2 +- src/DDD/MASA.Contrib.DDD.Domain/README.md | 4 +- .../MASA.Contrib.DDD.Domain/README.zh-CN.md | 4 +- .../ServiceCollectionExtensions.cs | 2 +- src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs | 2 +- .../MASA.Contrib.Data.Contracts.EF.csproj | 6 +-- .../TransactionSaveChangesFilter.cs | 9 ++-- .../_Imports.cs | 2 +- .../DispatcherOptionsExtensions.cs | 8 ++-- .../MASA.Contrib.Data.UoW.EF.csproj} | 8 ++-- .../Transaction.cs | 2 +- .../UnitOfWork.cs | 3 +- .../_Imports.cs | 2 +- .../EventBus.cs | 8 ++++ .../Middleware/TransactionMiddleware.cs | 11 +---- .../MASA.Contrib.Dispatcher.Events.csproj | 8 ++-- .../_Imports.cs | 2 +- .../IntegrationEventBus.cs | 8 ++++ ...b.Dispatcher.IntegrationEvents.Dapr.csproj | 4 +- .../README.md | 2 +- .../README.zh-CN.md | 2 +- .../_Imports.cs | 2 +- .../IntegrationEventLogService.cs | 19 ++++++-- ...cher.IntegrationEvents.EventLogs.EF.csproj | 4 +- ...MASA.Contrib.ReadWriteSpliting.CQRS.csproj | 4 +- .../MASA.Contrib.Service.MinimalAPIs.csproj | 4 +- .../RepositoryTest.cs | 4 +- .../_Imports.cs | 2 +- .../DomainEventBusTest.cs | 30 ++++++------ .../MASA.Contrib.DDD.Domain.Tests/_Imports.cs | 2 +- .../CustomerDbContext.cs | 2 +- .../MASA.Contrib.Data.UoW.EF.Tests.csproj} | 2 +- .../TestBase.cs | 2 +- .../TestUnitOfWork.cs | 10 ++-- .../_Imports.cs | 2 +- .../_Imports.cs | 2 +- .../_Imports.cs | 2 +- .../_Imports.cs | 2 +- 44 files changed, 143 insertions(+), 116 deletions(-) rename src/Data/{MASA.Contrib.Data.Uow.EF => MASA.Contrib.Data.UoW.EF}/DispatcherOptionsExtensions.cs (84%) rename src/Data/{MASA.Contrib.Data.Uow.EF/MASA.Contrib.Data.Uow.EF.csproj => MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj} (80%) rename src/Data/{MASA.Contrib.Data.Uow.EF => MASA.Contrib.Data.UoW.EF}/Transaction.cs (86%) rename src/Data/{MASA.Contrib.Data.Uow.EF => MASA.Contrib.Data.UoW.EF}/UnitOfWork.cs (96%) rename src/Data/{MASA.Contrib.Data.Uow.EF => MASA.Contrib.Data.UoW.EF}/_Imports.cs (88%) rename test/{MASA.Contrib.Data.Uow.EF.Tests => MASA.Contrib.Data.UoW.EF.Tests}/CustomerDbContext.cs (94%) rename test/{MASA.Contrib.Data.Uow.EF.Tests/MASA.Contrib.Data.Uow.EF.Tests.csproj => MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj} (96%) rename test/{MASA.Contrib.Data.Uow.EF.Tests => MASA.Contrib.Data.UoW.EF.Tests}/TestBase.cs (96%) rename test/{MASA.Contrib.Data.Uow.EF.Tests => MASA.Contrib.Data.UoW.EF.Tests}/TestUnitOfWork.cs (95%) rename test/{MASA.Contrib.Data.Uow.EF.Tests => MASA.Contrib.Data.UoW.EF.Tests}/_Imports.cs (89%) diff --git a/MASA.Contrib.sln b/MASA.Contrib.sln index 41a0d7273..f172e676c 100644 --- a/MASA.Contrib.sln +++ b/MASA.Contrib.sln @@ -40,10 +40,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DDD", "DDD", "{21180442-A6A EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Data", "Data", "{E33ADF54-4D35-49B7-BDA6-412587CA39FF}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.Uow.EF", "src\Data\MASA.Contrib.Data.Uow.EF\MASA.Contrib.Data.Uow.EF.csproj", "{626631CD-4FD5-424E-A678-27653F38CA3E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.Uow.EF.Tests", "test\MASA.Contrib.Data.Uow.EF.Tests\MASA.Contrib.Data.Uow.EF.Tests.csproj", "{63BB9F58-316E-4F20-8F45-B45D28FC2476}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Dispatcher.Events", "src\Dispatcher\MASA.Contrib.Dispatcher.Events\MASA.Contrib.Dispatcher.Events.csproj", "{1B44F2E7-28F5-4E88-B8A8-3F336800FD5C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest", "test\MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest\MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj", "{0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}" @@ -92,7 +88,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contribs.DDD.Domain.En EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MASA.Contrib.DDD.Domain.Repository.EF", "MASA.Contrib.DDD.Domain.Repository.EF", "{880E8263-AECC-4793-BD28-7CD03650D124}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository", "test\MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository\MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj", "{7A1493EC-196F-4389-A966-02E526453578}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository", "test\MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository\MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj", "{7A1493EC-196F-4389-A966-02E526453578}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.UoW.EF", "src\Data\MASA.Contrib.Data.UoW.EF\MASA.Contrib.Data.UoW.EF.csproj", "{1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.UoW.EF.Tests", "test\MASA.Contrib.Data.UoW.EF.Tests\MASA.Contrib.Data.UoW.EF.Tests.csproj", "{1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -110,22 +110,6 @@ Global {ED301FA5-4E70-460B-A0D4-1D79D135769F}.Release|Any CPU.Build.0 = Release|Any CPU {ED301FA5-4E70-460B-A0D4-1D79D135769F}.Release|x64.ActiveCfg = Release|Any CPU {ED301FA5-4E70-460B-A0D4-1D79D135769F}.Release|x64.Build.0 = Release|Any CPU - {626631CD-4FD5-424E-A678-27653F38CA3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {626631CD-4FD5-424E-A678-27653F38CA3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {626631CD-4FD5-424E-A678-27653F38CA3E}.Debug|x64.ActiveCfg = Debug|Any CPU - {626631CD-4FD5-424E-A678-27653F38CA3E}.Debug|x64.Build.0 = Debug|Any CPU - {626631CD-4FD5-424E-A678-27653F38CA3E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {626631CD-4FD5-424E-A678-27653F38CA3E}.Release|Any CPU.Build.0 = Release|Any CPU - {626631CD-4FD5-424E-A678-27653F38CA3E}.Release|x64.ActiveCfg = Release|Any CPU - {626631CD-4FD5-424E-A678-27653F38CA3E}.Release|x64.Build.0 = Release|Any CPU - {63BB9F58-316E-4F20-8F45-B45D28FC2476}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {63BB9F58-316E-4F20-8F45-B45D28FC2476}.Debug|Any CPU.Build.0 = Debug|Any CPU - {63BB9F58-316E-4F20-8F45-B45D28FC2476}.Debug|x64.ActiveCfg = Debug|Any CPU - {63BB9F58-316E-4F20-8F45-B45D28FC2476}.Debug|x64.Build.0 = Debug|Any CPU - {63BB9F58-316E-4F20-8F45-B45D28FC2476}.Release|Any CPU.ActiveCfg = Release|Any CPU - {63BB9F58-316E-4F20-8F45-B45D28FC2476}.Release|Any CPU.Build.0 = Release|Any CPU - {63BB9F58-316E-4F20-8F45-B45D28FC2476}.Release|x64.ActiveCfg = Release|Any CPU - {63BB9F58-316E-4F20-8F45-B45D28FC2476}.Release|x64.Build.0 = Release|Any CPU {1B44F2E7-28F5-4E88-B8A8-3F336800FD5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1B44F2E7-28F5-4E88-B8A8-3F336800FD5C}.Debug|Any CPU.Build.0 = Debug|Any CPU {1B44F2E7-28F5-4E88-B8A8-3F336800FD5C}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -310,6 +294,22 @@ Global {7A1493EC-196F-4389-A966-02E526453578}.Release|Any CPU.Build.0 = Release|Any CPU {7A1493EC-196F-4389-A966-02E526453578}.Release|x64.ActiveCfg = Release|Any CPU {7A1493EC-196F-4389-A966-02E526453578}.Release|x64.Build.0 = Release|Any CPU + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Debug|x64.ActiveCfg = Debug|Any CPU + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Debug|x64.Build.0 = Debug|Any CPU + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Release|Any CPU.Build.0 = Release|Any CPU + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Release|x64.ActiveCfg = Release|Any CPU + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Release|x64.Build.0 = Release|Any CPU + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Debug|x64.ActiveCfg = Debug|Any CPU + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Debug|x64.Build.0 = Debug|Any CPU + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Release|Any CPU.Build.0 = Release|Any CPU + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Release|x64.ActiveCfg = Release|Any CPU + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -329,8 +329,6 @@ Global {ED301FA5-4E70-460B-A0D4-1D79D135769F} = {593A3114-D1E0-47ED-BC37-58E08886175B} {21180442-A6A5-4239-A2AD-33FF5BB80E72} = {42DF7AAC-362C-48F4-B76A-BDEEEFF17CC9} {E33ADF54-4D35-49B7-BDA6-412587CA39FF} = {42DF7AAC-362C-48F4-B76A-BDEEEFF17CC9} - {626631CD-4FD5-424E-A678-27653F38CA3E} = {E33ADF54-4D35-49B7-BDA6-412587CA39FF} - {63BB9F58-316E-4F20-8F45-B45D28FC2476} = {38E6C400-90C0-493E-9266-C1602E229F1B} {1B44F2E7-28F5-4E88-B8A8-3F336800FD5C} = {FBD326D3-E59C-433E-A88E-14E179E3093D} {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6} = {2BE750A5-8AC7-457C-9BB2-6E3D5E2D23B8} {D55A7D3B-9C24-4029-BC03-41B28AD11DB6} = {2BE750A5-8AC7-457C-9BB2-6E3D5E2D23B8} @@ -356,6 +354,8 @@ Global {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32} = {13EDB361-AF88-4F89-B4AB-46622BCCBC37} {880E8263-AECC-4793-BD28-7CD03650D124} = {38E6C400-90C0-493E-9266-C1602E229F1B} {7A1493EC-196F-4389-A966-02E526453578} = {880E8263-AECC-4793-BD28-7CD03650D124} + {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F} = {E33ADF54-4D35-49B7-BDA6-412587CA39FF} + {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7} = {38E6C400-90C0-493E-9266-C1602E229F1B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03} diff --git a/README.md b/README.md index 6786c904c..12df8110f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ MASA.Contrib │ ├── nuget.config ├── src │ ├── Data -│ │ ├── MASA.Contrib.Data.Uow.EF Unit of work +│ │ ├── MASA.Contrib.Data.UoW.EF Unit of work │ │ └── MASA.Contribs.Data.Contracts.EF Protocol EF version │ ├── DDD │ │ ├── MASA.Contribs.DDD.Domain In-process and cross-process support @@ -36,7 +36,7 @@ MASA.Contrib │ │ ├── MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests │ │ ├── MASA.Contrib.Dispatcher.Events.CheckMethodsType.Tests │ │ ├── MASA.Contrib.Dispatcher.Events.Tests -│ ├── MASA.Contrib.Data.Uow.EF.Tests +│ ├── MASA.Contrib.Data.UoW.EF.Tests │ ├── MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests │ ├── MASA.Contribs.DDD.Domain.Tests │ ├── MASA.Contribs.DDD.Domain.Repository.EF.Tests diff --git a/README.zh-CN.md b/README.zh-CN.md index 05cb5ae90..36a97a2a1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -2,7 +2,7 @@ # MASA.Contrib -MASA.Contrib是基于[MASA.BuildingBlocks](https://github.com/masastack/MASA.BuildingBlocks)提供开放, 社区驱动的可重用组件,用于构建网格应用程序。这些组件将被[MASA Stack](https://github.com/masastack)和[MASA Labs](https://github.com/masalabs)等项目使用。 +MASA.Contrib是基于[MASA.BuildingBlocks](https://github.com/masastack/MASA.BuildingBlocks)提供开放, 社区驱动的可重用组件,用于构建网格应用程序。这些组件将被[MASA Stack](https://github.com/masastack)和[MASA Labs](https://github.com/masalabs)等项目使用。 ## 结构 @@ -12,7 +12,7 @@ MASA.Contrib │ ├── nuget.config ├── src │ ├── Data -│ │ ├── MASA.Contrib.Data.Uow.EF 工作单元 +│ │ ├── MASA.Contrib.Data.UoW.EF 工作单元 │ │ └── MASA.Contribs.Data.Contracts.EF 规约EF版 │ ├── DDD │ │ ├── MASA.Contribs.DDD.Domain 进程内、跨进程都支持 @@ -36,7 +36,7 @@ MASA.Contrib │ │ ├── MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests │ │ ├── MASA.Contrib.Dispatcher.Events.CheckMethodsType.Tests │ │ ├── MASA.Contrib.Dispatcher.Events.Tests -│ ├── MASA.Contrib.Data.Uow.EF.Tests +│ ├── MASA.Contrib.Data.UoW.EF.Tests │ ├── MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests │ ├── MASA.Contribs.DDD.Domain.Tests │ ├── MASA.Contribs.DDD.Domain.Repository.EF.Tests diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj index 2e7fffff8..706d68185 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/_Imports.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/_Imports.cs index 14372d0ed..345d1a833 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/_Imports.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.DDD.Domain.Entities; global using MASA.BuildingBlocks.DDD.Domain.Repositories; global using MASA.BuildingBlocks.Dispatcher.Events; diff --git a/src/DDD/MASA.Contrib.DDD.Domain/DomainEventBus.cs b/src/DDD/MASA.Contrib.DDD.Domain/DomainEventBus.cs index f6e6c0822..82dea5513 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/DomainEventBus.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/DomainEventBus.cs @@ -47,5 +47,10 @@ public async Task PublishQueueAsync() } } + public async Task CommitAsync(CancellationToken cancellationToken = default) + { + await _unitOfWork.CommitAsync(cancellationToken); + } + public IEnumerable GetAllEventTypes() => _options.AllEventTypes.Concat(_eventBus.GetAllEventTypes()).Distinct(); } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj index e7e66739f..cc3af397a 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain/README.md b/src/DDD/MASA.Contrib.DDD.Domain/README.md index 2df045361..d0b37c510 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/README.md +++ b/src/DDD/MASA.Contrib.DDD.Domain/README.md @@ -12,7 +12,7 @@ Install-Package MASA.Contrib.Dispatcher.Events Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.Dapr Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF -Install-Package MASA.Contrib.Data.Uow.EF +Install-Package MASA.Contrib.Data.UoW.EF ``` 1. Add DomainEventBus @@ -22,7 +22,7 @@ builder.Services .AddDomainEventBus(options => { options.UseEventBus()//Use in-process events - .UseUow(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=idientity")) + .UseUoW(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=idientity")) .UseDaprEventBus()///Use cross-process events .UseEventLog() .UseRepository();//Use the EF version of Repository to achieve diff --git a/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md b/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md index 7293c8017..95c16a4cb 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md +++ b/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md @@ -12,7 +12,7 @@ Install-Package MASA.Contrib.Dispatcher.Events Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.Dapr Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF -Install-Package MASA.Contrib.Data.Uow.EF +Install-Package MASA.Contrib.Data.UoW.EF ``` 1. 添加DomainEventBus @@ -22,7 +22,7 @@ builder.Services .AddDomainEventBus(options => { options.UseEventBus()//使用进程内事件 - .UseUow(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=idientity")) + .UseUoW(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=idientity")) .UseDaprEventBus()///使用跨进程事件 .UseEventLog() .UseRepository();//使用Repository的EF版实现 diff --git a/src/DDD/MASA.Contrib.DDD.Domain/ServiceCollectionExtensions.cs b/src/DDD/MASA.Contrib.DDD.Domain/ServiceCollectionExtensions.cs index 7211a238c..75aa97ab7 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/ServiceCollectionExtensions.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/ServiceCollectionExtensions.cs @@ -26,7 +26,7 @@ public static IServiceCollection AddDomainEventBus( if (services.All(service => service.ServiceType != typeof(IUnitOfWork))) { - throw new Exception("Please add Uow first."); + throw new Exception("Please add UoW first."); } if (services.All(service => service.ServiceType != typeof(IIntegrationEventBus))) diff --git a/src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs b/src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs index 021c36b81..971573b0d 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.DDD.Domain.Entities; global using MASA.BuildingBlocks.DDD.Domain.Events; global using MASA.BuildingBlocks.DDD.Domain.Repositories; diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj index c29fc9254..2a7fc1298 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs b/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs index a6c47eb16..d5fab308d 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs @@ -2,16 +2,17 @@ namespace MASA.Contrib.Data.Contracts.EF.SoftDelete { public class TransactionSaveChangesFilter : ISaveChangesFilter { - private readonly IUnitOfWork _unitOfWork; + private readonly IServiceProvider _serviceProvider; - public TransactionSaveChangesFilter(IUnitOfWork unitOfWork) => _unitOfWork = unitOfWork; + public TransactionSaveChangesFilter(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; public void OnExecuting(ChangeTracker changeTracker) { changeTracker.DetectChanges(); - if (changeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) && !_unitOfWork.TransactionHasBegun) + var unitOfWork = _serviceProvider.GetRequiredService(); + if (changeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) && !unitOfWork.TransactionHasBegun) { - var transaction = _unitOfWork.Transaction; // Open the transaction + var transaction = unitOfWork.Transaction; // Open the transaction } } } diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/_Imports.cs b/src/Data/MASA.Contrib.Data.Contracts.EF/_Imports.cs index c160c452a..d4c3c90c7 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/_Imports.cs +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/_Imports.cs @@ -1,5 +1,5 @@ global using MASA.BuildingBlocks.Data.Contracts; -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.Contrib.Data.Contracts.EF.SoftDelete; global using MASA.Utils.Data.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore; diff --git a/src/Data/MASA.Contrib.Data.Uow.EF/DispatcherOptionsExtensions.cs b/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs similarity index 84% rename from src/Data/MASA.Contrib.Data.Uow.EF/DispatcherOptionsExtensions.cs rename to src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs index c7cb8535e..118804a1a 100644 --- a/src/Data/MASA.Contrib.Data.Uow.EF/DispatcherOptionsExtensions.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Data.Uow.EF; +namespace MASA.Contrib.Data.UoW.EF; public static class DispatcherOptionsExtensions { @@ -12,8 +12,8 @@ public static IDispatcherOptions UseUoW( throw new ArgumentNullException(nameof(options.Services)); } - if (options.Services.Any(service => service.ImplementationType == typeof(UowProvider))) return options; - options.Services.AddSingleton(); + if (options.Services.Any(service => service.ImplementationType == typeof(UoWProvider))) return options; + options.Services.AddSingleton(); options.Services.AddLogging(); options.Services.AddScoped>(); @@ -27,7 +27,7 @@ public static IDispatcherOptions UseUoW( return options; } - private class UowProvider + private class UoWProvider { } diff --git a/src/Data/MASA.Contrib.Data.Uow.EF/MASA.Contrib.Data.Uow.EF.csproj b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj similarity index 80% rename from src/Data/MASA.Contrib.Data.Uow.EF/MASA.Contrib.Data.Uow.EF.csproj rename to src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj index 9a41bc05d..65959f903 100644 --- a/src/Data/MASA.Contrib.Data.Uow.EF/MASA.Contrib.Data.Uow.EF.csproj +++ b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj @@ -7,11 +7,11 @@ - - - + + + - + diff --git a/src/Data/MASA.Contrib.Data.Uow.EF/Transaction.cs b/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs similarity index 86% rename from src/Data/MASA.Contrib.Data.Uow.EF/Transaction.cs rename to src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs index c4a02136c..12b3eca2c 100644 --- a/src/Data/MASA.Contrib.Data.Uow.EF/Transaction.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace MASA.Contrib.Data.Uow.EF; +namespace MASA.Contrib.Data.UoW.EF; public class Transaction : ITransaction { diff --git a/src/Data/MASA.Contrib.Data.Uow.EF/UnitOfWork.cs b/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs similarity index 96% rename from src/Data/MASA.Contrib.Data.Uow.EF/UnitOfWork.cs rename to src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs index bb619503f..f4cde3a84 100644 --- a/src/Data/MASA.Contrib.Data.Uow.EF/UnitOfWork.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Data.Uow.EF; +namespace MASA.Contrib.Data.UoW.EF; public class UnitOfWork : IUnitOfWork where TDbContext : MasaDbContext @@ -38,7 +38,6 @@ public async Task CommitAsync(CancellationToken cancellationToken = default) { if (!TransactionHasBegun) { - await SaveChangesAsync(); return; } diff --git a/src/Data/MASA.Contrib.Data.Uow.EF/_Imports.cs b/src/Data/MASA.Contrib.Data.UoW.EF/_Imports.cs similarity index 88% rename from src/Data/MASA.Contrib.Data.Uow.EF/_Imports.cs rename to src/Data/MASA.Contrib.Data.UoW.EF/_Imports.cs index 005db3fab..81fcd49fa 100644 --- a/src/Data/MASA.Contrib.Data.Uow.EF/_Imports.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.Utils.Data.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore; diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs index 4b8c5ddd2..af121ac17 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs @@ -50,4 +50,12 @@ public async Task PublishAsync(TEvent @event) where TEvent : IEvent } public IEnumerable GetAllEventTypes() => _options.GetAllEventTypes(); + + public async Task CommitAsync(CancellationToken cancellationToken = default) + { + if (_unitOfWork is null) + throw new ArgumentNullException(nameof(IUnitOfWork), "You need to UseUoW when adding services"); + + await _unitOfWork.CommitAsync(cancellationToken); + } } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs index 91e1fd9de..1bb69f7e5 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs @@ -18,16 +18,9 @@ public async Task HandleAsync(TEvent @event, EventHandlerDelegate next) if (@event is ITransaction transactionEvent) { - if (transactionEvent.UnitOfWork != null) + if (transactionEvent.UnitOfWork != null && transactionEvent.UnitOfWork.TransactionHasBegun) { - if (transactionEvent.UnitOfWork.TransactionHasBegun) - { - await transactionEvent.UnitOfWork.CommitAsync(); - } - else - { - await transactionEvent.UnitOfWork.SaveChangesAsync(); - } + await transactionEvent.UnitOfWork.CommitAsync(); } } } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj index a80128258..4915dde83 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs index bce7d4024..331c6737c 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using MASA.Contrib.Dispatcher.Events.Enums; diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs index 7621bd6f3..0835dc9f2 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs @@ -82,4 +82,12 @@ private async Task PublishIntegrationAsync(TEvent @event) await _eventLogService.MarkEventAsFailedAsync(@event.Id); } } + + public async Task CommitAsync(CancellationToken cancellationToken = default) + { + if (_unitOfWork is null) + throw new ArgumentNullException(nameof(IUnitOfWork), "You need to UseUoW when adding services"); + + await _unitOfWork.CommitAsync(cancellationToken); + } } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj index 3fc9a9d3f..bff8b21c5 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md index 1f9f5ba02..447920fd8 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.md @@ -7,7 +7,7 @@ Example: ```C# Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.Dapr //Send cross-process messages Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF //Record cross-process message logs -Install-Package MASA.Contrib.Data.Uow.EF //Use UnitOfWork +Install-Package MASA.Contrib.Data.UoW.EF //Use UnitOfWork ``` 1. Add IIntegrationEventBus diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-CN.md b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-CN.md index 485103588..79d390f00 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-CN.md +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-CN.md @@ -7,7 +7,7 @@ ```C# Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.Dapr //发送跨进程消息 Install-Package MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF //记录跨进程消息日志 -Install-Package MASA.Contrib.Data.Uow.EF //使用工作单元 +Install-Package MASA.Contrib.Data.UoW.EF //使用工作单元 ``` 1. 添加IIntegrationEventBus diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/_Imports.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/_Imports.cs index 4a7056617..2bc91ba12 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/_Imports.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/_Imports.cs @@ -1,5 +1,5 @@ global using Dapr.Client; -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents.Logs; diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs index 480d65c0b..e3f491902 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs @@ -34,10 +34,12 @@ public async Task SaveEventAsync(IIntegrationEvent @event, DbTransaction transac { if (transaction == null) throw new ArgumentNullException(nameof(transaction)); if (_eventLogContext.Database.CurrentTransaction == null) - _eventLogContext.Database.UseTransaction(transaction, Guid.NewGuid()); + await _eventLogContext.Database.UseTransactionAsync(transaction, Guid.NewGuid()); var eventLogEntry = new IntegrationEventLog(@event, _eventLogContext.Database.CurrentTransaction!.TransactionId); await _eventLogContext.EventLogs.AddAsync(eventLogEntry); await _eventLogContext.SaveChangesAsync(); + + CheckAndDetached(eventLogEntry); } public Task MarkEventAsPublishedAsync(Guid eventId) @@ -55,7 +57,7 @@ public Task MarkEventAsFailedAsync(Guid eventId) return UpdateEventStatus(eventId, IntegrationEventStates.PublishedFailed); } - private Task UpdateEventStatus(Guid eventId, IntegrationEventStates status) + private async Task UpdateEventStatus(Guid eventId, IntegrationEventStates status) { var eventLogEntry = _eventLogContext.EventLogs.Single(e => e.Id == eventId); eventLogEntry.State = status; @@ -64,6 +66,17 @@ private Task UpdateEventStatus(Guid eventId, IntegrationEventStates status) eventLogEntry.TimesSent++; _eventLogContext.EventLogs.Update(eventLogEntry); - return _eventLogContext.SaveChangesAsync(); + await _eventLogContext.SaveChangesAsync(); + + CheckAndDetached(eventLogEntry); + } + + private void CheckAndDetached(IntegrationEventLog integrationEvent) + { + return; + if (_eventLogContext.ChangeTracker.QueryTrackingBehavior != QueryTrackingBehavior.TrackAll) + { + _eventLogContext.Entry(integrationEvent).State = EntityState.Detached; + } } } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj index 2c25ed79e..2bcd80cb6 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj index 70f79c30a..e20d3f74c 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj index b8dd6b327..c485abb3b 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs index 5e431db8f..d382568dd 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs @@ -27,8 +27,8 @@ public void TestUseCustomRepositoryAndNotImplementation() { var services = new ServiceCollection(); - Mock uow = new(); - services.AddScoped(serviceProvider => uow.Object); + Mock uoW = new(); + services.AddScoped(serviceProvider => uoW.Object); Assert.ThrowsException(() => new DispatcherOptions(services).UseRepository(typeof(TestBase).Assembly, typeof(IUserRepository).Assembly)); } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs index 763686eef..08bc80fd4 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.DDD.Domain.Entities; global using MASA.BuildingBlocks.DDD.Domain.Entities.Auditing; global using MASA.BuildingBlocks.DDD.Domain.Repositories; diff --git a/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs b/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs index f4b86aeaa..9f4ced875 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs +++ b/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs @@ -89,7 +89,7 @@ public void TestNotUseUnitOfWork() services.AddScoped(serviceProvider => eventBus.Object); var ex = Assert.ThrowsException(() => services.AddDomainEventBus()); - Assert.IsTrue(ex.Message == "Please add Uow first."); + Assert.IsTrue(ex.Message == "Please add UoW first."); } [TestMethod] @@ -100,8 +100,8 @@ public void TestNotUseIntegrationEventBus() var eventBus = new Mock(); services.AddScoped(serviceProvider => eventBus.Object); - var uow = new Mock(); - services.AddScoped(serviceProvider => uow.Object); + var uoW = new Mock(); + services.AddScoped(serviceProvider => uoW.Object); var ex = Assert.ThrowsException(() => services.AddDomainEventBus()); Assert.IsTrue(ex.Message == "Please add IntegrationEventBus first."); @@ -115,8 +115,8 @@ public void TestNullAssembly() var eventBus = new Mock(); services.AddScoped(serviceProvider => eventBus.Object); - var uow = new Mock(); - services.AddScoped(serviceProvider => uow.Object); + var uoW = new Mock(); + services.AddScoped(serviceProvider => uoW.Object); var integrationEventBus = new Mock(); services.AddScoped(serviceProvider => integrationEventBus.Object); @@ -132,8 +132,8 @@ public void TestNotRepository() var eventBus = new Mock(); services.AddScoped(serviceProvider => eventBus.Object); - var uow = new Mock(); - services.AddScoped(serviceProvider => uow.Object); + var uoW = new Mock(); + services.AddScoped(serviceProvider => uoW.Object); var integrationEventBus = new Mock(); services.AddScoped(serviceProvider => integrationEventBus.Object); @@ -156,8 +156,8 @@ public void TestUserRepository() var eventBus = new Mock(); services.AddScoped(serviceProvider => eventBus.Object); - var uow = new Mock(); - services.AddScoped(serviceProvider => uow.Object); + var uoW = new Mock(); + services.AddScoped(serviceProvider => uoW.Object); var integrationEventBus = new Mock(); services.AddScoped(serviceProvider => integrationEventBus.Object); @@ -207,12 +207,12 @@ public async Task TestPublishQueueAsync() await Task.FromResult(result); }); - var uow = new Mock(); - uow.Setup(u => u.CommitAsync(default)).Verifiable(); + var uoW = new Mock(); + uoW.Setup(u => u.CommitAsync(default)).Verifiable(); var options = Options.Create(new DispatcherOptions(services) { Assemblies = AppDomain.CurrentDomain.GetAssemblies() }); - var domainEventBus = new DomainEventBus(eventBus.Object, integrationEventBus.Object, uow.Object, options); + var domainEventBus = new DomainEventBus(eventBus.Object, integrationEventBus.Object, uoW.Object, options); // todo: It has no practical meaning, just to show the order of entering and leaving the team await domainEventBus.Enqueue(new PaymentSucceededDomainEvent() { OrderId = "ef5f84db-76e4-4c79-9815-99a1543b6589" }); @@ -233,12 +233,12 @@ public async Task TestPublishDomainQuery() query.Result = "apple"; }); var integrationEventBus = new Mock(); - var uow = new Mock(); - uow.Setup(u => u.CommitAsync(default)).Verifiable(); + var uoW = new Mock(); + uoW.Setup(u => u.CommitAsync(default)).Verifiable(); var options = Options.Create(new DispatcherOptions(services) { Assemblies = AppDomain.CurrentDomain.GetAssemblies() }); - var domainEventBus = new DomainEventBus(eventBus.Object, integrationEventBus.Object, uow.Object, options); + var domainEventBus = new DomainEventBus(eventBus.Object, integrationEventBus.Object, uoW.Object, options); var query = new ProductItemDomainQuery() { ProductId = "2f8d4c3c-1736-4e56-a188-f865da6a63d1" }; await domainEventBus.PublishAsync(query); diff --git a/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs index 3415e4957..2992c4d89 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs +++ b/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.DDD.Domain.Events; global using MASA.BuildingBlocks.DDD.Domain.Repositories; global using MASA.BuildingBlocks.Dispatcher.Events; diff --git a/test/MASA.Contrib.Data.Uow.EF.Tests/CustomerDbContext.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/CustomerDbContext.cs similarity index 94% rename from test/MASA.Contrib.Data.Uow.EF.Tests/CustomerDbContext.cs rename to test/MASA.Contrib.Data.UoW.EF.Tests/CustomerDbContext.cs index 92d31bad0..8b4a72d28 100644 --- a/test/MASA.Contrib.Data.Uow.EF.Tests/CustomerDbContext.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/CustomerDbContext.cs @@ -1,6 +1,6 @@ using MASA.Utils.Data.EntityFrameworkCore; -namespace MASA.Contrib.Data.Uow.EF.Tests; +namespace MASA.Contrib.Data.UoW.EF.Tests; public class CustomerDbContext : MasaDbContext { diff --git a/test/MASA.Contrib.Data.Uow.EF.Tests/MASA.Contrib.Data.Uow.EF.Tests.csproj b/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj similarity index 96% rename from test/MASA.Contrib.Data.Uow.EF.Tests/MASA.Contrib.Data.Uow.EF.Tests.csproj rename to test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj index 2f7ff853c..ca11a7ee2 100644 --- a/test/MASA.Contrib.Data.Uow.EF.Tests/MASA.Contrib.Data.Uow.EF.Tests.csproj +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj @@ -21,7 +21,7 @@ - + diff --git a/test/MASA.Contrib.Data.Uow.EF.Tests/TestBase.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/TestBase.cs similarity index 96% rename from test/MASA.Contrib.Data.Uow.EF.Tests/TestBase.cs rename to test/MASA.Contrib.Data.UoW.EF.Tests/TestBase.cs index 20eb11ab3..7d3289cfe 100644 --- a/test/MASA.Contrib.Data.Uow.EF.Tests/TestBase.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/TestBase.cs @@ -1,6 +1,6 @@ using Microsoft.Data.Sqlite; -namespace MASA.Contrib.Data.Uow.EF.Tests +namespace MASA.Contrib.Data.UoW.EF.Tests { public class TestBase : IDisposable { diff --git a/test/MASA.Contrib.Data.Uow.EF.Tests/TestUnitOfWork.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs similarity index 95% rename from test/MASA.Contrib.Data.Uow.EF.Tests/TestUnitOfWork.cs rename to test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs index 2a7956258..8e73b038b 100644 --- a/test/MASA.Contrib.Data.Uow.EF.Tests/TestUnitOfWork.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs @@ -1,17 +1,17 @@ -namespace MASA.Contrib.Data.Uow.EF.Tests; +namespace MASA.Contrib.Data.UoW.EF.Tests; [TestClass] public class TestUnitOfWork : TestBase { [TestMethod] - public void TestAddUowAndNullServices() + public void TestAddUoWAndNullServices() { var options = new Mock(); Assert.ThrowsException(() => options.Object.UseUoW()); } [TestMethod] - public void TestAddUow() + public void TestAddUoW() { var options = new Mock(); options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); @@ -21,7 +21,7 @@ public void TestAddUow() } [TestMethod] - public void TestAddUowAndUseSqlLite() + public void TestAddUoWAndUseSqlLite() { var options = new Mock(); options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); @@ -31,7 +31,7 @@ public void TestAddUowAndUseSqlLite() } [TestMethod] - public void TestAddMultUow() + public void TestAddMultUoW() { var options = new Mock(); options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); diff --git a/test/MASA.Contrib.Data.Uow.EF.Tests/_Imports.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/_Imports.cs similarity index 89% rename from test/MASA.Contrib.Data.Uow.EF.Tests/_Imports.cs rename to test/MASA.Contrib.Data.UoW.EF.Tests/_Imports.cs index dafc00074..d13736058 100644 --- a/test/MASA.Contrib.Data.Uow.EF.Tests/_Imports.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.Dispatcher.Events; global using Microsoft.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/_Imports.cs index 506c0cf2d..63c70300f 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests.Events; diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/_Imports.cs index 0da27f506..6a4e8b6aa 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/_Imports.cs @@ -1,5 +1,5 @@ global using Dapr.Client; -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents.Logs; diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/_Imports.cs index b268ee00a..cb7e74de8 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/_Imports.cs @@ -1,4 +1,4 @@ -global using MASA.BuildingBlocks.Data.Uow; +global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents.Logs; global using MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.Domain.Entities; From ac0626506916c199dd0237e93df434e6ea8c4395 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Mon, 15 Nov 2021 04:44:47 +0000 Subject: [PATCH 04/39] Configuration and UnitTest --- MASA.Contrib.sln | 135 ++++ .../ConfigurationAPIClient.cs | 119 +++ .../ConfigurationAPIManage.cs | 28 + .../Internal/ConfigFormats.cs | 8 + .../Internal/ConfigurationAPIBase.cs | 37 + .../Internal/Constants.cs | 12 + .../Internal/DccConfigurationRepository.cs | 92 +++ .../Internal/DccFactory.cs | 21 + .../Internal/Model/Property.cs | 8 + .../Internal/Model/PublishRelease.cs | 8 + .../Parser/JsonConfigurationParser.cs | 101 +++ .../Parser/PropertyConfigurationParser.cs | 7 + .../MASA.Contrib.BasicAbility.Dcc.csproj | 20 + .../MasaConfigurationExtensions.cs | 195 +++++ .../Options/DccConfigurationOptions.cs | 11 + .../Options/DccExpandSectionOptions.cs | 9 + .../Options/DccSectionOptions.cs | 24 + .../MASA.Contrib.BasicAbility.Dcc/_Imports.cs | 23 + .../LocalMasaConfigurationRepository.cs | 71 ++ .../MASA.Contrib.Configuration.csproj | 14 + .../MasaConfigurationBuilder.cs | 52 ++ .../MasaConfigurationExtensions.cs | 35 + .../MasaConfigurationOptions.cs | 19 + .../MasaConfigurationProvider.cs | 64 ++ .../MasaConfigurationSource.cs | 17 + .../MasaRelationOptions.cs | 33 + .../ServiceCollectionExtensions.cs | 120 +++ .../MASA.Contrib.Configuration/_Imports.cs | 15 + .../DispatcherOptionsExtensions.cs | 8 +- .../Internal/LinqExtensions.cs | 67 ++ .../ServiceCollectionRepositoryExtensions.cs | 43 +- ...SA.Contrib.DDD.Domain.Repository.EF.csproj | 10 +- .../Repository.cs | 50 +- .../_Imports.cs | 2 + .../MASA.Contrib.DDD.Domain/DomainEventBus.cs | 26 +- .../Events/DomainQuery.cs | 6 +- .../MASA.Contrib.DDD.Domain.csproj | 4 +- .../Options/DispatcherOptions.cs | 10 +- .../ServiceCollectionExtensions.cs | 8 +- src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs | 1 + .../MASA.Contrib.Data.Contracts.EF.csproj | 10 +- .../TransactionSaveChangesFilter.cs | 23 +- .../DispatcherOptionsExtensions.cs | 22 +- .../MASA.Contrib.Data.UoW.EF.csproj | 10 +- .../MASA.Contrib.Data.UoW.EF/Transaction.cs | 2 - .../MASA.Contrib.Data.UoW.EF/UnitOfWork.cs | 23 +- src/Data/MASA.Contrib.Data.UoW.EF/_Imports.cs | 1 + .../EventBus.cs | 4 +- .../Middleware/TransactionMiddleware.cs | 25 +- .../MASA.Contrib.Dispatcher.Events.csproj | 10 +- .../Options/DispatcherOptions.cs | 14 +- .../IntegrationEventBus.cs | 4 +- ...b.Dispatcher.IntegrationEvents.Dapr.csproj | 8 +- .../Options/DispatcherOptions.cs | 17 +- .../IntegrationEventLogService.cs | 8 +- .../Internal/QueryFilterProvider.cs | 3 - ...cher.IntegrationEvents.EventLogs.EF.csproj | 8 +- .../_Imports.cs | 2 + ...MASA.Contrib.ReadWriteSpliting.CQRS.csproj | 8 +- .../Queries/QueryHandler.cs | 11 +- .../MASA.Contrib.Service.MinimalAPIs.csproj | 7 +- .../ServiceBase.cs | 1 + .../ServiceCollectionExtensions.cs | 13 +- .../_Imports.cs | 1 + .../DccClientTest.cs | 342 +++++++++ .../DccManageTest.cs | 163 ++++ .../DccTest.cs | 701 ++++++++++++++++++ .../Internal/Common/SerializeCommon.cs | 7 + .../Internal/Config/Property.cs | 8 + .../Internal/Config/PublishRelease.cs | 8 + .../Internal/CustomTrigger.cs | 26 + .../Internal/Enum/ConfigFormats.cs | 8 + .../Internal/Model/Brands.cs | 14 + ...MASA.Contrib.BasicAbility.Dcc.Tests.csproj | 36 + .../_Imports.cs | 14 + .../appsettings.json | 21 + .../expandSections.json | 30 + .../ErrorKafkaOptions.cs | 12 + .../KafkaOptions.cs | 15 + ...figuration.ErrorSectionAutoMapTests.csproj | 14 + .../_Imports.cs | 2 + ...ation.MountErrorSectionAutoMapTests.csproj | 14 + .../MountSectionRedisOptions.cs | 12 + .../_Imports.cs | 2 + .../Config/RabbitMqOptions.cs | 16 + .../Config/RedisOptions.cs | 10 + .../Config/SystemOptions.cs | 14 + .../ConfigurationTest.cs | 295 ++++++++ .../MASA.Contrib.Configuration.Tests.csproj | 43 ++ .../_Imports.cs | 8 + .../appsettings.json | 9 + .../rabbitMq.json | 7 + .../redis.json | 5 + .../Courses.cs | 19 + ...pository.EF.CombinedKeysNoFindTests.csproj | 14 + .../_Imports.cs | 1 + ...ain.Repository.EF.CombinedKeysTests.csproj | 14 + .../Students.cs | 28 + .../_Imports.cs | 1 + ...main.Repository.EF.CustomRepository.csproj | 1 + .../Hobbies.cs | 16 + ...DD.Domain.Repository.EF.EntityTests.csproj | 14 + .../_Imports.cs | 1 + .../BaseRepositoryTest.cs | 78 ++ .../Domain/Entities/Orders.cs | 37 +- .../Domain/Repositories/IOrderRepository.cs | 1 + .../Infrastructure/CustomDbContext.cs | 23 + .../Options/DispatcherOptions.cs | 8 - .../Infrastructure/OrderDbContext.cs | 8 - .../Repositories/OrderRepository.cs | 19 +- ...trib.DDD.Domain.Repository.EF.Tests.csproj | 11 +- .../RepositoryTest.cs | 265 ++++++- .../TestBase.cs | 22 +- .../_Imports.cs | 3 +- .../DomainEventBusTest.cs | 312 +++++--- .../EventHandlers/PaymentSucceededHandlers.cs | 14 - .../Events/ForgetPasswordEvent.cs | 10 + .../MASA.Contrib.DDD.Domain.Tests.csproj | 6 +- .../Repositories/UserRepository.cs | 96 --- .../Services/UserDomainService.cs | 4 +- .../MASA.Contrib.DDD.Domain.Tests/TestBase.cs | 33 - .../MASA.Contrib.DDD.Domain.Tests/_Imports.cs | 3 +- .../Domain/Entities/Courses.cs | 16 + .../Domain/Entities/Students.cs | 16 + .../Infrastructure/CustomDbContext.cs | 10 + ...MASA.Contrib.Data.Contracts.EF.Test.csproj | 29 + .../SoftDeleteTest.cs | 113 +++ .../_Imports.cs | 11 + .../CustomerDbContext.cs | 16 +- .../MASA.Contrib.Data.UoW.EF.Tests.csproj | 8 +- .../TestBase.cs | 41 +- .../TestUnitOfWork.cs | 219 ++++-- .../_Imports.cs | 2 + ...spatcher.Events.BenchmarkDotnetTest.csproj | 4 +- .../EventHandlers/AddGoodsHandler.cs | 2 - .../_Imports.cs | 1 + .../EventHandlers/AddCatalogHandler.cs | 2 - .../_Imports.cs | 1 + .../EventHandlers/UserEventHandler.cs | 2 - ...cher.Events.OnlyCancelHandler.Tests.csproj | 2 +- .../_Imports.cs | 1 + .../EventHandlers/EditCategoryHandler.cs | 2 - ...tcher.Events.OrderEqualBySaga.Tests.csproj | 2 +- .../_Imports.cs | 1 + .../OrderStockConfirmedHandler.cs | 2 - ...ts.OrderLessThanZeroByFeature.Tests.csproj | 2 +- .../_Imports.cs | 1 + .../EventHandlers/EditGoodsHandler.cs | 2 - .../_Imports.cs | 1 + .../FeaturesTest.cs | 36 +- ...ASA.Contrib.Dispatcher.Events.Tests.csproj | 4 + .../_Imports.cs | 1 + .../Events/ForgetPasswordEvent.cs | 8 - .../Events/RegisterUserIntegrationEvent.cs | 10 + .../IntegrationEventBusTest.cs | 363 ++++++--- ...atcher.IntegrationEvents.Dapr.Tests.csproj | 4 + .../RegisterServicesBusTest.cs | 15 - .../TestBase.cs | 86 --- .../_Imports.cs | 2 + .../IntegrationEventLogServiceTest.cs | 21 +- ...ntegrationEvents.EventLogs.EF.Tests.csproj | 6 +- .../TestBase.cs | 4 - .../_Imports.cs | 4 + .../Commands/CreateProductionCommand.cs | 8 + .../CqrsTest.cs | 51 ++ .../CreateProductionCommandHandler.cs | 24 + ...ontrib.ReadWriteSpliting.CQRS.Tests.csproj | 27 + .../ProductionQueryHandler.cs | 18 + .../Queries/ProductionItemQuery.cs | 8 + .../_Imports.cs | 8 + ...A.Contrib.Service.MinimalAPIs.Tests.csproj | 26 + .../MinimalAPITest.cs | 48 ++ .../Services/CustomService.cs | 13 + .../_Imports.cs | 4 + .../{User.cs => Users.cs} | 2 +- 175 files changed, 5109 insertions(+), 887 deletions(-) create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIManage.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigFormats.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigurationAPIBase.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Constants.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccConfigurationRepository.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccFactory.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Model/Property.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Model/PublishRelease.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/JsonConfigurationParser.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/PropertyConfigurationParser.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccConfigurationOptions.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccExpandSectionOptions.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccSectionOptions.cs create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/_Imports.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/LocalMasaConfigurationRepository.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj create mode 100644 src/Configuration/MASA.Contrib.Configuration/MasaConfigurationBuilder.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/MasaConfigurationExtensions.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/MasaConfigurationOptions.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/MasaConfigurationProvider.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/MasaConfigurationSource.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/MasaRelationOptions.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/ServiceCollectionExtensions.cs create mode 100644 src/Configuration/MASA.Contrib.Configuration/_Imports.cs create mode 100644 src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/LinqExtensions.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Common/SerializeCommon.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Config/Property.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Config/PublishRelease.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/CustomTrigger.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Enum/ConfigFormats.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Model/Brands.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/MASA.Contrib.BasicAbility.Dcc.Tests.csproj create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/_Imports.cs create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/appsettings.json create mode 100644 test/MASA.Contrib.BasicAbility.Dcc.Tests/expandSections.json create mode 100644 test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/ErrorKafkaOptions.cs create mode 100644 test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/KafkaOptions.cs create mode 100644 test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj create mode 100644 test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/_Imports.cs create mode 100644 test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj create mode 100644 test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MountSectionRedisOptions.cs create mode 100644 test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/_Imports.cs create mode 100644 test/MASA.Contrib.Configuration.Tests/Config/RabbitMqOptions.cs create mode 100644 test/MASA.Contrib.Configuration.Tests/Config/RedisOptions.cs create mode 100644 test/MASA.Contrib.Configuration.Tests/Config/SystemOptions.cs create mode 100644 test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs create mode 100644 test/MASA.Contrib.Configuration.Tests/MASA.Contrib.Configuration.Tests.csproj create mode 100644 test/MASA.Contrib.Configuration.Tests/_Imports.cs create mode 100644 test/MASA.Contrib.Configuration.Tests/appsettings.json create mode 100644 test/MASA.Contrib.Configuration.Tests/rabbitMq.json create mode 100644 test/MASA.Contrib.Configuration.Tests/redis.json create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/Courses.cs create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/_Imports.cs create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/Students.cs create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/_Imports.cs create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/Hobbies.cs create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/_Imports.cs create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/BaseRepositoryTest.cs create mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/CustomDbContext.cs delete mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Options/DispatcherOptions.cs delete mode 100644 test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/OrderDbContext.cs delete mode 100644 test/MASA.Contrib.DDD.Domain.Tests/EventHandlers/PaymentSucceededHandlers.cs create mode 100644 test/MASA.Contrib.DDD.Domain.Tests/Events/ForgetPasswordEvent.cs delete mode 100644 test/MASA.Contrib.DDD.Domain.Tests/Repositories/UserRepository.cs delete mode 100644 test/MASA.Contrib.DDD.Domain.Tests/TestBase.cs create mode 100644 test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Courses.cs create mode 100644 test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Students.cs create mode 100644 test/MASA.Contrib.Data.Contracts.EF.Test/Infrastructure/CustomDbContext.cs create mode 100644 test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj create mode 100644 test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs create mode 100644 test/MASA.Contrib.Data.Contracts.EF.Test/_Imports.cs delete mode 100644 test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/Events/ForgetPasswordEvent.cs delete mode 100644 test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/RegisterServicesBusTest.cs delete mode 100644 test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/TestBase.cs create mode 100644 test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/Commands/CreateProductionCommand.cs create mode 100644 test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/CqrsTest.cs create mode 100644 test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/CreateProductionCommandHandler.cs create mode 100644 test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/MASA.Contrib.ReadWriteSpliting.CQRS.Tests.csproj create mode 100644 test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/ProductionQueryHandler.cs create mode 100644 test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/Queries/ProductionItemQuery.cs create mode 100644 test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/_Imports.cs create mode 100644 test/MASA.Contrib.Service.MinimalAPIs.Tests/MASA.Contrib.Service.MinimalAPIs.Tests.csproj create mode 100644 test/MASA.Contrib.Service.MinimalAPIs.Tests/MinimalAPITest.cs create mode 100644 test/MASA.Contrib.Service.MinimalAPIs.Tests/Services/CustomService.cs create mode 100644 test/MASA.Contrib.Service.MinimalAPIs.Tests/_Imports.cs rename test/MASA.Contribs.DDD.Domain.Entities/{User.cs => Users.cs} (68%) diff --git a/MASA.Contrib.sln b/MASA.Contrib.sln index f172e676c..dce90e45e 100644 --- a/MASA.Contrib.sln +++ b/MASA.Contrib.sln @@ -94,6 +94,32 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.UoW.EF", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.UoW.EF.Tests", "test\MASA.Contrib.Data.UoW.EF.Tests\MASA.Contrib.Data.UoW.EF.Tests.csproj", "{1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.BasicAbility.Dcc", "src\BasicAbility\MASA.Contrib.BasicAbility.Dcc\MASA.Contrib.BasicAbility.Dcc.csproj", "{FDF1C618-4C68-485E-A881-4FFF04EDF6E8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration", "src\Configuration\MASA.Contrib.Configuration\MASA.Contrib.Configuration.csproj", "{C056C688-8FFC-42BC-B4EA-EF3808A8A12C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.EntityTests", "test\MASA.Contrib.DDD.Domain.Repository.EF.EntityTests\MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj", "{9CC40E07-C24B-4EC8-B05B-56CF986E0477}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests", "test\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj", "{313E60D8-23E3-419C-9EC7-7C625DFDC1A7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests", "test\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj", "{A2667784-9BA0-47AC-A327-C0C8F95B26D3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.ReadWriteSpliting.CQRS.Tests", "test\MASA.Contrib.ReadWriteSpliting.CQRS.Tests\MASA.Contrib.ReadWriteSpliting.CQRS.Tests.csproj", "{428CDAF3-957A-4017-82EA-70737F205546}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration.Tests", "test\MASA.Contrib.Configuration.Tests\MASA.Contrib.Configuration.Tests.csproj", "{DB93B639-899D-4B2C-AF8A-47B4BC6B3776}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.BasicAbility.Dcc.Tests", "test\MASA.Contrib.BasicAbility.Dcc.Tests\MASA.Contrib.BasicAbility.Dcc.Tests.csproj", "{85BCA106-4A6F-4BEE-A748-E61A24D12DBD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MASA.Contrib.Configuration", "MASA.Contrib.Configuration", "{9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration.ErrorSectionAutoMapTests", "test\MASA.Contrib.Configuration.ErrorSectionAutoMapTests\MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj", "{2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration.MountErrorSectionAutoMapTests", "test\MASA.Contrib.Configuration.MountErrorSectionAutoMapTests\MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj", "{17CD5E42-C589-47CA-8FF2-7B6D3B70131A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Service.MinimalAPIs.Tests", "test\MASA.Contrib.Service.MinimalAPIs.Tests\MASA.Contrib.Service.MinimalAPIs.Tests.csproj", "{A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.Contracts.EF.Test", "test\MASA.Contrib.Data.Contracts.EF.Test\MASA.Contrib.Data.Contracts.EF.Test.csproj", "{0843A857-87A3-4603-9659-160B2DCE36AC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -310,6 +336,102 @@ Global {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Release|Any CPU.Build.0 = Release|Any CPU {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Release|x64.ActiveCfg = Release|Any CPU {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}.Release|x64.Build.0 = Release|Any CPU + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8}.Debug|x64.ActiveCfg = Debug|Any CPU + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8}.Debug|x64.Build.0 = Debug|Any CPU + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8}.Release|Any CPU.Build.0 = Release|Any CPU + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8}.Release|x64.ActiveCfg = Release|Any CPU + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8}.Release|x64.Build.0 = Release|Any CPU + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Debug|x64.ActiveCfg = Debug|Any CPU + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Debug|x64.Build.0 = Debug|Any CPU + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Release|Any CPU.Build.0 = Release|Any CPU + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Release|x64.ActiveCfg = Release|Any CPU + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Release|x64.Build.0 = Release|Any CPU + {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Debug|x64.ActiveCfg = Debug|Any CPU + {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Debug|x64.Build.0 = Debug|Any CPU + {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Release|Any CPU.Build.0 = Release|Any CPU + {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Release|x64.ActiveCfg = Release|Any CPU + {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Release|x64.Build.0 = Release|Any CPU + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Debug|x64.ActiveCfg = Debug|Any CPU + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Debug|x64.Build.0 = Debug|Any CPU + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Release|Any CPU.Build.0 = Release|Any CPU + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Release|x64.ActiveCfg = Release|Any CPU + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Release|x64.Build.0 = Release|Any CPU + {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Debug|x64.ActiveCfg = Debug|Any CPU + {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Debug|x64.Build.0 = Debug|Any CPU + {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Release|Any CPU.Build.0 = Release|Any CPU + {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Release|x64.ActiveCfg = Release|Any CPU + {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Release|x64.Build.0 = Release|Any CPU + {428CDAF3-957A-4017-82EA-70737F205546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {428CDAF3-957A-4017-82EA-70737F205546}.Debug|Any CPU.Build.0 = Debug|Any CPU + {428CDAF3-957A-4017-82EA-70737F205546}.Debug|x64.ActiveCfg = Debug|Any CPU + {428CDAF3-957A-4017-82EA-70737F205546}.Debug|x64.Build.0 = Debug|Any CPU + {428CDAF3-957A-4017-82EA-70737F205546}.Release|Any CPU.ActiveCfg = Release|Any CPU + {428CDAF3-957A-4017-82EA-70737F205546}.Release|Any CPU.Build.0 = Release|Any CPU + {428CDAF3-957A-4017-82EA-70737F205546}.Release|x64.ActiveCfg = Release|Any CPU + {428CDAF3-957A-4017-82EA-70737F205546}.Release|x64.Build.0 = Release|Any CPU + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776}.Debug|x64.ActiveCfg = Debug|Any CPU + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776}.Debug|x64.Build.0 = Debug|Any CPU + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776}.Release|Any CPU.Build.0 = Release|Any CPU + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776}.Release|x64.ActiveCfg = Release|Any CPU + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776}.Release|x64.Build.0 = Release|Any CPU + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Debug|x64.ActiveCfg = Debug|Any CPU + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Debug|x64.Build.0 = Debug|Any CPU + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Release|Any CPU.Build.0 = Release|Any CPU + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Release|x64.ActiveCfg = Release|Any CPU + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Release|x64.Build.0 = Release|Any CPU + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Debug|x64.ActiveCfg = Debug|Any CPU + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Debug|x64.Build.0 = Debug|Any CPU + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Release|Any CPU.Build.0 = Release|Any CPU + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Release|x64.ActiveCfg = Release|Any CPU + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Release|x64.Build.0 = Release|Any CPU + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Debug|x64.ActiveCfg = Debug|Any CPU + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Debug|x64.Build.0 = Debug|Any CPU + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Release|Any CPU.Build.0 = Release|Any CPU + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Release|x64.ActiveCfg = Release|Any CPU + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Release|x64.Build.0 = Release|Any CPU + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Debug|x64.ActiveCfg = Debug|Any CPU + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Debug|x64.Build.0 = Debug|Any CPU + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Release|Any CPU.Build.0 = Release|Any CPU + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Release|x64.ActiveCfg = Release|Any CPU + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Release|x64.Build.0 = Release|Any CPU + {0843A857-87A3-4603-9659-160B2DCE36AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0843A857-87A3-4603-9659-160B2DCE36AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0843A857-87A3-4603-9659-160B2DCE36AC}.Debug|x64.ActiveCfg = Debug|Any CPU + {0843A857-87A3-4603-9659-160B2DCE36AC}.Debug|x64.Build.0 = Debug|Any CPU + {0843A857-87A3-4603-9659-160B2DCE36AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0843A857-87A3-4603-9659-160B2DCE36AC}.Release|Any CPU.Build.0 = Release|Any CPU + {0843A857-87A3-4603-9659-160B2DCE36AC}.Release|x64.ActiveCfg = Release|Any CPU + {0843A857-87A3-4603-9659-160B2DCE36AC}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -356,6 +478,19 @@ Global {7A1493EC-196F-4389-A966-02E526453578} = {880E8263-AECC-4793-BD28-7CD03650D124} {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F} = {E33ADF54-4D35-49B7-BDA6-412587CA39FF} {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {FDF1C618-4C68-485E-A881-4FFF04EDF6E8} = {5DFAF4A2-ECB5-46E4-904D-1EA5F48B2D48} + {C056C688-8FFC-42BC-B4EA-EF3808A8A12C} = {59DA3D5F-9E39-4173-8C31-126967CC189F} + {9CC40E07-C24B-4EC8-B05B-56CF986E0477} = {880E8263-AECC-4793-BD28-7CD03650D124} + {313E60D8-23E3-419C-9EC7-7C625DFDC1A7} = {880E8263-AECC-4793-BD28-7CD03650D124} + {A2667784-9BA0-47AC-A327-C0C8F95B26D3} = {880E8263-AECC-4793-BD28-7CD03650D124} + {428CDAF3-957A-4017-82EA-70737F205546} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {DB93B639-899D-4B2C-AF8A-47B4BC6B3776} = {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} + {85BCA106-4A6F-4BEE-A748-E61A24D12DBD} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1} = {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} + {17CD5E42-C589-47CA-8FF2-7B6D3B70131A} = {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} + {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {0843A857-87A3-4603-9659-160B2DCE36AC} = {38E6C400-90C0-493E-9266-C1602E229F1B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs new file mode 100644 index 000000000..4ae0fab47 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs @@ -0,0 +1,119 @@ +namespace MASA.Contrib.BasicAbility.Dcc; + +public class ConfigurationAPIClient : ConfigurationAPIBase, IConfigurationAPIClient +{ + private readonly IMemoryCacheClient _client; + private readonly JsonSerializerOptions _jsonSerializerOptions; + + private readonly ConcurrentDictionary>> _taskExpandoObjects = new(); + private readonly ConcurrentDictionary>> _taskJsonObjects = new(); + + public ConfigurationAPIClient( + IMemoryCacheClient client, + JsonSerializerOptions jsonSerializerOptions, + DccSectionOptions defaultSectionOption, + List? expandSectionOptions) + : base(defaultSectionOption, expandSectionOptions) + { + _client = client; + _jsonSerializerOptions = jsonSerializerOptions; + } + + public Task<(string Raw, ConfigurationTypes ConfigurationType)> GetRawAsync(string environment, string cluster, string appId, string configObject, Action valueChanged) + { + var key = FomartKey(environment, cluster, appId, configObject); + return GetRawByKeyAsync(key, valueChanged); + } + + public async Task GetAsync(string environment, string cluster, string appId, string configObject, Action valueChanged) + where T : class + { + var key = FomartKey(environment, cluster, appId, configObject); + + var value = await _taskJsonObjects.GetOrAdd(key, (k) => new Lazy>(async () => + { + var options = new JsonSerializerOptions(_jsonSerializerOptions); + options.EnableDynamicTypes(); + + var result = await GetRawByKeyAsync(k, (value) => + { + var result = JsonSerializer.Deserialize(value, options); + + var newValue = new Lazy>(() => Task.FromResult((object)result!)); + _taskJsonObjects.AddOrUpdate(k, newValue, (_, _) => newValue); + valueChanged?.Invoke(result!); + }); + + return JsonSerializer.Deserialize(result.Raw, options) ?? throw new ArgumentException(nameof(configObject)); + + })).Value; + + return (value as T)!; + } + + public async Task GetDynamicAsync(string environment, string cluster, string appId, string configObject, Action valueChanged) + { + var key = FomartKey(environment, cluster, appId, configObject); + + var value = _taskExpandoObjects.GetOrAdd(key, (k) => new Lazy>(async () => + { + var options = new JsonSerializerOptions(_jsonSerializerOptions); + options.EnableDynamicTypes(); + + var raw = await GetRawByKeyAsync(k, (value) => + { + var result = JsonSerializer.Deserialize(value, options); + var newValue = new Lazy>(() => Task.FromResult(result)!); + _taskExpandoObjects.AddOrUpdate(k, newValue!, (_, _) => newValue!); + valueChanged?.Invoke(result!); + }); + + return JsonSerializer.Deserialize(raw.Raw, options) ?? throw new ArgumentException(nameof(configObject)); + })).Value; + + return await value; + } + + private async Task<(string Raw, ConfigurationTypes ConfigurationType)> GetRawByKeyAsync(string key, Action valueChanged) + { + var raw = await _client.GetAsync(key, (value) => + { + var result = FormatRaw(value); + valueChanged?.Invoke(result.Raw); + }); + + return FormatRaw(raw); + } + + private (string Raw, ConfigurationTypes ConfigurationType) FormatRaw(string raw) + { + if (raw == null) + throw new ArgumentException("configObject invalid"); + + var result = JsonSerializer.Deserialize(raw, _jsonSerializerOptions); + if (result == null || result.ConfigFormat == 0) + throw new ArgumentException("configObject invalid"); + + switch (result.ConfigFormat) + { + case ConfigFormats.Json: + return (result.Content!, ConfigurationTypes.Json); + + case ConfigFormats.Text: + return (result.Content!, ConfigurationTypes.Text); + + case ConfigFormats.Properties: + var properties = PropertyConfigurationParser.Parse(result.Content!, _jsonSerializerOptions); + if (properties == null) + throw new ArgumentException("configObject invalid"); + + return (JsonSerializer.Serialize(properties, _jsonSerializerOptions), ConfigurationTypes.Properties); + + default: + throw new NotSupportedException("Unsupported configuration type"); + } + } + + private string FomartKey(string environment, string cluster, string appId, string configObject) + => $"{GetEnvironment(environment)}-{GetCluster(cluster)}-{GetAppid(appId)}-{GetConfigObject(configObject)}".ToLower(); +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIManage.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIManage.cs new file mode 100644 index 000000000..406a03583 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIManage.cs @@ -0,0 +1,28 @@ +namespace MASA.Contrib.BasicAbility.Dcc; + +public class ConfigurationAPIManage : ConfigurationAPIBase, IConfigurationAPIManage +{ + private readonly ICallerProvider _callerProvider; + + public ConfigurationAPIManage( + ICallerProvider callerProvider, + DccSectionOptions defaultSectionOption, + List? expandSectionOptions) + : base(defaultSectionOption, expandSectionOptions) + { + _callerProvider = callerProvider; + } + + public async Task UpdateAsync(string environment, string cluster, string appId, string configObject, object value) + { + var requestUri = $"open-api/releasing/{GetEnvironment(environment)}/{GetCluster(cluster)}/{GetAppid(appId)}/{GetConfigObject(configObject)}?secret={GetSecret(appId)}"; + var result = await _callerProvider.PutAsync(requestUri, value, default); + + // 299 is the status code when throwing a UserFriendlyException in masa.framework + if ((int)result.StatusCode == 299 || !result.IsSuccessStatusCode) + { + var error = await result.Content.ReadAsStringAsync(); + throw new HttpRequestException(error); + } + } +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigFormats.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigFormats.cs new file mode 100644 index 000000000..fbd4b6c6e --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigFormats.cs @@ -0,0 +1,8 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Internal; + +internal enum ConfigFormats +{ + Properties = 1, + Text, + Json +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigurationAPIBase.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigurationAPIBase.cs new file mode 100644 index 000000000..19ccc2214 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigurationAPIBase.cs @@ -0,0 +1,37 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Internal; + +public class ConfigurationAPIBase +{ + private readonly DccSectionOptions _defaultSectionOption; + private readonly List _expandSectionOptions; + + protected ConfigurationAPIBase(DccSectionOptions defaultSectionOption, List? expandSectionOptions) + { + _defaultSectionOption = defaultSectionOption; + _expandSectionOptions = expandSectionOptions ?? new(); + } + + protected string GetSecret(string appId) + { + if (_defaultSectionOption.AppId == appId) + return _defaultSectionOption.Secret ?? ""; + + var option = _expandSectionOptions.FirstOrDefault(x => x.AppId == appId); + if (option == null) + throw new ArgumentNullException(nameof(appId)); + + return option.Secret ?? ""; + } + + protected string GetEnvironment(string environment) + => !string.IsNullOrEmpty(environment) ? environment : _defaultSectionOption.Environment!; + + protected string GetCluster(string cluster) + => !string.IsNullOrEmpty(cluster) ? cluster : _defaultSectionOption.Cluster!; + + protected string GetAppid(string appId) + => !string.IsNullOrEmpty(appId) ? appId : _defaultSectionOption.AppId!; + + protected string GetConfigObject(string configObject) + => !string.IsNullOrEmpty(configObject) ? configObject : throw new ArgumentNullException(nameof(configObject)); +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Constants.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Constants.cs new file mode 100644 index 000000000..d352c723b --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Constants.cs @@ -0,0 +1,12 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Internal; + +internal class Constants +{ + internal const string DEFAULT_CLIENT_NAME = "masa.plugins.caching.dcc"; + + internal const string DEFAULT_SUBSCRIBE_KEY_PREFIX = "masa.dcc:"; + + internal const string DEFAULT_ENVIRONMENT_NAME = "ASPNETCORE_ENVIRONMENT"; + + internal const string DATA_DICTIONARY_SECTION_NAME = "DataDictionary"; +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccConfigurationRepository.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccConfigurationRepository.cs new file mode 100644 index 000000000..84cc092ca --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccConfigurationRepository.cs @@ -0,0 +1,92 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Internal; + +internal class DccConfigurationRepository : AbstractConfigurationRepository +{ + private readonly IConfigurationAPIClient _client; + + public override SectionTypes SectionType { get; init; } = SectionTypes.ConfigurationAPI; + + private readonly ConcurrentDictionary> _dictionaries = new(); + + private readonly ConcurrentDictionary _configObjectConfigurationTypeRelations = new(); + + public DccConfigurationRepository( + IEnumerable sectionOptions, + IConfigurationAPIClient client, + ILoggerFactory loggerFactory) + : base(loggerFactory) + { + _client = client; + foreach (var sectionOption in sectionOptions) + { + Initialize(sectionOption).ConfigureAwait(false).GetAwaiter().GetResult(); + } + } + + private async Task Initialize(DccSectionOptions sectionOption) + { + foreach (var configObject in sectionOption.ConfigObjects) + { + string key = $"{sectionOption.Environment!}-{sectionOption.Cluster!}-{sectionOption.AppId}-{configObject}".ToLower(); + var result = await _client.GetRawAsync(sectionOption.Environment!, sectionOption.Cluster!, sectionOption.AppId, configObject, (val) => + { + if (_configObjectConfigurationTypeRelations.TryGetValue(key, out var configurationType)) + { + _dictionaries[key] = FormatRaw(sectionOption.AppId, configObject, val, configurationType); + FireRepositoryChange(SectionType, Load()); + } + }); + + _configObjectConfigurationTypeRelations.TryAdd(key, result.ConfigurationType); + _dictionaries[key] = FormatRaw(sectionOption.AppId, configObject, result.Raw, result.ConfigurationType); + } + } + + private IDictionary FormatRaw(string appId, string configObject, string? raw, ConfigurationTypes configurationType) + { + if (raw == null) + return new Dictionary(); + + switch (configurationType) + { + case ConfigurationTypes.Json: + return SecondaryFormat(appId, configObject, JsonConfigurationParser.Parse(raw)); + case ConfigurationTypes.Properties: + return SecondaryFormat(appId, configObject, JsonSerializer.Deserialize>(raw)!); + case ConfigurationTypes.Text: + return new Dictionary() + { + { $"{appId}{ConfigurationPath.KeyDelimiter}{DATA_DICTIONARY_SECTION_NAME}{ConfigurationPath.KeyDelimiter}{configObject}" , raw ?? "" } + }; + default: + throw new NotSupportedException(nameof(configurationType)); + } + } + + private IDictionary SecondaryFormat( + string appId, + string configObject, + IDictionary data) + { + var dictionary = new Dictionary(); + foreach (var item in data) + { + dictionary[$"{appId}{ConfigurationPath.KeyDelimiter}{configObject}{ConfigurationPath.KeyDelimiter}{item.Key}"] = item.Value; + } + return dictionary; + } + + public override Properties Load() + { + Dictionary properties = new(); + foreach (var item in _dictionaries) + { + foreach (var key in item.Value.Keys) + { + properties[key] = item.Value[key] ?? string.Empty; + } + } + return new Properties(properties); + } + +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccFactory.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccFactory.cs new file mode 100644 index 000000000..ac199e966 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccFactory.cs @@ -0,0 +1,21 @@ +using MASA.Utils.Caller.Core; + +namespace MASA.Contrib.BasicAbility.Dcc.Internal; + +internal class DccFactory +{ + public static IConfigurationAPIClient CreateClient( + IMemoryCacheClient client, + JsonSerializerOptions jsonSerializerOptions, + DccSectionOptions defaultSectionOption, + List? expandSectionOptions) + { + return new ConfigurationAPIClient(client, jsonSerializerOptions, defaultSectionOption, expandSectionOptions); + } + + public static IConfigurationAPIManage CreateManage( + ICallerFactory callerFactory, + DccSectionOptions defaultSectionOption, + List? expandSectionOptions) + => new ConfigurationAPIManage(callerFactory.CreateClient(), defaultSectionOption, expandSectionOptions); +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Model/Property.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Model/Property.cs new file mode 100644 index 000000000..760b9cc23 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Model/Property.cs @@ -0,0 +1,8 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Internal.Model; + +internal class Property +{ + public string Key { get; set; } = default!; + + public string Value { get; set; } = default!; +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Model/PublishRelease.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Model/PublishRelease.cs new file mode 100644 index 000000000..b94b53372 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Model/PublishRelease.cs @@ -0,0 +1,8 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Internal.Model; + +internal class PublishRelease +{ + public ConfigFormats ConfigFormat { get; set; } + + public string? Content { get; set; } +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/JsonConfigurationParser.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/JsonConfigurationParser.cs new file mode 100644 index 000000000..e3d2f7295 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/JsonConfigurationParser.cs @@ -0,0 +1,101 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Internal.Parser; + +/// +/// https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationFileParser.cs +/// +internal sealed class JsonConfigurationParser +{ + private JsonConfigurationParser() + { + } + + private readonly Dictionary _data = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Stack _paths = new Stack(); + + public static IDictionary Parse(string json) + => new JsonConfigurationParser().ParseJson(json); + + private IDictionary ParseJson(string json) + { + var jsonDocumentOptions = new JsonDocumentOptions + { + CommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true, + }; + + var doc = JsonDocument.Parse(json, jsonDocumentOptions); + + if (doc.RootElement.ValueKind != JsonValueKind.Object) + { + throw new FormatException($"[{doc.RootElement.ValueKind}]Invalid top level JsonElement."); + } + + VisitElement(doc.RootElement); + + return _data; + } + + private void VisitElement(JsonElement element) + { + var isEmpty = true; + + foreach (JsonProperty property in element.EnumerateObject()) + { + isEmpty = false; + EnterContext(property.Name); + VisitValue(property.Value); + ExitContext(); + } + + if (isEmpty && _paths.Count > 0) + { + _data[_paths.Peek()] = null; + } + } + + private void VisitValue(JsonElement value) + { + Debug.Assert(_paths.Count > 0); + + switch (value.ValueKind) + { + case JsonValueKind.Object: + VisitElement(value); + break; + + case JsonValueKind.Array: + int index = 0; + foreach (JsonElement arrayElement in value.EnumerateArray()) + { + EnterContext(index.ToString()); + VisitValue(arrayElement); + ExitContext(); + index++; + } + + break; + + case JsonValueKind.Number: + case JsonValueKind.String: + case JsonValueKind.True: + case JsonValueKind.False: + case JsonValueKind.Null: + string key = _paths.Peek(); + if (_data.ContainsKey(key)) + { + throw new FormatException($"[{key}]key is duplicated."); + } + + _data[key] = value.ToString(); + break; + + default: + throw new FormatException($"[{value.ValueKind}]Unsupported json token."); + } + } + + private void EnterContext(string context) => + _paths.Push(_paths.Count > 0 ? _paths.Peek() + ConfigurationPath.KeyDelimiter + context : context); + + private void ExitContext() => _paths.Pop(); +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/PropertyConfigurationParser.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/PropertyConfigurationParser.cs new file mode 100644 index 000000000..fb05155cd --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/PropertyConfigurationParser.cs @@ -0,0 +1,7 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Internal.Parser; + +internal class PropertyConfigurationParser +{ + public static IDictionary? Parse(string raw, JsonSerializerOptions serializerOption) + => JsonSerializer.Deserialize>(raw, serializerOption)?.ToDictionary(k => k.Key, v => v.Value); +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj new file mode 100644 index 000000000..e93f58247 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj @@ -0,0 +1,20 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + + diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs new file mode 100644 index 000000000..9840f628d --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs @@ -0,0 +1,195 @@ +namespace MASA.Contrib.BasicAbility.Dcc; + +public static class MasaConfigurationExtensions +{ + public static IMasaConfigurationBuilder UseDCC( + this IMasaConfigurationBuilder builder, + IServiceCollection services, + Action? jsonSerializerOptions = null, + Action? callerOptions = null) + => builder.UseDCC(services, "Appsettings", jsonSerializerOptions, callerOptions); + + public static IMasaConfigurationBuilder UseDCC( + this IMasaConfigurationBuilder builder, + IServiceCollection services, + string defaultSectionName, + Action? jsonSerializerOptions = null, + Action? callerOptions = null) + { + if (!builder.GetSectionRelations().TryGetValue(defaultSectionName, out IConfiguration? configuration)) + throw new ArgumentNullException("Failed to obtain Dcc configuration, check whether the current section is configured with Dcc"); + + var configurationSection = configuration.GetSection("DccOptions"); + var dccOptions = configurationSection.Get(); + + List expandSections = new(); + var configurationExpandSection = configuration.GetSection("ExpandSections"); + if (configurationExpandSection.Exists()) + { + configurationExpandSection.Bind(expandSections); + } + + return builder.UseDCC(services, () => dccOptions, option => + { + option.Environment = configuration["Environment"]; + option.Cluster = configuration["Cluster"]; + option.AppId = configuration["AppId"]; + option.ConfigObjects = configuration.GetSection("ConfigObjects").Get>(); + option.Secret = configuration["Sectet"]; + }, option => option.ExpandSections = expandSections, jsonSerializerOptions, callerOptions); + } + + public static IMasaConfigurationBuilder UseDCC( + this IMasaConfigurationBuilder builder, + IServiceCollection services, + Func configureOptions, + Action defaultSectionOptions, + Action? expansionSectionOptions = null, + Action? jsonSerializerOptions = null, + Action? callerOptions = null) + { + if (services.Any(service => service.ImplementationType == typeof(DccConfigurationProvider))) + return builder; + + services.AddSingleton(); + + var config = GetDccConfigurationOption(configureOptions, defaultSectionOptions, expansionSectionOptions); + + var jsonSerializerOption = new JsonSerializerOptions() + { + PropertyNameCaseInsensitive = true + }; + jsonSerializerOptions?.Invoke(jsonSerializerOption); + services.AddCaller(Options => + { + if (callerOptions == null) + { + Options.UseHttpClient(() + => new MasaHttpClientBuilder(DEFAULT_CLIENT_NAME, string.Empty, opt => opt.BaseAddress = new Uri(config.DccConfigurationOption.DccServiceAddress), jsonSerializerOption) + ); + } + else + { + callerOptions.Invoke(Options); + } + }); + + services.AddMasaRedisCache(DEFAULT_CLIENT_NAME, config.DccConfigurationOption).AddSharedMasaMemoryCache(config.DccConfigurationOption.SubscribeKeyPrefix ?? DEFAULT_SUBSCRIBE_KEY_PREFIX); + + TryAddConfigurationAPIClient(services, config.DefaultSectionOption, config.ExpansionSectionOptions, jsonSerializerOption); + TryAddConfigurationAPIManage(services, config.DefaultSectionOption, config.ExpansionSectionOptions); + + var sectionOptions = new List() + { + config.DefaultSectionOption + }.Concat(config.ExpansionSectionOptions); + + var configurationAPIClient = services.BuildServiceProvider().GetRequiredService(); + var loggerFactory = services.BuildServiceProvider().GetRequiredService(); + builder.AddRepository(new DccConfigurationRepository(sectionOptions, configurationAPIClient, loggerFactory)); + return builder; + } + + public static IServiceCollection TryAddConfigurationAPIClient(IServiceCollection services, + DccSectionOptions defaultSectionOption, + List expansionSectionOptions, + JsonSerializerOptions jsonSerializerOption) + { + services.TryAddSingleton(serviceProvider => + { + var client = serviceProvider.GetRequiredService() + .CreateClient(DEFAULT_CLIENT_NAME); + + if (client == null) + throw new ArgumentNullException(nameof(client)); + + return DccFactory.CreateClient(client, jsonSerializerOption, defaultSectionOption, expansionSectionOptions); + }); + return services; + } + + public static IServiceCollection TryAddConfigurationAPIManage(IServiceCollection services, + DccSectionOptions defaultSectionOption, + List expansionSectionOptions) + { + services.TryAddSingleton(serviceProvider => + { + var callerFactory = serviceProvider.GetRequiredService(); + return DccFactory.CreateManage(callerFactory, defaultSectionOption, expansionSectionOptions); + }); + return services; + } + + private static (DccSectionOptions DefaultSectionOption, List ExpansionSectionOptions, DccConfigurationOptions DccConfigurationOption) GetDccConfigurationOption( + Func configureOptions, + Action defaultSectionOptions, + Action? expansionSectionOptions = null) + { + var dccConfigurationOption = configureOptions?.Invoke() ?? null; + if (dccConfigurationOption == null) + throw new ArgumentNullException(nameof(configureOptions)); + + if (string.IsNullOrEmpty(dccConfigurationOption.DccServiceAddress)) + throw new ArgumentNullException(nameof(dccConfigurationOption.DccServiceAddress)); + + if (dccConfigurationOption.Servers == null || dccConfigurationOption.Servers.Count == 0 || dccConfigurationOption.Servers.Any(service => string.IsNullOrEmpty(service.Host) || service.Port <= 0)) + throw new ArgumentNullException(nameof(dccConfigurationOption.Servers)); + + if (defaultSectionOptions == null) + throw new ArgumentNullException(nameof(defaultSectionOptions)); + + var defaultSectionOption = new DccSectionOptions(); + defaultSectionOptions.Invoke(defaultSectionOption); + + if (string.IsNullOrEmpty(defaultSectionOption.AppId)) + throw new ArgumentNullException("AppId cannot be empty"); + + if (defaultSectionOption.ConfigObjects == null || !defaultSectionOption.ConfigObjects.Any()) + throw new ArgumentNullException("ConfigObjects cannot be empty"); + + if (string.IsNullOrEmpty(defaultSectionOption.Cluster)) + defaultSectionOption.Cluster = "Default"; + if (string.IsNullOrEmpty(defaultSectionOption.Environment)) + defaultSectionOption.Environment = GetDefaultEnvironment(); + + var dccCachingOption = new DccExpandSectionOptions(); + expansionSectionOptions?.Invoke(dccCachingOption); + List expansionOptions = new(); + foreach (var expansionOption in dccCachingOption.ExpandSections ?? new()) + { + if (string.IsNullOrEmpty(expansionOption.Environment)) + expansionOption.Environment = defaultSectionOption.Environment; + if (string.IsNullOrEmpty(expansionOption.Cluster)) + expansionOption.Cluster = defaultSectionOption.Cluster; + + if (expansionOption.ConfigObjects == null || !expansionOption.ConfigObjects.Any()) + throw new ArgumentNullException("ConfigObjects in the extension section cannot be empty"); + + if (expansionOption.AppId == defaultSectionOption.AppId || expansionOptions.Any(section => section.AppId == expansionOption.AppId)) + throw new ArgumentNullException("The current section already exists, no need to mount repeatedly"); + + expansionOptions.Add(expansionOption); + } + return (defaultSectionOption, expansionOptions, dccConfigurationOption); + } + + private static ICachingBuilder AddSharedMasaMemoryCache(this ICachingBuilder builder, string subscribeKeyPrefix) + { + builder.AddMasaMemoryCache(options => + { + options.SubscribeKeyType = SubscribeKeyTypes.SpecificPrefix; + options.SubscribeKeyPrefix = subscribeKeyPrefix; + }); + + return builder; + } + + private static string GetDefaultEnvironment() + => System.Environment.GetEnvironmentVariable(DEFAULT_ENVIRONMENT_NAME) ?? + throw new ArgumentNullException("Error getting environment information, please make sure the value of ASPNETCORE_ENVIRONMENT has been configured"); + + private class DccConfigurationProvider + { + + } +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccConfigurationOptions.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccConfigurationOptions.cs new file mode 100644 index 000000000..2ecfb9da2 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccConfigurationOptions.cs @@ -0,0 +1,11 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Options; + +public class DccConfigurationOptions : RedisConfigurationOptions +{ + public string DccServiceAddress { get; set; } = default!; + + /// + /// The prefix of Dcc PubSub, it is not recommended to modify + /// + public string? SubscribeKeyPrefix { get; set; } +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccExpandSectionOptions.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccExpandSectionOptions.cs new file mode 100644 index 000000000..e9629637c --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccExpandSectionOptions.cs @@ -0,0 +1,9 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Options; + +public class DccExpandSectionOptions +{ + /// + /// Expansion section information + /// + public List? ExpandSections { get; set; } +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccSectionOptions.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccSectionOptions.cs new file mode 100644 index 000000000..fc905907e --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccSectionOptions.cs @@ -0,0 +1,24 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Options; + +public class DccSectionOptions +{ + /// + /// The environment name. + /// Get from the environment variable ASPNETCORE_ENVIRONMENT when Environment is null or empty + /// + public string? Environment { get; set; } = null; + + /// + /// The cluster name. + /// + public string? Cluster { get; set; } + + /// + /// The app id. + /// + public string AppId { get; set; } = default!; + + public List ConfigObjects { get; set; } = default!; + + public string? Secret { get; set; } +} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/_Imports.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/_Imports.cs new file mode 100644 index 000000000..b31c76679 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/_Imports.cs @@ -0,0 +1,23 @@ +global using MASA.BuildingBlocks.Configuration; +global using MASA.Contrib.BasicAbility.Dcc.Internal; +global using MASA.Contrib.BasicAbility.Dcc.Internal.Model; +global using MASA.Contrib.BasicAbility.Dcc.Internal.Parser; +global using MASA.Contrib.BasicAbility.Dcc.Options; +global using MASA.Utils.Caching.Core.DependencyInjection; +global using MASA.Utils.Caching.Core.Models; +global using MASA.Utils.Caching.DistributedMemory.DependencyInjection; +global using MASA.Utils.Caching.DistributedMemory.Interfaces; +global using MASA.Utils.Caching.Redis.DependencyInjection; +global using MASA.Utils.Caching.Redis.Extensions; +global using MASA.Utils.Caching.Redis.Models; +global using MASA.Utils.Caller.Core; +global using MASA.Utils.Caller.HttpClient; +global using Microsoft.Extensions.Configuration; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.DependencyInjection.Extensions; +global using Microsoft.Extensions.Logging; +global using System.Collections.Concurrent; +global using System.Diagnostics; +global using System.Dynamic; +global using System.Text.Json; +global using static MASA.Contrib.BasicAbility.Dcc.Internal.Constants; diff --git a/src/Configuration/MASA.Contrib.Configuration/LocalMasaConfigurationRepository.cs b/src/Configuration/MASA.Contrib.Configuration/LocalMasaConfigurationRepository.cs new file mode 100644 index 000000000..667d5bfc1 --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/LocalMasaConfigurationRepository.cs @@ -0,0 +1,71 @@ +namespace MASA.Contrib.Configuration; + +internal class LocalMasaConfigurationRepository : AbstractConfigurationRepository +{ + public override SectionTypes SectionType { get; init; } + + private ConcurrentDictionary _data = new(); + + public LocalMasaConfigurationRepository( + Dictionary sectionRelation, + ILoggerFactory loggerFactory) + : base(loggerFactory) + { + this.SectionType = SectionTypes.Local; + foreach (var section in sectionRelation) + { + Initialize(section.Key, section.Value); + + ChangeToken.OnChange(() => section.Value.GetReloadToken(), () => + { + Initialize(section.Key, section.Value); + base.FireRepositoryChange(SectionType, Load()); + }); + } + } + + private void Initialize(string rootSectionName, IConfiguration configuration) + { + Dictionary data = new(); + GetData(rootSectionName, configuration, configuration.GetChildren(), ref data); + var properties = new Properties(data); + _data[rootSectionName] = properties; + } + + private void GetData(string rootSectionName, IConfiguration configuration, IEnumerable configurationSections, ref Dictionary dictionary) + { + foreach (var configurationSection in configurationSections) + { + var section = configuration.GetSection(configurationSection.Path); + + var childrenSections = section.GetChildren(); + + if (!section.Exists() || !childrenSections.Any()) + { + var key = string.IsNullOrEmpty(rootSectionName) ? section.Path : $"{rootSectionName}{ConfigurationPath.KeyDelimiter}{section.Path}"; + if (!dictionary.ContainsKey(key)) + { + dictionary.Add(key, configuration[section.Path]); + } + } + else + { + GetData(rootSectionName, configuration, childrenSections, ref dictionary); + } + } + } + + public override Properties Load() + { + Dictionary localProperties = new(); + foreach (var item in _data) + { + foreach (var key in item.Value.GetPropertyNames()) + { + localProperties[key] = item.Value.GetProperty(key) ?? string.Empty; + } + } + return new Properties(localProperties); + } +} + diff --git a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj new file mode 100644 index 000000000..4cb44403d --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + diff --git a/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationBuilder.cs b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationBuilder.cs new file mode 100644 index 000000000..fd8294c4a --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationBuilder.cs @@ -0,0 +1,52 @@ +namespace MASA.Contrib.Configuration; + +public class MasaConfigurationBuilder : IMasaConfigurationBuilder +{ + private readonly IConfigurationBuilder _builder; + + public IDictionary Properties => _builder.Properties; + + public IList Sources => _builder.Sources; + + public Dictionary GetSectionRelations() => SectionRelations; + + internal Dictionary SectionRelations { get; } = new(); + + internal List Repositories { get; } = new(); + + internal List Relations { get; } = new(); + + public MasaConfigurationBuilder(IConfigurationBuilder builder) + => _builder = builder; + + /// + /// + /// + /// + /// If section is null, it is mounted to the Local section + public void AddSection(IConfigurationBuilder configurationBuilder, string? sectionName = null) + { + if (configurationBuilder == null) + throw new ArgumentNullException(nameof(configurationBuilder)); + + if (configurationBuilder.Sources.Count == 0) + throw new ArgumentException("Source cannot be empty"); + + sectionName = sectionName ?? ""; + + if (SectionRelations.ContainsKey(sectionName)) + throw new ArgumentException("Section already exists", nameof(sectionName)); + + SectionRelations.Add(sectionName, configurationBuilder.Build()); + } + + public void AddRepository(IConfigurationRepository configurationRepository) + => Repositories.Add(configurationRepository); + + public void AddRelations(params ConfigurationRelationOptions[] relationOptions) + => Relations.AddRange(relationOptions); + + public IConfigurationBuilder Add(IConfigurationSource source) => _builder.Add(source); + + public IConfigurationRoot Build() => _builder.Build(); +} diff --git a/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationExtensions.cs b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationExtensions.cs new file mode 100644 index 000000000..09552cf5c --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationExtensions.cs @@ -0,0 +1,35 @@ +namespace MASA.Contrib.Configuration; + +public static class MasaConfigurationExtensions +{ + public static void UseMasaOptions(this IMasaConfigurationBuilder builder, Action options) + { + var relation = new MasaRelationOptions(); + options.Invoke(relation); + builder.AddRelations(relation.Relations.ToArray()); + } + + internal static void AutoMapping(this MasaConfigurationBuilder builder, params Assembly[] assemblies) + { + var optionTypes = assemblies + .SelectMany(assembly => assembly.GetTypes()) + .Where(type => type != typeof(IMasaConfigurationOptions) && type != typeof(MasaConfigurationOptions) && typeof(IMasaConfigurationOptions).IsAssignableFrom(type)) + .ToList(); + optionTypes.ForEach(optionType => + { + var option = (IMasaConfigurationOptions)Activator.CreateInstance(optionType)!; + var sectionName = option.Section ?? optionType.Name; + if (builder.Relations.Any(relation => relation.SectionType == option.SectionType && relation.Section == sectionName)) + { + throw new ArgumentException("The section has been loaded, no need to load repeatedly, check whether there are duplicate sections or inheritance between auto-mapping classes"); + } + builder.AddRelations(new ConfigurationRelationOptions() + { + SectionType = option.SectionType, + ParentSection = option.ParentSection, + Section = sectionName, + ObjectType = optionType + }); + }); + } +} diff --git a/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationOptions.cs b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationOptions.cs new file mode 100644 index 000000000..09e2fa6a7 --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationOptions.cs @@ -0,0 +1,19 @@ +namespace MASA.Contrib.Configuration; + +public abstract class MasaConfigurationOptions : IMasaConfigurationOptions +{ + /// + /// The name of the parent section, if it is empty, it will be mounted under SectionType, otherwise it will be mounted to the specified section under SectionType + /// + [JsonIgnore] + public virtual string? ParentSection { get; init; } = null; + + /// + /// The section null means same as the class name, else load from the specify section + /// + [JsonIgnore] + public virtual string? Section { get; init; } = null; + + [JsonIgnore] + public abstract SectionTypes SectionType { get; init; } +} diff --git a/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationProvider.cs b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationProvider.cs new file mode 100644 index 000000000..f4ba2b5cb --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationProvider.cs @@ -0,0 +1,64 @@ +namespace MASA.Contrib.Configuration; + +public class MasaConfigurationProvider : ConfigurationProvider, IRepositoryChangeListener, IDisposable +{ + private readonly ConcurrentDictionary _data; + private readonly IEnumerable _configurationRepositories; + + public MasaConfigurationProvider(MasaConfigurationSource source) + { + _data = new(); + _configurationRepositories = source.Builder.Repositories; + + foreach (var configurationRepository in _configurationRepositories) + { + configurationRepository.AddChangeListener(this); + } + } + + public override void Load() + { + foreach (var configurationRepository in _configurationRepositories) + { + var properties = configurationRepository.Load(); + _data[configurationRepository.SectionType] = properties; + } + SetData(); + } + + public void OnRepositoryChange(SectionTypes sectionType, Properties newProperties) + { + if (_data[sectionType] == newProperties) + return; + + _data[sectionType] = newProperties; + + SetData(); + + OnReload(); + } + + void SetData() + { + Dictionary data = new(); + + foreach (var configurationType in _data.Keys) + { + var properties = _data[configurationType]; + foreach (var key in properties.GetPropertyNames()) + { + data[$"{configurationType}{ConfigurationPath.KeyDelimiter}{key}"] = properties.GetProperty(key)!; + } + } + + Data = data; + } + + public void Dispose() + { + foreach (var configurationRepository in _configurationRepositories) + { + configurationRepository.RemoveChangeListener(this); + } + } +} diff --git a/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationSource.cs b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationSource.cs new file mode 100644 index 000000000..7f57cf17e --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/MasaConfigurationSource.cs @@ -0,0 +1,17 @@ +namespace MASA.Contrib.Configuration; + +public class MasaConfigurationSource : IConfigurationSource +{ + internal MasaConfigurationBuilder Builder; + + public MasaConfigurationSource(MasaConfigurationBuilder builder) + { + Builder = builder; + } + + public IConfigurationProvider Build(IConfigurationBuilder builder) + { + return new MasaConfigurationProvider(this); + } +} + diff --git a/src/Configuration/MASA.Contrib.Configuration/MasaRelationOptions.cs b/src/Configuration/MASA.Contrib.Configuration/MasaRelationOptions.cs new file mode 100644 index 000000000..b521c4efa --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/MasaRelationOptions.cs @@ -0,0 +1,33 @@ +namespace MASA.Contrib.Configuration; + +public class MasaRelationOptions +{ + internal List Relations { get; } = new(); + + /// + /// Map Section relationship + /// + /// + /// + /// parent section, local section is the name of the locally configured section, and ConfigurationAPI is the name of the Appid where the configuration is located + /// The default is null, which is consistent with the mapping class name + /// + /// + public MasaRelationOptions Mapping(SectionTypes sectionType, string parentSection, string? section = null) + { + if (section == null) + section = typeof(TModel).Name; + + if (Relations.Any(relation => relation.SectionType == sectionType && relation.Section == section)) + throw new ArgumentOutOfRangeException(nameof(section), "The current section already has a configuration"); + + Relations.Add(new ConfigurationRelationOptions() + { + SectionType = sectionType, + ParentSection = parentSection, + Section = section, + ObjectType = typeof(TModel) + }); + return this; + } +} diff --git a/src/Configuration/MASA.Contrib.Configuration/ServiceCollectionExtensions.cs b/src/Configuration/MASA.Contrib.Configuration/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..8930bda1e --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/ServiceCollectionExtensions.cs @@ -0,0 +1,120 @@ +namespace MASA.Contrib.Configuration; + +public static class ServiceCollectionExtensions +{ + public static WebApplicationBuilder AddMasaConfiguration( + this WebApplicationBuilder builder, + Action? configureDelegate = null) + => builder.AddMasaConfiguration(configureDelegate, + AppDomain.CurrentDomain.GetAssemblies()); + + public static WebApplicationBuilder AddMasaConfiguration( + this WebApplicationBuilder builder, + Action? configureDelegate, + params Assembly[] assemblies) + { + // TODO Currently builder.Configuration does not support updating after refresh, wait for the problem to be fixed before processing + // https://github.com/dotnet/core/blob/main/release-notes/6.0/known-issues.md#configuration-not-reloaded-on-changes + var masaConfiguration = builder.Services.CreateMasaConfiguration(configureDelegate, assemblies: assemblies); + if (!masaConfiguration.Providers.Any()) + return builder; + + Microsoft.Extensions.Hosting.HostingHostBuilderExtensions.ConfigureAppConfiguration(builder.Host, configBuilder => + { + configBuilder.Sources.Clear(); + }); + builder.Configuration.AddConfiguration(masaConfiguration); + + return builder; + } + + public static IConfigurationRoot CreateMasaConfiguration( + this IServiceCollection services, + Action? configureDelegate, + IConfigurationBuilder? configurationBuilder = null, + string defaultSectionName = "Appsettings", + params Assembly[] assemblies) + { + if (services.Any(service => service.ImplementationType == typeof(MasaConfigurationProvider))) + return new ConfigurationBuilder().Build(); + + services.AddSingleton(); + + if (!services.Any(service => service.ImplementationType == typeof(ILoggerFactory))) + services.AddLogging(); + + MasaConfigurationBuilder masaConfigurationBuilder = new MasaConfigurationBuilder(new ConfigurationBuilder()); + if (configurationBuilder != null) + { + masaConfigurationBuilder.AddSection(configurationBuilder, defaultSectionName); + } + configureDelegate?.Invoke(masaConfigurationBuilder); + + if (masaConfigurationBuilder.SectionRelations.Count == 0) + throw new Exception("Please add the section to be loaded"); + + var localConfigurationRepository = new LocalMasaConfigurationRepository(masaConfigurationBuilder.SectionRelations, services.BuildServiceProvider().GetRequiredService()); + masaConfigurationBuilder.AddRepository(localConfigurationRepository); + + var source = new MasaConfigurationSource(masaConfigurationBuilder); + var configuration = masaConfigurationBuilder.Add(source).Build(); + + masaConfigurationBuilder.AutoMapping(assemblies); + masaConfigurationBuilder.Relations.ForEach(relation => + { + List sectionNames = new List() + { + relation.SectionType.ToString(), + }; + if (!string.IsNullOrEmpty(relation.ParentSection)) + sectionNames.Add(relation.ParentSection); + + if (relation.Section != "") + { + sectionNames.AddRange(relation.Section.Split(ConfigurationPath.KeyDelimiter)); + } + + services.ConfigureOption(configuration, sectionNames, relation.ObjectType); + }); + + return configuration; + } + + internal static void ConfigureOption( + this IServiceCollection services, + IConfiguration configuration, + List sectionNames, Type optionType) + { + IConfigurationSection? configurationSection = null; + foreach (var sectionName in sectionNames) + { + if (configurationSection == null) + configurationSection = configuration.GetSection(sectionName); + else + configurationSection = configurationSection.GetSection(sectionName); + } + if (!configurationSection.Exists()) + { + throw new ArgumentNullException("Section", "Check if the mapping section is correct"); + } + + var configurationChangeTokenSource = + Activator.CreateInstance(typeof(ConfigurationChangeTokenSource<>).MakeGenericType(optionType), string.Empty, + configurationSection)!; + services.TryAdd(new ServiceDescriptor(typeof(IOptionsChangeTokenSource<>).MakeGenericType(optionType), + configurationChangeTokenSource)); + + Action configureBinder = _ => { }; + var configureOptions = + Activator.CreateInstance(typeof(NamedConfigureFromConfigurationOptions<>).MakeGenericType(optionType), + string.Empty, + configurationSection, configureBinder)!; + services.TryAdd(new ServiceDescriptor(typeof(IConfigureOptions<>).MakeGenericType(optionType), + configureOptions)); + } + + private class MasaConfigurationProvider + { + + } +} diff --git a/src/Configuration/MASA.Contrib.Configuration/_Imports.cs b/src/Configuration/MASA.Contrib.Configuration/_Imports.cs new file mode 100644 index 000000000..85d4ce738 --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/_Imports.cs @@ -0,0 +1,15 @@ +global using MASA.BuildingBlocks.Configuration; +global using MASA.BuildingBlocks.Configuration.Options; +global using Microsoft.AspNetCore.Builder; +global using Microsoft.Extensions.Configuration; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.DependencyInjection.Extensions; +global using Microsoft.Extensions.Logging; +global using Microsoft.Extensions.Options; +global using Microsoft.Extensions.Primitives; +global using System; +global using System.Collections.Concurrent; +global using System.Collections.Generic; +global using System.Linq; +global using System.Reflection; +global using System.Text.Json.Serialization; diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/DispatcherOptionsExtensions.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/DispatcherOptionsExtensions.cs index fe1608028..ee5ae368f 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/DispatcherOptionsExtensions.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/DispatcherOptionsExtensions.cs @@ -13,17 +13,15 @@ public static IDispatcherOptions UseRepository( where TDbContext : DbContext { if (options.Services == null) - { throw new ArgumentNullException(nameof(options.Services)); - } - if (options.Services.Any(service => service.ImplementationType == typeof(RepositoryProvider))) return options; + if (options.Services.Any(service => service.ImplementationType == typeof(RepositoryProvider))) + return options; + options.Services.AddSingleton(); if (options.Services.All(service => service.ServiceType != typeof(IUnitOfWork))) - { throw new Exception("Please add UoW first."); - } options.Services.TryAddRepository(assemblies); return options; diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/LinqExtensions.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/LinqExtensions.cs new file mode 100644 index 000000000..95ceb5ef3 --- /dev/null +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/LinqExtensions.cs @@ -0,0 +1,67 @@ +namespace MASA.Contrib.DDD.Domain.Repository.EF.Internal; + +internal static class LinqExtensions +{ + public static IQueryable OrderBy(this IQueryable query, string[] fields, bool desc) where T : class + { + for (int i = 0; i < fields.Length; i++) + { + if (i == 0) + query = query.OrderBy(fields[i], desc); + else + query = query.ThenBy(fields[i], desc); + } + + return query; + } + + public static IQueryable OrderBy(this IQueryable query, string field, bool desc) where T : class + { + ParameterExpression parameterExpression = Expression.Parameter(typeof(T)); + Expression key = Expression.Property(parameterExpression, field); + var propertyInfo = GetPropertyInfo(typeof(T), field); + var orderExpression = GetOrderExpression(typeof(T), propertyInfo); + if (desc) + { + var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "OrderByDescending" && m.GetParameters().Length == 2); + var genericMethod = method!.MakeGenericMethod(typeof(T), propertyInfo.PropertyType); + return (genericMethod.Invoke(null, new object[] { query, orderExpression }) as IQueryable)!; + } + else + { + var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "OrderBy" && m.GetParameters().Length == 2); + var genericMethod = method!.MakeGenericMethod(typeof(T), propertyInfo.PropertyType); + return (IQueryable)genericMethod.Invoke(null, new object[] { query, orderExpression })!; + } + } + + public static IQueryable ThenBy(this IQueryable query, string field, bool desc) where T : class + { + ParameterExpression parameterExpression = Expression.Parameter(typeof(T)); + Expression key = Expression.Property(parameterExpression, field); + var propertyInfo = GetPropertyInfo(typeof(T), field); + var orderExpression = GetOrderExpression(typeof(T), propertyInfo); + if (desc) + { + var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "ThenByDescending" && m.GetParameters().Length == 2); + var genericMethod = method!.MakeGenericMethod(typeof(T), propertyInfo.PropertyType); + return (genericMethod.Invoke(null, new object[] { query, orderExpression }) as IQueryable)!; + } + else + { + var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "ThenBy" && m.GetParameters().Length == 2); + var genericMethod = method!.MakeGenericMethod(typeof(T), propertyInfo.PropertyType); + return (IQueryable)genericMethod.Invoke(null, new object[] { query, orderExpression })!; + } + } + + private static PropertyInfo GetPropertyInfo(Type entityType, string field) + => entityType.GetProperties().FirstOrDefault(p => p.Name.Equals(field, StringComparison.OrdinalIgnoreCase))!; + + private static LambdaExpression GetOrderExpression(Type entityType, PropertyInfo propertyInfo) + { + var parametersExpression = Expression.Parameter(entityType); + var fieldExpression = Expression.PropertyOrField(parametersExpression, propertyInfo.Name); + return Expression.Lambda(fieldExpression, parametersExpression); + } +} diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs index 4a344663f..a51b8bdb5 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs @@ -2,6 +2,11 @@ namespace MASA.Contrib.DDD.Domain.Repository.EF.Internal; internal static class ServiceCollectionRepositoryExtensions { + /// + /// The relationship between entity and keys + /// + public static Dictionary Relations = new(); + public static IServiceCollection TryAddRepository( this IServiceCollection services, params Assembly[] assemblies) @@ -9,7 +14,7 @@ public static IServiceCollection TryAddRepository( { if (assemblies == null || assemblies.Length == 0) { - assemblies = AppDomain.CurrentDomain.GetAssemblies(); + throw new ArgumentNullException(nameof(assemblies)); } var allTypes = assemblies.SelectMany(assembly => assembly.GetTypes()); @@ -21,10 +26,46 @@ public static IServiceCollection TryAddRepository( services.TryAddAddDefaultRepository(repositoryInterfaceType, GetRepositoryImplementationType(typeof(TDbContext), entityType)); services.TryAddCustomRepository(repositoryInterfaceType, allTypes.ToArray()); + + var keys = GetKeys(entityType); + CheckKeys(entityType, keys); + Relations.TryAdd(entityType, keys); } + return services; } + private static string[] GetKeys(Type entityType) + { + IAggregateRoot aggregateRoot; + try + { + aggregateRoot = (IAggregateRoot)(Activator.CreateInstance(entityType))!; + } + catch (Exception ex) + { + throw new ArgumentNullException("The entity needs to have an empty constructor"); + } + + var keys = aggregateRoot.GetKeys().Select(k => k.Name).ToArray(); + if (keys.Length != keys.Where(key => !string.IsNullOrEmpty(key)).Distinct().Count()) + throw new ArgumentException("The joint primary key cannot be empty"); + + return keys; + } + + /// + /// Check if the combined primary key is correct + /// + private static void CheckKeys(Type entityType, string[] fields) + { + foreach (var field in fields) + { + if (!entityType.GetProperties().Any(p => p.Name.Equals(field, StringComparison.OrdinalIgnoreCase))!) + throw new ArgumentException("Check if the combined primary key is correct"); + } + } + private static bool IsAggregateRootEntity(this Type type) => type.IsClass && !type.IsGenericType && !type.IsAbstract && type != typeof(AggregateRoot) && type != typeof(Entity) && typeof(IAggregateRoot).IsAssignableFrom(type); diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj index 706d68185..ae978ffb0 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj @@ -5,11 +5,11 @@ enable enable - + - - - + + + - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs index bcde5dbce..9a804fdce 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs @@ -12,6 +12,9 @@ public Repository(TDbContext context, IUnitOfWork unitOfWork) UnitOfWork = unitOfWork; } + public override bool TransactionHasBegun + => _context.Database.CurrentTransaction != null; + public override DbTransaction Transaction { get @@ -22,20 +25,9 @@ public override DbTransaction Transaction } return _context.Database.BeginTransaction().GetDbTransaction(); } - set - { - if (_context.Database.CurrentTransaction == null) - { - _context.Database.UseTransaction(value); - } - else - { - throw new NotSupportedException("The transaction is opened"); - } - } } - public override IUnitOfWork UnitOfWork { get; set; } + public override IUnitOfWork UnitOfWork { get; } public override async ValueTask AddAsync(TEntity entity, CancellationToken cancellationToken = default) => (await _context.AddAsync(entity, cancellationToken).AsTask()).Entity; @@ -46,7 +38,7 @@ public override Task AddRangeAsync(IEnumerable entities, CancellationTo public override Task CommitAsync(CancellationToken cancellationToken = default) => UnitOfWork.CommitAsync(cancellationToken); - public override ValueTask DisposeAsync() => ValueTask.CompletedTask; + public override async ValueTask DisposeAsync() => await ValueTask.CompletedTask; public override ValueTask FindAsync(object?[]? keyValues, CancellationToken cancellationToken) => _context.Set().FindAsync(keyValues, cancellationToken); @@ -56,8 +48,8 @@ public override Task CommitAsync(CancellationToken cancellationToken = default) CancellationToken cancellationToken = default) => _context.Set().Where(predicate).FirstOrDefaultAsync(cancellationToken); - public override Task GetCountAsync(CancellationToken cancellationToken) - => _context.Set().LongCountAsync(cancellationToken); + public override async Task GetCountAsync(CancellationToken cancellationToken) + => await _context.Set().LongCountAsync(cancellationToken); public override Task GetCountAsync( Expression> predicate, @@ -72,16 +64,33 @@ public override async Task> GetListAsync( CancellationToken cancellationToken) => await _context.Set().Where(predicate).ToListAsync(cancellationToken); + /// + /// + /// + /// + /// + /// asc or desc, default asc + /// + /// public override Task> GetPaginatedListAsync(int skip, int take, string? sorting, CancellationToken cancellationToken) { - var iQueryable = _context.Set(); - return (string.Equals(sorting ?? "asc", "asc", StringComparison.CurrentCultureIgnoreCase) ? iQueryable.OrderBy(x => x.GetKeys()) : iQueryable.OrderByDescending(x => x.GetKeys())).Skip(skip).Take(take).ToListAsync(cancellationToken); + var isDesc = !string.Equals(sorting ?? "asc", "asc", StringComparison.CurrentCultureIgnoreCase); + return _context.Set().OrderBy(GetKeys(typeof(TEntity)), isDesc).Skip(skip).Take(take).ToListAsync(cancellationToken); } + /// + /// + /// + /// condition + /// + /// + /// asc or desc, default asc + /// + /// public override Task> GetPaginatedListAsync(Expression> predicate, int skip, int take, string? sorting, CancellationToken cancellationToken) { - var iQueryable = _context.Set().Where(predicate); - return (string.Equals(sorting ?? "asc", "asc", StringComparison.CurrentCultureIgnoreCase) ? iQueryable.OrderBy(x => x.GetKeys()) : iQueryable.OrderByDescending(x => x.GetKeys())).Skip(skip).Take(take).ToListAsync(cancellationToken); + var isDesc = !string.Equals(sorting ?? "asc", "asc", StringComparison.CurrentCultureIgnoreCase); + return _context.Set().Where(predicate).OrderBy(GetKeys(typeof(TEntity)), isDesc).Skip(skip).Take(take).ToListAsync(cancellationToken); } public override Task RemoveAsync(TEntity entity, CancellationToken cancellationToken = default) @@ -119,4 +128,7 @@ public override Task UpdateRangeAsync(IEnumerable entities, Cancellatio _context.Set().UpdateRange(entities); return Task.CompletedTask; } + + private string[] GetKeys(Type entityType) + => ServiceCollectionRepositoryExtensions.Relations[entityType]!; } diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/_Imports.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/_Imports.cs index 345d1a833..2950dfb43 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/_Imports.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/_Imports.cs @@ -7,6 +7,8 @@ global using Microsoft.EntityFrameworkCore.Storage; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection.Extensions; +global using Microsoft.Extensions.Logging; +global using System.Collections.Concurrent; global using System.Data.Common; global using System.Linq.Expressions; global using System.Reflection; diff --git a/src/DDD/MASA.Contrib.DDD.Domain/DomainEventBus.cs b/src/DDD/MASA.Contrib.DDD.Domain/DomainEventBus.cs index 82dea5513..556b00400 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/DomainEventBus.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/DomainEventBus.cs @@ -19,18 +19,30 @@ public DomainEventBus(IEventBus eventBus, IIntegrationEventBus integrationEventB public async Task PublishAsync(TEvent @event) where TEvent : IEvent { + if (@event is IDomainEvent @domainEvent && !IsAssignableFromDomainQuery(@event.GetType())) + { + @domainEvent.UnitOfWork = _unitOfWork; + } if (@event is IIntegrationEvent integrationEvent) { - if (integrationEvent.UnitOfWork == null) - { - integrationEvent.UnitOfWork = _unitOfWork; - } - await _integrationEventBus.PublishAsync(integrationEvent); + await _integrationEventBus.PublishAsync((TEvent)integrationEvent); } else { await _eventBus.PublishAsync(@event); } + + bool IsAssignableFromDomainQuery(Type? type) + { + if (type == null) + return false; + + if (!type.IsGenericType) + { + return IsAssignableFromDomainQuery(type.BaseType); + } + return type.GetInterfaces().Any(type => type.GetGenericTypeDefinition() == typeof(IDomainQuery<>)); + } } public Task Enqueue(TDomentEvent @event) where TDomentEvent : IDomainEvent @@ -48,9 +60,7 @@ public async Task PublishQueueAsync() } public async Task CommitAsync(CancellationToken cancellationToken = default) - { - await _unitOfWork.CommitAsync(cancellationToken); - } + => await _unitOfWork.CommitAsync(cancellationToken); public IEnumerable GetAllEventTypes() => _options.AllEventTypes.Concat(_eventBus.GetAllEventTypes()).Distinct(); } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs index a91c481e4..f622ae736 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs @@ -8,7 +8,11 @@ public abstract record DomainQuery : IDomainQuery public DateTime CreationTime { get; init; } [JsonIgnore] - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork UnitOfWork + { + get => throw new NotSupportedException(nameof(UnitOfWork)); + set => throw new NotSupportedException(nameof(UnitOfWork)); + } public abstract TResult Result { get; set; } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj index cc3af397a..32938df06 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Options/DispatcherOptions.cs b/src/DDD/MASA.Contrib.DDD.Domain/Options/DispatcherOptions.cs index 8fdef4264..742ffa1bc 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Options/DispatcherOptions.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Options/DispatcherOptions.cs @@ -22,17 +22,17 @@ public Assembly[] Assemblies } private bool IsAggregateRootEntity(Type type) - => type.IsClass && !type.IsGenericType && !type.IsAbstract && type != typeof(AggregateRoot) && type != typeof(Entity) && typeof(IAggregateRoot).IsAssignableFrom(type); + => type.IsClass && !type.IsGenericType && !type.IsAbstract && type != typeof(AggregateRoot) && typeof(IAggregateRoot).IsAssignableFrom(type); private IEnumerable Types { get; set; } - public List AllEventTypes { get; private set; } + private IEnumerable GetTypes(Type type) => Types.Where(t => t.IsClass && type.IsAssignableFrom(t)); - public List AllDomainServiceTypes { get; private set; } + internal List AllEventTypes { get; private set; } - public List AllAggregateRootTypes { get; private set; } + internal List AllDomainServiceTypes { get; private set; } - private IEnumerable GetTypes(Type type) => Types.Where(t => type.IsAssignableFrom(t) && t.IsClass); + internal List AllAggregateRootTypes { get; private set; } public IServiceCollection Services { get; } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/ServiceCollectionExtensions.cs b/src/DDD/MASA.Contrib.DDD.Domain/ServiceCollectionExtensions.cs index 75aa97ab7..28c03d33e 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/ServiceCollectionExtensions.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/ServiceCollectionExtensions.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.DependencyInjection.Extensions; - namespace MASA.Contrib.DDD.Domain; public static class ServiceCollectionExtensions @@ -8,7 +6,9 @@ public static IServiceCollection AddDomainEventBus( this IServiceCollection services, Action? options = null) { - if (services.Any(service => service.ImplementationType == typeof(DomainEventBusProvider))) return services; + if (services.Any(service => service.ImplementationType == typeof(DomainEventBusProvider))) + return services; + services.AddSingleton(); var dispatcherOptions = new DispatcherOptions(services); @@ -17,7 +17,7 @@ public static IServiceCollection AddDomainEventBus( { dispatcherOptions.Assemblies = AppDomain.CurrentDomain.GetAssemblies(); } - services.TryAddSingleton(typeof(IOptions), serviceProvider => Microsoft.Extensions.Options.Options.Create(dispatcherOptions)); + services.AddSingleton(typeof(IOptions), serviceProvider => Options.Create(dispatcherOptions)); if (services.All(service => service.ServiceType != typeof(IEventBus))) { diff --git a/src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs b/src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs index 971573b0d..62791d406 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/_Imports.cs @@ -6,6 +6,7 @@ global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.DependencyInjection.Extensions; global using Microsoft.Extensions.Options; global using System.Collections.Concurrent; global using System.Reflection; diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj index 2a7fc1298..c6c6f6e88 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj @@ -7,10 +7,10 @@ - - - - - + + + + + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs b/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs index d5fab308d..aaffad5bf 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs @@ -1,19 +1,18 @@ -namespace MASA.Contrib.Data.Contracts.EF.SoftDelete +namespace MASA.Contrib.Data.Contracts.EF.SoftDelete; + +public class TransactionSaveChangesFilter : ISaveChangesFilter { - public class TransactionSaveChangesFilter : ISaveChangesFilter - { - private readonly IServiceProvider _serviceProvider; + private readonly IServiceProvider _serviceProvider; - public TransactionSaveChangesFilter(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; + public TransactionSaveChangesFilter(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; - public void OnExecuting(ChangeTracker changeTracker) + public void OnExecuting(ChangeTracker changeTracker) + { + changeTracker.DetectChanges(); + var unitOfWork = _serviceProvider.GetRequiredService(); + if (changeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) && !unitOfWork.TransactionHasBegun) { - changeTracker.DetectChanges(); - var unitOfWork = _serviceProvider.GetRequiredService(); - if (changeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) && !unitOfWork.TransactionHasBegun) - { - var transaction = unitOfWork.Transaction; // Open the transaction - } + var transaction = unitOfWork.Transaction; // Open the transaction } } } diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs b/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs index 118804a1a..c9bcd3cfa 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs @@ -4,23 +4,29 @@ public static class DispatcherOptionsExtensions { public static IDispatcherOptions UseUoW( this IDispatcherOptions options, - Action? optionsBuilder = null) + Action? optionsBuilder = null, + bool disableRollbackOnFailure = false) where TDbContext : MasaDbContext { if (options.Services == null) - { throw new ArgumentNullException(nameof(options.Services)); - } - if (options.Services.Any(service => service.ImplementationType == typeof(UoWProvider))) return options; + if (options.Services.Any(service => service.ImplementationType == typeof(UoWProvider))) + return options; + options.Services.AddSingleton(); - options.Services.AddLogging(); - options.Services.AddScoped>(); - if (options.Services.All(service => service.ServiceType != typeof(MasaDbContextOptions))) + options.Services.AddScoped(serviceProvider => { + var dbContext = serviceProvider.GetRequiredService(); + var logger = serviceProvider.GetService>>(); + return new UnitOfWork(dbContext, logger) + { + DisableRollbackOnFailure = disableRollbackOnFailure + }; + }); + if (options.Services.All(service => service.ServiceType != typeof(MasaDbContextOptions))) options.Services.AddMasaDbContext(optionsBuilder); - } options.Services.AddScoped(); diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj index 65959f903..c4d0854ef 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj +++ b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj @@ -7,11 +7,11 @@ - - - - - + + + + + diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs b/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs index 12b3eca2c..a54b487cb 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs @@ -1,5 +1,3 @@ -using System.Text.Json.Serialization; - namespace MASA.Contrib.Data.UoW.EF; public class Transaction : ITransaction diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs b/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs index f4cde3a84..052dca91c 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs @@ -1,6 +1,6 @@ namespace MASA.Contrib.Data.UoW.EF; -public class UnitOfWork : IUnitOfWork +public class UnitOfWork : IAsyncDisposable, IUnitOfWork where TDbContext : MasaDbContext { public DbTransaction Transaction @@ -21,9 +21,9 @@ public DbTransaction Transaction private readonly DbContext _context; - private readonly ILogger> _logger; + private readonly ILogger>? _logger; - public UnitOfWork(TDbContext dbContext, ILogger> logger) + public UnitOfWork(TDbContext dbContext, ILogger>? logger = null) { _context = dbContext; _logger = logger; @@ -37,24 +37,23 @@ public async Task SaveChangesAsync(CancellationToken cancellationToken = default public async Task CommitAsync(CancellationToken cancellationToken = default) { if (!TransactionHasBegun) - { - return; - } + throw new NotSupportedException("Transaction not opened"); try { - await SaveChangesAsync(); + await SaveChangesAsync(cancellationToken); await _context.Database.CommitTransactionAsync(cancellationToken); } catch (Exception ex) { if (DisableRollbackOnFailure) { - _logger.LogError(ex, "Failed to commit transaction"); + _logger?.LogError(ex, "Failed to commit transaction"); throw; } + await _context.Database.RollbackTransactionAsync(cancellationToken); - _logger.LogError(ex, "Failed to commit transaction, rolled back"); + _logger?.LogError(ex, "Failed to commit transaction, rolled back"); } } @@ -62,11 +61,9 @@ public async Task RollbackAsync(CancellationToken cancellationToken = default) { if (!TransactionHasBegun) throw new NotSupportedException("Transactions are not started and rollback is not supported"); + await _context.Database.RollbackTransactionAsync(cancellationToken); } - public ValueTask DisposeAsync() - { - return ValueTask.CompletedTask; - } + public ValueTask DisposeAsync() => ValueTask.CompletedTask; } diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/_Imports.cs b/src/Data/MASA.Contrib.Data.UoW.EF/_Imports.cs index 81fcd49fa..4a660924a 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/_Imports.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/_Imports.cs @@ -6,3 +6,4 @@ global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.Logging; global using System.Data.Common; +global using System.Text.Json.Serialization; diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs index af121ac17..3ef2f01f0 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs @@ -49,12 +49,12 @@ public async Task PublishAsync(TEvent @event) where TEvent : IEvent await middlewares.Reverse().Aggregate(publishEvent, (next, middleware) => () => middleware.HandleAsync(@event, next))(); } - public IEnumerable GetAllEventTypes() => _options.GetAllEventTypes(); + public IEnumerable GetAllEventTypes() => _options.AllEventTypes; public async Task CommitAsync(CancellationToken cancellationToken = default) { if (_unitOfWork is null) - throw new ArgumentNullException(nameof(IUnitOfWork), "You need to UseUoW when adding services"); + throw new ArgumentNullException("You need to UseUoW when adding services"); await _unitOfWork.CommitAsync(cancellationToken); } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs index 1bb69f7e5..882a9ad00 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs @@ -12,30 +12,11 @@ public TransactionMiddleware(ILogger> logger) public async Task HandleAsync(TEvent @event, EventHandlerDelegate next) { - try - { - await next(); + await next(); - if (@event is ITransaction transactionEvent) - { - if (transactionEvent.UnitOfWork != null && transactionEvent.UnitOfWork.TransactionHasBegun) - { - await transactionEvent.UnitOfWork.CommitAsync(); - } - } - } - catch (Exception ex) + if (@event is ITransaction transactionEvent && transactionEvent.UnitOfWork != null && transactionEvent.UnitOfWork.TransactionHasBegun) { - _logger.LogError(ex, nameof(TransactionMiddleware)); - - if (@event is ITransaction transactionEvent && transactionEvent.UnitOfWork != null && transactionEvent.UnitOfWork.TransactionHasBegun && !transactionEvent.UnitOfWork.DisableRollbackOnFailure) - { - await transactionEvent.UnitOfWork.RollbackAsync(); - } - else - { - throw; - } + await transactionEvent.UnitOfWork.CommitAsync(); } } } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj index 4915dde83..8c5760882 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj @@ -7,11 +7,11 @@ - - - - - + + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs index 6e7cd6a06..8a2dd3fce 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs @@ -14,20 +14,16 @@ public Assembly[] Assemblies { throw new ArgumentNullException(nameof(_assemblies)); } - Types = _assemblies.SelectMany(assembly => assembly.GetTypes()).ToList(); - _allEventTypes = GetTypes(typeof(IEvent)).ToList(); + AllEventTypes = _assemblies + .SelectMany(assembly => assembly.GetTypes()) + .Where(type => type.IsClass && typeof(IEvent).IsAssignableFrom(type)) + .ToList(); } } - private IEnumerable Types { get; set; } - - private IEnumerable GetTypes(Type type) => Types.Where(t => type.IsAssignableFrom(t) && t.IsClass); - - public IEnumerable GetAllEventTypes() => _allEventTypes; + public IEnumerable AllEventTypes { get; private set; } public IServiceCollection Services { get; } - private IEnumerable _allEventTypes; - public DispatcherOptions(IServiceCollection services) => Services = services; } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs index 0835dc9f2..b0880c91f 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs @@ -31,8 +31,8 @@ public IntegrationEventBus(IOptions options, public IEnumerable GetAllEventTypes() => _eventBus == null ? - dispatcherOptions.GetAllEventTypes() : - dispatcherOptions.GetAllEventTypes().Concat(_eventBus.GetAllEventTypes()).Distinct(); + dispatcherOptions.AllEventTypes : + dispatcherOptions.AllEventTypes.Concat(_eventBus.GetAllEventTypes()).Distinct(); public async Task PublishAsync(TEvent @event) where TEvent : IEvent diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj index bff8b21c5..52fdcd26e 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj @@ -7,11 +7,11 @@ - + - - - + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/Options/DispatcherOptions.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/Options/DispatcherOptions.cs index 828cff347..2ccadea4f 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/Options/DispatcherOptions.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/Options/DispatcherOptions.cs @@ -11,7 +11,7 @@ public string PubSubName { if (string.IsNullOrWhiteSpace(value)) { - throw new ArgumentNullException(_pubSubName); + throw new ArgumentNullException(nameof(_pubSubName)); } _pubSubName = value; } @@ -31,18 +31,15 @@ public Assembly[] Assemblies { throw new ArgumentNullException(nameof(_assemblies)); } - Types = _assemblies.SelectMany(assembly => assembly.GetTypes()).ToList(); - AllEventTypes = GetTypes(typeof(IEvent)).ToList(); + + AllEventTypes = _assemblies + .SelectMany(assembly => assembly.GetTypes()) + .Where(type => type.IsClass && typeof(IEvent).IsAssignableFrom(type)) + .ToList(); } } - private List Types { get; set; } - - private List AllEventTypes { get; set; } - - private IEnumerable GetTypes(Type type) => Types.Where(t => type.IsAssignableFrom(t) && t.IsClass && t != typeof(IntegrationEvent)); - - public IEnumerable GetAllEventTypes() => AllEventTypes; + public List AllEventTypes { get; private set; } public DispatcherOptions(IServiceCollection services) => Services = services; } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs index e3f491902..d991b8f61 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs @@ -59,7 +59,10 @@ public Task MarkEventAsFailedAsync(Guid eventId) private async Task UpdateEventStatus(Guid eventId, IntegrationEventStates status) { - var eventLogEntry = _eventLogContext.EventLogs.Single(e => e.Id == eventId); + var eventLogEntry = _eventLogContext.EventLogs.FirstOrDefault(e => e.EventId == eventId); + if (eventLogEntry == null) + throw new ArgumentException(nameof(eventId)); + eventLogEntry.State = status; if (status == IntegrationEventStates.InProgress) @@ -73,10 +76,9 @@ private async Task UpdateEventStatus(Guid eventId, IntegrationEventStates status private void CheckAndDetached(IntegrationEventLog integrationEvent) { - return; if (_eventLogContext.ChangeTracker.QueryTrackingBehavior != QueryTrackingBehavior.TrackAll) { - _eventLogContext.Entry(integrationEvent).State = EntityState.Detached; + _eventLogContext.Entry(integrationEvent).State = EntityState.Detached; } } } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/Internal/QueryFilterProvider.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/Internal/QueryFilterProvider.cs index 4b32ab4ad..c21f782a4 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/Internal/QueryFilterProvider.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/Internal/QueryFilterProvider.cs @@ -1,6 +1,3 @@ -using Microsoft.EntityFrameworkCore.Metadata; -using System.Linq.Expressions; - namespace MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Internal; internal abstract class QueryFilterProvider : IQueryFilterProvider diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj index 2bcd80cb6..87db25155 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/_Imports.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/_Imports.cs index 18e5a61e2..c83947ac6 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/_Imports.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/_Imports.cs @@ -5,6 +5,7 @@ global using MASA.Utils.Data.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore.ChangeTracking; +global using Microsoft.EntityFrameworkCore.Metadata; global using Microsoft.EntityFrameworkCore.Metadata.Builders; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection.Extensions; @@ -12,4 +13,5 @@ global using System.Collections.Generic; global using System.Data.Common; global using System.Linq; +global using System.Linq.Expressions; global using System.Threading.Tasks; diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj index e20d3f74c..029b97a4f 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj @@ -7,10 +7,10 @@ - - - + + + - + diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Queries/QueryHandler.cs b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Queries/QueryHandler.cs index 5e44c2eba..44256ba62 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Queries/QueryHandler.cs +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Queries/QueryHandler.cs @@ -1,13 +1,8 @@ namespace MASA.Contrib.ReadWriteSpliting.CQRS.Queries; -public abstract class QueryHandler : IQueryHandler, ISagaEventHandler - where TCommand : IQuery +public abstract class QueryHandler : IQueryHandler + where TQuery : IQuery where TResult : notnull { - public abstract Task HandleAsync(TCommand @event); - - public virtual Task CancelAsync(TCommand @event) - { - return Task.CompletedTask; - } + public abstract Task HandleAsync(TQuery @event); } diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj index c485abb3b..8cdd6f22d 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj @@ -6,9 +6,10 @@ - - - + + + + diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs b/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs index 910cee7a0..6d0bee5d0 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs @@ -1,4 +1,5 @@ namespace MASA.Contrib.Service.MinimalAPIs; + public class ServiceBase : IService { private ServiceProvider _serviceProvider = default!; diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceCollectionExtensions.cs b/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceCollectionExtensions.cs index b6c816c19..98a21e7a1 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceCollectionExtensions.cs +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceCollectionExtensions.cs @@ -1,9 +1,16 @@ -using System.Linq; - namespace MASA.Contrib.Service.MinimalAPIs; public static class ServiceCollectionExtensions { + /// + /// Add all classes that inherit from ServiceBase to Microsoft.Extensions.DependencyInjection.IServiceCollection + /// Notice: this method must be last call. + /// + /// The Microsoft.AspNetCore.Builder.WebApplicationBuilder. + /// + public static WebApplication AddServices(this WebApplicationBuilder builder) + => builder.Services.AddServices(builder); + /// /// Add all classes that inherit from ServiceBase to Microsoft.Extensions.DependencyInjection.IServiceCollection /// Notice: this method must be last call. @@ -21,7 +28,7 @@ public static WebApplication AddServices(this IServiceCollection services, WebAp services.AddSingleton(new Lazy(() => builder.Build(), LazyThreadSafetyMode.ExecutionAndPublication)) .AddTransient(serviceProvider => serviceProvider.GetRequiredService>().Value); - services.AddServices(true); + services.AddServices(true, AppDomain.CurrentDomain.GetAssemblies()); } var serviceProvider = services.BuildServiceProvider(); diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/_Imports.cs b/src/Service/MASA.Contrib.Service.MinimalAPIs/_Imports.cs index e4101ab7d..9015d4d4a 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/_Imports.cs +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/_Imports.cs @@ -3,4 +3,5 @@ global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection.Extensions; global using System; +global using System.Linq; global using System.Threading; diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs new file mode 100644 index 000000000..b50eebe3c --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs @@ -0,0 +1,342 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Tests; + +[TestClass] +public class DccClientTest +{ + private Mock _client; + private JsonSerializerOptions _jsonSerializerOptions; + private DccSectionOptions _dccSectionOptions; + private CustomTrigger _trigger; + + [TestInitialize] + public void Initialize() + { + _client = new(); + _jsonSerializerOptions = new JsonSerializerOptions() + { + PropertyNameCaseInsensitive = true + }; + _dccSectionOptions = new DccSectionOptions() + { + Environment = "Test", + Cluster = "Default", + AppId = "DccTest", + ConfigObjects = new List() + { + "Test1" + }, + Secret = "" + }; + _trigger = new CustomTrigger(_jsonSerializerOptions); + } + + [DataTestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task TestGetRawAsync(string environment, string cluster, string appId, string configObject) + { + Action valueChanged = delegate (string val) { }; + _client.Setup(client => client.GetAsync(It.IsAny(), valueChanged).Result).Returns(() => null).Verifiable(); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () + => await client.GetRawAsync(environment, cluster, appId, configObject, valueChanged), "configObject invalid" + ); + + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => "test").Verifiable(); + client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () + => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()) + ); + + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => "{}").Verifiable(); + await Assert.ThrowsExceptionAsync(async () + => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), "configObject invalid" + ); + + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new + { + ConfigFormat = "1", + Content = "" + }.Serialize(_jsonSerializerOptions)).Verifiable(); + await Assert.ThrowsExceptionAsync(async () + => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), "configObject invalid" + ); + + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease + { + ConfigFormat = (ConfigFormats)5, + Content = "" + }.Serialize(_jsonSerializerOptions)).Verifiable(); + await Assert.ThrowsExceptionAsync(async () => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), "Unsupported configuration type"); + } + + [DataTestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task TestGetRawAsyncByJson(string environment, string cluster, string appId, string configObject) + { + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + + var brand = new Brands("Apple"); + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Json, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Verifiable(); + var ret = await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsTrue(ret.Raw == brand.Serialize(_jsonSerializerOptions)); + Assert.IsTrue(ret.ConfigurationType == ConfigurationTypes.Json); + } + + [DataTestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task TestGetRawAsyncByText(string environment, string cluster, string appId, string configObject) + { + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Text, + Content = "test" + }.Serialize(_jsonSerializerOptions)).Verifiable(); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var ret = await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsTrue(ret.Raw == "test"); + Assert.IsTrue(ret.ConfigurationType == ConfigurationTypes.Text); + } + + [DataTestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task TestGetRawAsyncByProperty(string environment, string cluster, string appId, string configObject) + { + List properties = new List() + { + new Property() + { + Key="Brand", + Value="Microsoft" + } + }; + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Text, + Content = properties.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Verifiable(); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var ret = await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsTrue(ret.Raw == properties.Serialize(_jsonSerializerOptions)); + Assert.IsTrue(ret.ConfigurationType == ConfigurationTypes.Text); + } + + [TestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task GetAsyncByJson(string environment, string cluster, string appId, string configObject) + { + var brand = new Brands("Microsoft"); + var newBrand = new Brands("Microsoft2"); + + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Json, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Callback((string str, Action action) => + { + _trigger.Formats = ConfigFormats.Json; + _trigger.Content = newBrand.Serialize(_jsonSerializerOptions); + _trigger.Action = action; + }); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var ret = await client.GetAsync(environment, cluster, appId, configObject, (Brands br) => + { + Assert.IsTrue(br.Id == newBrand.Id); + Assert.IsTrue(br.Name == newBrand.Name); + }); + Assert.IsNotNull(ret); + + Assert.IsTrue(ret.Serialize(_jsonSerializerOptions).Equals(brand.Serialize(_jsonSerializerOptions))); + _trigger.Execute(); + + ret = await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsNotNull(ret); + + Assert.IsTrue(ret.Id == newBrand.Id && ret.Name == newBrand.Name); + + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Json, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Callback((string str, Action action) => + { + _trigger.Formats = ConfigFormats.Json; + newBrand.Name = "Masa"; + _trigger.Content = newBrand.Serialize(_jsonSerializerOptions); + _trigger.Action = action; + }); + client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + ret = await client.GetAsync(environment, cluster, appId, configObject, null); + Assert.IsNotNull(ret); + Assert.IsTrue(ret.Id == brand.Id && ret.Name == brand.Name); + _trigger.Execute(); + ret = await client.GetAsync(environment, cluster, appId, configObject, null); + Assert.IsTrue(ret.Id == newBrand.Id && ret.Name == "Masa"); + + _client.Setup(client => client.GetAsync(It.IsAny(), null).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Json, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)); + client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + ret = await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsNotNull(ret); + Assert.IsTrue(ret.Id == brand.Id && ret.Name == brand.Name); + } + + [TestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task GetAsyncByText(string environment, string cluster, string appId, string configObject) + { + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Text, + Content = "test" + }.Serialize(_jsonSerializerOptions)).Verifiable(); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () => await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>())); + } + + [TestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task GetAsyncByProperty(string environment, string cluster, string appId, string configObject) + { + var brand = new List() + { + new Property() + { + Key = "Id", + Value=Guid.NewGuid().ToString(), + }, + new Property() + { + Key = "Name", + Value = "Microsoft" + } + }; + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Properties, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Verifiable(); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var ret = await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsNotNull(ret); + + Assert.IsTrue(ret.Id.ToString() == brand.Where(b => b.Key == "Id").Select(t => t.Value).FirstOrDefault() && ret.Name == brand.Where(b => b.Key == "Name").Select(t => t.Value).FirstOrDefault()); + } + + [TestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task GetDynamicAsyncByJson(string environment, string cluster, string appId, string configObject) + { + var brand = new Brands("Microsoft"); + var newBrand = new Brands("Microsoft2"); + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Json, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Callback((string str, Action action) => + { + _trigger.Formats = ConfigFormats.Json; + _trigger.Content = newBrand.Serialize(_jsonSerializerOptions); + _trigger.Action = action; + }).Verifiable(); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, (dynamic obj) => + { + Assert.IsTrue((obj.Id + "") == newBrand.Id.ToString()); + + Assert.IsTrue(obj.Name == newBrand.Name); + }); + Assert.IsNotNull(ret); + + Assert.IsTrue(ret.Id == brand.Id.ToString()); + + Assert.IsTrue(ret.Name == brand.Name); + + _trigger.Execute(); + + ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsNotNull(ret); + Assert.IsTrue(ret.Id == newBrand.Id.ToString() && ret.Name == newBrand.Name); + + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Json, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Callback((string str, Action action) => + { + _trigger.Formats = ConfigFormats.Json; + _trigger.Content = newBrand.Serialize(_jsonSerializerOptions); + _trigger.Action = action; + }).Verifiable(); + client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny()); + Assert.IsNotNull(ret); + Assert.IsTrue(ret.Id == brand.Id.ToString()); + Assert.IsTrue(ret.Name == brand.Name); + _trigger.Execute(); + + ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsNotNull(ret); + Assert.IsTrue(ret.Id == newBrand.Id.ToString() && ret.Name == newBrand.Name); + + _client.Setup(client => client.GetAsync(It.IsAny(), null).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Json, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)); + client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsNotNull(ret); + Assert.IsTrue(ret.Id == brand.Id.ToString() && ret.Name == brand.Name); + } + + [TestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task GetDynamicAsyncByText(string environment, string cluster, string appId, string configObject) + { + string result = "Test"; + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Text, + Content = result + }.Serialize(_jsonSerializerOptions)).Verifiable(); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () => { await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); }); + } + + [TestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task GetDynamicAsyncByProperty(string environment, string cluster, string appId, string configObject) + { + var brand = new List() + { + new Property() + { + Key = "Id", + Value=Guid.NewGuid().ToString(), + }, + new Property() + { + Key = "Name", + Value = "Microsoft" + } + }; + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Properties, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Verifiable(); + var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); + Assert.IsNotNull(ret); + + Assert.IsTrue(ret.Id == brand.Where(b => b.Key == "Id").Select(b => b.Value).FirstOrDefault()); + Assert.IsTrue(ret.Name == brand.Where(b => b.Key == "Name").Select(b => b.Value).FirstOrDefault()); + } +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs new file mode 100644 index 000000000..26ae27118 --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs @@ -0,0 +1,163 @@ +using MASA.Contrib.BasicAbility.Dcc.Internal; +using MASA.Utils.Caller.Core; +using System.Net; + +namespace MASA.Contrib.BasicAbility.Dcc.Tests; + +[TestClass] +public class DccManageTest +{ + private DccSectionOptions _dccSectionOptions; + private JsonSerializerOptions _jsonSerializerOptions; + private Mock _callerProvider; + private Mock _httpMessageHandler; + + [TestInitialize] + public void Initialize() + { + _dccSectionOptions = new DccSectionOptions() + { + Environment = "Test", + Cluster = "Default", + AppId = "DccTest", + ConfigObjects = new List() + { + "Test1" + }, + Secret = "Secret" + }; + _jsonSerializerOptions = new JsonSerializerOptions() + { + PropertyNameCaseInsensitive = true + }; + _callerProvider = new(); + } + + [DataTestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task TestUpdateAsync(string environment, string cluster, string appId, string configObject) + { + var brand = new Brands("Microsoft"); + _callerProvider.Setup(factory => factory.PutAsync(It.IsAny(), It.IsAny(), default).Result).Returns(() => new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(brand.Serialize(_jsonSerializerOptions)) + }).Verifiable(); + + var manage = new ConfigurationAPIManage(_callerProvider.Object, _dccSectionOptions, null); + await manage.UpdateAsync(environment, cluster, appId, configObject, brand); + } + + [DataTestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task TestUpdateAsyncAndError(string environment, string cluster, string appId, string configObject) + { + var brand = new Brands("Microsoft"); + + _callerProvider.Setup(factory => factory.PutAsync(It.IsAny(), It.IsAny(), default).Result).Returns(() => new HttpResponseMessage() + { + StatusCode = HttpStatusCode.ExpectationFailed, + Content = new StringContent("error") + }).Verifiable(); + + var manage = new ConfigurationAPIManage(_callerProvider.Object, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () => await manage.UpdateAsync(environment, cluster, appId, configObject, brand)); + } + + [DataTestMethod] + [DataRow("Test", "Default", "DccTest", "Brand")] + public async Task TestUpdateAsyncAndCustomError(string environment, string cluster, string appId, string configObject) + { + var brand = new Brands("Microsoft"); + _callerProvider.Setup(factory => factory.PutAsync(It.IsAny(), It.IsAny(), default).Result).Returns(() => new HttpResponseMessage() + { + StatusCode = (HttpStatusCode)299, + Content = new StringContent("custom error") + }).Verifiable(); + + var manage = new ConfigurationAPIManage(_callerProvider.Object, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () => await manage.UpdateAsync(environment, cluster, appId, configObject, brand)); + } + + [DataTestMethod] + [DataRow("DccTest", "Secret")] + [DataRow("DccTest2", "Secret2")] + [DataRow("DccTest3", "")] + public void TestGetSecret(string appId, string secret) + { + var api = new CustomConfigurationAPI(_dccSectionOptions, new List() + { + new DccSectionOptions() + { + Environment = "Test2", + Cluster = "Default2", + AppId = "DccTest2", + ConfigObjects = new List() + { + "Test12" + }, + Secret = "Secret2" + } + }); + if (string.IsNullOrEmpty(secret)) + Assert.ThrowsException(() => api.GetSecret(appId)); + else + Assert.IsTrue(api.GetSecret(appId) == secret); + } + + [DataTestMethod] + [DataRow("Test2", "Test2")] + [DataRow("", "Test")] + public void TestGetEnvironment(string environment, string outEnvironment) + { + var api = new CustomConfigurationAPI(_dccSectionOptions, null); + Assert.IsTrue(api.GetEnvironment(environment) == outEnvironment); + } + + [DataTestMethod] + [DataRow("CustomCluster", "CustomCluster")] + [DataRow("", "Default")] + public void GetCluster(string cluster, string outCluster) + { + var api = new CustomConfigurationAPI(_dccSectionOptions, null); + Assert.IsTrue(api.GetCluster(cluster) == outCluster); + } + + [DataTestMethod] + [DataRow("CustomAppid", "CustomAppid")] + [DataRow("", "DccTest")] + public void GetAppid(string appId, string outAppid) + { + var api = new CustomConfigurationAPI(_dccSectionOptions, null); + Assert.IsTrue(api.GetAppid(appId) == outAppid); + } + + [DataTestMethod] + [DataRow("configObject", "configObject")] + [DataRow("", "")] + public void GetConfigObject(string configObject, string outConfigObject) + { + var api = new CustomConfigurationAPI(_dccSectionOptions, null); + if (string.IsNullOrEmpty(configObject)) + Assert.ThrowsException(() => api.GetConfigObject(configObject)); + else + Assert.IsTrue(api.GetConfigObject(configObject) == outConfigObject); + } +} + +public class CustomConfigurationAPI : ConfigurationAPIBase +{ + public CustomConfigurationAPI(DccSectionOptions defaultSectionOption, List? expandSectionOptions) : base(defaultSectionOption, expandSectionOptions) + { + } + + public string GetSecret(string appId) => base.GetSecret(appId); + + public string GetEnvironment(string environment) => base.GetEnvironment(environment); + + public string GetCluster(string cluster) => base.GetCluster(cluster); + + public string GetAppid(string appId) => base.GetAppid(appId); + + public string GetConfigObject(string configObject) => base.GetConfigObject(configObject); +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs new file mode 100644 index 000000000..52691207f --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs @@ -0,0 +1,701 @@ +using MASA.Utils.Caching.Core.Interfaces; +using MASA.Utils.Caching.Core.Models; +using MASA.Utils.Caching.DistributedMemory.Models; +using MASA.Utils.Caller.Core; +using MASA.Utils.Caller.HttpClient; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Options; + +namespace MASA.Contrib.BasicAbility.Dcc.Tests; + +[TestClass] +public class DccTest +{ + private string DEFAULT_CLIENT_NAME = "masa.plugins.caching.dcc"; + private Mock _masaConfigurationBuilder; + private JsonSerializerOptions _jsonSerializerOptions; + private IServiceCollection _services; + + private Mock _memoryCacheClientFactory; + private Mock _memoryCache; + private Mock _distributedCacheClient; + private const string DefaultEnvironmentName = "ASPNETCORE_ENVIRONMENT"; + private const string DEFAULT_SUBSCRIBE_KEY_PREFIX = "masa.dcc:"; + + [TestInitialize] + public void Initialize() + { + _masaConfigurationBuilder = new(); + _memoryCacheClientFactory = new(); + _memoryCache = new(); + _distributedCacheClient = new(); + _services = new ServiceCollection(); + _jsonSerializerOptions = new JsonSerializerOptions() + { + PropertyNameCaseInsensitive = true + }; + } + + [TestMethod] + public void TestErrorDccSection() + { + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary()).Verifiable(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(new ServiceCollection())); + } + + [TestMethod] + public void TestTryAddConfigurationAPIClient() + { + _memoryCacheClientFactory.Setup(factory => factory.CreateClient(DEFAULT_CLIENT_NAME)).Returns(() => null).Verifiable(); + _services.AddSingleton(serviceProvider => _memoryCacheClientFactory.Object); + MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), new List(), null); + Assert.IsTrue(_services.Count(service => service.ServiceType == typeof(IConfigurationAPIClient) && service.Lifetime == ServiceLifetime.Singleton) == 1); + Assert.ThrowsException(() => + { + var clienties = _services.BuildServiceProvider().GetServices(); + }); + + _services = new ServiceCollection(); + _memoryCacheClientFactory + .Setup(factory => factory.CreateClient(DEFAULT_CLIENT_NAME)) + .Returns(() => new MemoryCacheClient(_memoryCache.Object, _distributedCacheClient.Object, Utils.Caching.Core.Models.SubscribeKeyTypes.ValueTypeFullNameAndKey)) + .Verifiable(); + _services.AddSingleton(serviceProvider => _memoryCacheClientFactory.Object); + MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), new List(), new JsonSerializerOptions() + { + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + + var clienties = _services.BuildServiceProvider().GetServices(); + Assert.IsTrue(clienties.Count() == 1); + + _services = new ServiceCollection(); + _memoryCacheClientFactory + .Setup(factory => factory.CreateClient(DEFAULT_CLIENT_NAME)) + .Returns(() => new MemoryCacheClient(_memoryCache.Object, _distributedCacheClient.Object, Utils.Caching.Core.Models.SubscribeKeyTypes.ValueTypeFullNameAndKey)) + .Verifiable(); + _services.AddSingleton(serviceProvider => _memoryCacheClientFactory.Object); + MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), null, null); + MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), null, null); + clienties = _services.BuildServiceProvider().GetServices(); + Assert.IsTrue(clienties.Count() == 1); + } + + [TestMethod] + public void TestTryAddConfigurationAPIManage() + { + Mock httpClientFactory = new(); + _services.AddSingleton(httpClientFactory.Object); + _services.AddCaller(options => options.UseHttpClient()); + + MasaConfigurationExtensions.TryAddConfigurationAPIManage(_services, new DccSectionOptions(), new List()); + MasaConfigurationExtensions.TryAddConfigurationAPIManage(_services, new DccSectionOptions(), new List()); + Assert.IsTrue(_services.Count(service => service.ServiceType == typeof(IConfigurationAPIManage) && service.Lifetime == ServiceLifetime.Singleton) == 1); + var serviceProvider = _services.BuildServiceProvider(); + Assert.IsTrue(serviceProvider.GetServices().Count() == 1); + } + + [TestMethod] + public void TestUseDCCAndErrorSection() + { + _services.AddCaller(options => options.UseHttpClient()); + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary()).Verifiable(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, "", null, null), "configureOptions"); + } + + [TestMethod] + public void TestUseDCCAndNullDccConfigurationOption() + { + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => null, option => + { + option.AppId = "Test"; + option.Environment = "Test"; + option.ConfigObjects = new List() { "Te" }; + }, null), "configureOptions"); + + Initialize(); + + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, null, option => + { + option.AppId = "Test"; + option.Environment = "Test"; + option.ConfigObjects = new List() { "Te" }; + }, null), "configureOptions"); + } + + [TestMethod] + public void TestCustomCaller() + { + Mock configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), null).Result).Returns(() => ("", ConfigurationTypes.Text)); + _services.AddSingleton(configurationAPIClient.Object); + _masaConfigurationBuilder.Object.UseDCC(_services, () => new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }, option => + { + option.AppId = "Test"; + option.Environment = "Test"; + option.ConfigObjects = new List() + { + "Settings" + }; + }, null, jsonSerializerOption => + { + jsonSerializerOption.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + }, option => + { + option.UseHttpClient(builder => + { + builder.Name = "CustomHttpClient"; + builder.Configure = opt => opt.BaseAddress = new Uri("https://github.com"); + }); + }); + var callerProvider = _services.BuildServiceProvider().GetRequiredService().CreateClient("CustomHttpClient"); + Assert.IsNotNull(callerProvider); + } + + [TestMethod] + public void TestUseDCCAndEmptyDccServiceAddress() + { + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "", + }; + }, null, null), "DccServiceAddress"); + } + + [TestMethod] + public void TestUseDCCAndErrorDccService() + { + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = null + }; + }, null, null), "Servers"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + }; + }, null, null), "Servers"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host="", + Port=8080 + } + } + }; + }, null, null), "Servers"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host="localhost", + Port=-1 + } + } + }; + }, null, null), "Servers"); + } + + [TestMethod] + public void TestUseDCCAndErrorDefaultSectionOption() + { + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, null, null), "defaultSectionOptions"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = ""; + }, null), "AppId cannot be empty"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = "Test"; + option.ConfigObjects = null; + }, null), "ConfigObjects cannot be empty"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = "Test"; + option.ConfigObjects = new List(); + }, null), "ConfigObjects cannot be empty"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = "Test"; + option.ConfigObjects = new List() + { + "Brand" + }; + }, null), "Error getting environment information, please make sure the value of ASPNETCORE_ENVIRONMENT has been configured"); + } + + [TestMethod] + public void TestUseDCCAndErrorExpansionSectionOptions() + { + System.Environment.SetEnvironmentVariable(DefaultEnvironmentName, "Test"); + + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = "Test"; + option.ConfigObjects = new List() + { + "Brand" + }; + }, option => + { + option.ExpandSections = new List() + { + new DccSectionOptions() + { + AppId = "Test2", + } + }; + }), "ConfigObjects in the extension section cannot be empty"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = "Test"; + option.ConfigObjects = new List() + { + "Brand" + }; + }, option => + { + option.ExpandSections = new List() + { + new DccSectionOptions() + { + AppId = "Test2", + ConfigObjects=new List() + } + }; + }), "ConfigObjects in the extension section cannot be empty"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = "Test"; + option.ConfigObjects = new List() + { + "Brand" + }; + }, option => + { + option.ExpandSections = new List() + { + new DccSectionOptions() + { + AppId = "Test", + ConfigObjects=new List() + { + "Settings" + } + } + }; + }), "The current section already exists, no need to mount repeatedly"); + + _services = new ServiceCollection(); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = "Test"; + option.ConfigObjects = new List() + { + "Brand" + }; + }, option => + { + option.ExpandSections = new List() + { + new DccSectionOptions() + { + AppId = "Test2", + ConfigObjects=new List() + { + "Settings" + } + }, + new DccSectionOptions() + { + AppId = "Test2", + ConfigObjects=new List() + { + "Settings" + } + } + }; + }), "The current section already exists, no need to mount repeatedly"); + } + + [DataTestMethod] + [DataRow("Development", "Default", "WebApplication1", "Brand")] + public void TestUseDCCAndSuccess(string environment, string cluster, string appId, string configObject) + { + System.Environment.SetEnvironmentVariable(DefaultEnvironmentName, "Test"); + var brand = new Brands("Microsoft"); + Mock configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()).Result).Returns(() + => new(brand.Serialize(_jsonSerializerOptions), ConfigurationTypes.Json) + ).Verifiable(); + _services.AddSingleton(configurationAPIClient.Object); + _masaConfigurationBuilder.Object.UseDCC(_services, () => + { + return new DccConfigurationOptions() + { + DccServiceAddress = "https://github.com", + Servers = new List() + { + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } + } + }; + }, option => + { + option.AppId = "Test"; + option.ConfigObjects = new List() + { + "Brand" + }; + }, null); + var optionFactory = _services.BuildServiceProvider().GetRequiredService>(); + var option = optionFactory.Create(DEFAULT_CLIENT_NAME); + + Assert.IsTrue(option.SubscribeKeyType == SubscribeKeyTypes.SpecificPrefix); + + Assert.IsTrue(option.SubscribeKeyPrefix == DEFAULT_SUBSCRIBE_KEY_PREFIX); + } + + [DataTestMethod] + [DataRow("Development", "Default", "WebApplication1", "Brand")] + public void TestUseDccAndSingleSection(string environment, string cluster, string appId, string configObject) + { + CustomTrigger trigger = new CustomTrigger(_jsonSerializerOptions); + var brand = new Brands("Microsoft"); + var newBrand = new Brands("Masa"); + Mock configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()).Result).Returns(() + => new(brand.Serialize(_jsonSerializerOptions), ConfigurationTypes.Json) + ).Callback((string environment, string cluster, string appId, string configObject, Action action) => + { + trigger.Formats = ConfigFormats.Json; + trigger.Content = newBrand.Serialize(_jsonSerializerOptions); + trigger.Action = action; + }); + _services.AddSingleton(configurationAPIClient.Object); + var chainedConfiguration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", true, true); + + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary() + { + { "Appsettings",chainedConfiguration.Build() } + }).Verifiable(); + + _masaConfigurationBuilder.Object.UseDCC(_services); + configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); + trigger.Execute(); + + Initialize(); + + configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()).Result).Returns(() + => new(new Dictionary() + { + { "Id",Guid.NewGuid().ToString()}, + { "Name","Masa"} + }.Serialize(_jsonSerializerOptions), ConfigurationTypes.Properties) + ).Verifiable(); + _services.AddSingleton(configurationAPIClient.Object); + chainedConfiguration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", true, true); + + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary() + { + { "Appsettings",chainedConfiguration.Build() } + }).Verifiable(); + + _masaConfigurationBuilder.Object.UseDCC(_services); + configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); + + Initialize(); + + configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()).Result).Returns(() + => new("Test", ConfigurationTypes.Text) + ).Verifiable(); + _services.AddSingleton(configurationAPIClient.Object); + chainedConfiguration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", true, true); + + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary() + { + { "Appsettings",chainedConfiguration.Build() } + }).Verifiable(); + + _masaConfigurationBuilder.Object.UseDCC(_services); + configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); + + Initialize(); + + configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()).Result).Returns(() + => new(null, ConfigurationTypes.Text) + ).Verifiable(); + _services.AddSingleton(configurationAPIClient.Object); + chainedConfiguration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", true, true); + + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary() + { + { "Appsettings",chainedConfiguration.Build() } + }).Verifiable(); + + _masaConfigurationBuilder.Object.UseDCC(_services); + configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); + + + Initialize(); + + configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()).Result).Returns(() + => new("Test", (ConfigurationTypes)4) + ).Verifiable(); + _services.AddSingleton(configurationAPIClient.Object); + chainedConfiguration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", true, true); + + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary() + { + { "Appsettings",chainedConfiguration.Build() } + }).Verifiable(); + + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services), "configurationType"); + configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); + } + + [TestMethod] + public void TestUseDccAndExpandSections() + { + var brand = new Brands("Microsoft"); + Mock configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync("Test", "Default", "DccTest", "Test1", It.IsAny>()).Result).Returns(() + => new(brand.Serialize(_jsonSerializerOptions), ConfigurationTypes.Json) + ).Verifiable(); + configurationAPIClient.Setup(client => client.GetRawAsync("Test2", "Default", "DccTest2", "Test3", It.IsAny>()).Result).Returns(() + => new(brand.Serialize(_jsonSerializerOptions), ConfigurationTypes.Json) + ).Verifiable(); + _services.AddSingleton(configurationAPIClient.Object); + var chainedConfiguration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("expandSections.json", true, true); + + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary() + { + { "Appsettings",chainedConfiguration.Build() } + }).Verifiable(); + + _masaConfigurationBuilder.Object.UseDCC(_services); + configurationAPIClient.Verify(client => client.GetRawAsync("Test", "Default", "DccTest", "Test1", It.IsAny>()), Times.Once); + configurationAPIClient.Verify(client => client.GetRawAsync("Test2", "Default", "DccTest2", "Test3", It.IsAny>()), Times.Once); + configurationAPIClient.Verify(client => client.GetRawAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()), Times.Exactly(2)); + } + + [DataTestMethod] + [DataRow("Development", "Default", "WebApplication1", "Brand")] + public void TestUseMultiDcc(string environment, string cluster, string appId, string configObject) + { + var brand = new Brands("Microsoft"); + Mock configurationAPIClient = new(); + configurationAPIClient.Setup(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()).Result).Returns(() + => new(brand.Serialize(_jsonSerializerOptions), ConfigurationTypes.Json) + ).Verifiable(); + _services.AddSingleton(configurationAPIClient.Object); + var chainedConfiguration = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", true, true); + + _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary() + { + { "Appsettings",chainedConfiguration.Build() } + }).Verifiable(); + + _masaConfigurationBuilder.Object.UseDCC(_services).UseDCC(_services); + configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); + + var httpClient = _services.BuildServiceProvider().GetRequiredService().CreateClient(DEFAULT_CLIENT_NAME); + Assert.IsTrue(httpClient.BaseAddress!.ToString() == "http://localhost:6379/"); + } + +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Common/SerializeCommon.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Common/SerializeCommon.cs new file mode 100644 index 000000000..7f5827b59 --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Common/SerializeCommon.cs @@ -0,0 +1,7 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Tests.Internal.Common; + +internal static class SerializeCommon +{ + public static string Serialize(this object obj, JsonSerializerOptions? jsonSerializerOptions) + => JsonSerializer.Serialize(obj, jsonSerializerOptions); +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Config/Property.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Config/Property.cs new file mode 100644 index 000000000..01735427f --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Config/Property.cs @@ -0,0 +1,8 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Tests.Internal.Config; + +internal class Property +{ + public string Key { get; set; } = default!; + + public string Value { get; set; } = default!; +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Config/PublishRelease.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Config/PublishRelease.cs new file mode 100644 index 000000000..5cafa5fe5 --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Config/PublishRelease.cs @@ -0,0 +1,8 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Tests.Internal; + +internal class PublishRelease +{ + public ConfigFormats ConfigFormat { get; set; } + + public string? Content { get; set; } +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/CustomTrigger.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/CustomTrigger.cs new file mode 100644 index 000000000..93088edcc --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/CustomTrigger.cs @@ -0,0 +1,26 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Tests.Internal; + +public class CustomTrigger +{ + private JsonSerializerOptions _jsonSerializerOptions; + + public CustomTrigger(JsonSerializerOptions jsonSerializerOptions) + { + _jsonSerializerOptions = jsonSerializerOptions; + } + + internal ConfigFormats Formats { get; set; } + + internal string Content { get; set; } + + internal Action Action { get; set; } + + internal void Execute() + { + Action?.Invoke(new PublishRelease() + { + ConfigFormat = Formats, + Content = Content + }.Serialize(_jsonSerializerOptions)); + } +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Enum/ConfigFormats.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Enum/ConfigFormats.cs new file mode 100644 index 000000000..15e6e5d3b --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Enum/ConfigFormats.cs @@ -0,0 +1,8 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Tests.Internal.Enum; + +internal enum ConfigFormats +{ + Properties = 1, + Text, + Json +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Model/Brands.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Model/Brands.cs new file mode 100644 index 000000000..d394e9e06 --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/Internal/Model/Brands.cs @@ -0,0 +1,14 @@ +namespace MASA.Contrib.BasicAbility.Dcc.Tests.Internal.Model; + +internal class Brands +{ + public Guid Id { get; init; } + + public string Name { get; set; } + + public Brands() + => this.Id = Guid.NewGuid(); + + public Brands(string Name) : this() + => this.Name = Name; +} diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/MASA.Contrib.BasicAbility.Dcc.Tests.csproj b/test/MASA.Contrib.BasicAbility.Dcc.Tests/MASA.Contrib.BasicAbility.Dcc.Tests.csproj new file mode 100644 index 000000000..d1fac8015 --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/MASA.Contrib.BasicAbility.Dcc.Tests.csproj @@ -0,0 +1,36 @@ + + + + net6.0 + enable + false + enable + + + + + Always + + + Always + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/_Imports.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/_Imports.cs new file mode 100644 index 000000000..8161f76a2 --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/_Imports.cs @@ -0,0 +1,14 @@ +global using MASA.BuildingBlocks.Configuration; +global using MASA.Contrib.BasicAbility.Dcc.Options; +global using MASA.Contrib.BasicAbility.Dcc.Tests.Internal; +global using MASA.Contrib.BasicAbility.Dcc.Tests.Internal.Common; +global using MASA.Contrib.BasicAbility.Dcc.Tests.Internal.Config; +global using MASA.Contrib.BasicAbility.Dcc.Tests.Internal.Enum; +global using MASA.Contrib.BasicAbility.Dcc.Tests.Internal.Model; +global using MASA.Utils.Caching.DistributedMemory; +global using MASA.Utils.Caching.DistributedMemory.Interfaces; +global using Microsoft.Extensions.Configuration; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using Moq; +global using System.Text.Json; diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/appsettings.json b/test/MASA.Contrib.BasicAbility.Dcc.Tests/appsettings.json new file mode 100644 index 000000000..042a485d1 --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/appsettings.json @@ -0,0 +1,21 @@ +{ + "DccOptions": { + "Servers": [ + { + "Host": "localhost", + "Port": 8888 + } + ], + "DefaultDatabase": 0, + "Password": "", + "DccServiceAddress": "http://localhost:6379", + "SubscribeKeyPrefix": "masa.dcc:" + }, + "AppId": "WebApplication1", + "Environment": "Development", + "Cluster": "Default", + "ConfigObjects": [ + "Brand" + ], + "Sectet": "" +} \ No newline at end of file diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/expandSections.json b/test/MASA.Contrib.BasicAbility.Dcc.Tests/expandSections.json new file mode 100644 index 000000000..b16a77dfb --- /dev/null +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/expandSections.json @@ -0,0 +1,30 @@ +{ + "DccOptions": { + "Servers": [ + { + "Host": "localhost", + "Port": 8888 + } + ], + "DefaultDatabase": 0, + "Password": "", + "DccServiceAddress": "http://localhost:6379" + }, + "AppId": "DccTest", + "Environment": "Test", + "Cluster": "Default", + "ConfigObjects": [ + "Test1" + ], + "Sectet": "", + "ExpandSections": [ + { + "AppId": "DccTest2", + "Environment": "Test2", + "Cluster": "Default", + "ConfigObjects": [ + "Test3" + ] + } + ] +} \ No newline at end of file diff --git a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/ErrorKafkaOptions.cs b/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/ErrorKafkaOptions.cs new file mode 100644 index 000000000..52750046a --- /dev/null +++ b/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/ErrorKafkaOptions.cs @@ -0,0 +1,12 @@ +namespace MASA.Contrib.Configuration.ErrorSectionAutoMapTests; + +public class ErrorKafkaOptions : KafkaOptions +{ + [JsonIgnore] + public override string? ParentSection { get; init; } = "Appsettings"; + + public ErrorKafkaOptions() + { + base.Section = "KafkaOptions"; + } +} diff --git a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/KafkaOptions.cs b/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/KafkaOptions.cs new file mode 100644 index 000000000..3cf9ec2a2 --- /dev/null +++ b/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/KafkaOptions.cs @@ -0,0 +1,15 @@ +namespace MASA.Contrib.Configuration.ErrorSectionAutoMapTests; + +public class KafkaOptions : MasaConfigurationOptions +{ + public string Servers { get; set; } + + public int ConnectionPoolSize { get; set; } + + public override SectionTypes SectionType { get; init; } = SectionTypes.Local; + + public KafkaOptions() + { + base.ParentSection = ""; + } +} diff --git a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj b/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj new file mode 100644 index 000000000..0ddf5d6a8 --- /dev/null +++ b/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + false + enable + + + + + + + diff --git a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/_Imports.cs b/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/_Imports.cs new file mode 100644 index 000000000..ddfd0182f --- /dev/null +++ b/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/_Imports.cs @@ -0,0 +1,2 @@ +global using MASA.BuildingBlocks.Configuration; +global using System.Text.Json.Serialization; diff --git a/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj new file mode 100644 index 000000000..11cf31006 --- /dev/null +++ b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + false + enable + + + + + + + diff --git a/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MountSectionRedisOptions.cs b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MountSectionRedisOptions.cs new file mode 100644 index 000000000..3fc6f8f89 --- /dev/null +++ b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MountSectionRedisOptions.cs @@ -0,0 +1,12 @@ +namespace MASA.Contrib.Configuration.MountErrorSectionAutoMapTests; + +public class MountSectionRedisOptions : MasaConfigurationOptions +{ + [JsonIgnore] + public override string? ParentSection { get; init; } = "Appsettings"; + + [JsonIgnore] + public override string? Section { get; init; } = null; + + public override SectionTypes SectionType { get; init; } = SectionTypes.ConfigurationAPI; +} diff --git a/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/_Imports.cs b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/_Imports.cs new file mode 100644 index 000000000..ddfd0182f --- /dev/null +++ b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/_Imports.cs @@ -0,0 +1,2 @@ +global using MASA.BuildingBlocks.Configuration; +global using System.Text.Json.Serialization; diff --git a/test/MASA.Contrib.Configuration.Tests/Config/RabbitMqOptions.cs b/test/MASA.Contrib.Configuration.Tests/Config/RabbitMqOptions.cs new file mode 100644 index 000000000..3bbcc3a4d --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/Config/RabbitMqOptions.cs @@ -0,0 +1,16 @@ +namespace MASA.Contrib.Configuration.Tests.Config; + +public class RabbitMqOptions : MasaConfigurationOptions +{ + public string HostName { get; set; } + + public string UserName { get; set; } + + public string Password { get; set; } + + public string VirtualHost { get; set; } + + public string Port { get; set; } + + public override SectionTypes SectionType { get; init; } = SectionTypes.Local; +} diff --git a/test/MASA.Contrib.Configuration.Tests/Config/RedisOptions.cs b/test/MASA.Contrib.Configuration.Tests/Config/RedisOptions.cs new file mode 100644 index 000000000..3fe96cb56 --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/Config/RedisOptions.cs @@ -0,0 +1,10 @@ +namespace MASA.Contrib.Configuration.Tests.Config; + +public class RedisOptions +{ + public string Ip { get; set; } + + public string Password { get; set; } + + public int Port { get; set; } +} diff --git a/test/MASA.Contrib.Configuration.Tests/Config/SystemOptions.cs b/test/MASA.Contrib.Configuration.Tests/Config/SystemOptions.cs new file mode 100644 index 000000000..39f32fa84 --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/Config/SystemOptions.cs @@ -0,0 +1,14 @@ +namespace MASA.Contrib.Configuration.Tests.Config; + +public class SystemOptions : MasaConfigurationOptions +{ + [JsonIgnore] + public override string? ParentSection { get; init; } = "Appsettings"; + + [JsonIgnore] + public override string? Section { get; init; } = null; + + public override SectionTypes SectionType { get; init; } = SectionTypes.Local; + + public string? Name { get; set; } +} diff --git a/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs b/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs new file mode 100644 index 000000000..95555d15c --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs @@ -0,0 +1,295 @@ +using MASA.Contrib.Configuration.ErrorSectionAutoMapTests; +using MASA.Contrib.Configuration.MountErrorSectionAutoMapTests; + +namespace MASA.Contrib.Configuration.Tests; + +[TestClass] +public class ConfigurationTest +{ + private IConfigurationBuilder _configurationBuilder; + + [TestInitialize] + public void Initialize() + { + _configurationBuilder = new ConfigurationBuilder(); + } + + [TestMethod] + public void TestAddSection() + { + var masaConfigurationBuilder = new MasaConfigurationBuilder(_configurationBuilder); + Assert.ThrowsException(() => masaConfigurationBuilder.AddSection(null)); + + Assert.ThrowsException(() => masaConfigurationBuilder.AddSection(new ConfigurationBuilder())); + + masaConfigurationBuilder.AddSection( + new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", true, true), "appsettings" + ); + + Assert.IsTrue(masaConfigurationBuilder.GetSectionRelations().Count == 1); + + masaConfigurationBuilder.AddSection( + new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("redis.json", true, true) + ); + Assert.IsTrue(masaConfigurationBuilder.GetSectionRelations().Count == 2); + + Assert.ThrowsException(() => + { + masaConfigurationBuilder.AddSection( + new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("rabbitMq.json", true, true) + ); + }); + } + + [TestMethod] + public void TestAddCustomSection() + { + var builder = WebApplication.CreateBuilder(); + builder.AddMasaConfiguration(configurationBuilder => + { + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true), "Appsettings"); + + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("redis.json", true, true), "RedisOptions"); + + configurationBuilder.AddSection( + new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("rabbitMq.json", true, true), "RabbitMqOptions" + ); + + configurationBuilder.UseMasaOptions(option => + { + option.Mapping(SectionTypes.Local, ""); + }); + }); + var serviceProvider = builder.Services.BuildServiceProvider(); + var configuration = serviceProvider.GetRequiredService(); + var redisOption = serviceProvider.GetRequiredService>(); + + Assert.IsNotNull(configuration); + Assert.IsNotNull(redisOption); + Assert.IsTrue(redisOption.Value.Ip == "localhost"); + } + + [TestMethod] + public void TestAddMasaConfiguration() + { + var builder = WebApplication.CreateBuilder(); + builder.AddMasaConfiguration(configurationBuilder => + { + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true), "Appsettings"); + + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("redis.json", true, true) + ); + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("rabbitMq.json", true, true), "RabbitMqOptions" + ); + configurationBuilder.UseMasaOptions(option => + option.Mapping(SectionTypes.Local, "", "") + ); + }); + var serviceProvider = builder.Services.BuildServiceProvider(); + var configuration = serviceProvider.GetRequiredService(); + var redisOption = serviceProvider.GetRequiredService>(); + Assert.IsTrue(configuration["Local:Ip"] == "localhost"); + Assert.IsTrue(redisOption.Value.Ip == "localhost"); + + var rabbitMqOption = serviceProvider.GetRequiredService>(); + Assert.IsTrue(configuration["Local:RabbitMqOptions:UserName"] == "admin"); + Assert.IsTrue(rabbitMqOption.Value.UserName == "admin" && rabbitMqOption.Value.Password == "admin"); + } + + [TestMethod] + public void TestAddMultiMasaConfiguration() + { + var builder = WebApplication.CreateBuilder(); + builder.AddMasaConfiguration(configurationBuilder => + { + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true), "Appsettings"); + + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("redis.json", true, true) + ); + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("rabbitMq.json", true, true), "RabbitMqOptions" + ); + configurationBuilder.UseMasaOptions(option => + option.Mapping(SectionTypes.Local, "", "") + ); + }).AddMasaConfiguration(); + var serviceProvider = builder.Services.BuildServiceProvider(); + var configuration = serviceProvider.GetRequiredService(); + var redisOption = serviceProvider.GetRequiredService>(); + Assert.IsTrue(configuration["Local:Ip"] == "localhost"); + Assert.IsTrue(redisOption.Value.Ip == "localhost"); + + var rabbitMqOption = serviceProvider.GetRequiredService>(); + Assert.IsTrue(configuration["Local:RabbitMqOptions:UserName"] == "admin"); + Assert.IsTrue(rabbitMqOption.Value.UserName == "admin" && rabbitMqOption.Value.Password == "admin"); + } + + [TestMethod] + public void TestAutoMapSectionError() + { + var builder = WebApplication.CreateBuilder(); + builder.Host.ConfigureAppConfiguration((context, config) => { config.Sources.Clear(); }); + var chainedConfiguration = new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true); + builder.Configuration.AddConfiguration(chainedConfiguration.Build()); + + Assert.ThrowsException(() => + builder.AddMasaConfiguration(configurationBuilder => + { + configurationBuilder.AddSection( + new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true), "Appsettings" + ); + }, typeof(ConfigurationTest).Assembly, typeof(KafkaOptions).Assembly)); + } + + [TestMethod] + public void TestAutoMapAndErrorSection() + { + var builder = WebApplication.CreateBuilder(); + Assert.ThrowsException(() => + { + return builder.AddMasaConfiguration(configurationBuilder => + { + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("appsettings.json", true, true), "Appsettings" + ); + + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("redis.json", true, true) + ); //Mount to the Local section + }, typeof(ConfigurationTest).Assembly, typeof(MountSectionRedisOptions).Assembly); + }); + } + + [TestMethod] + public void TestRepeatMappting() + { + var builder = WebApplication.CreateBuilder(); + Assert.ThrowsException(() => + { + builder.AddMasaConfiguration(configurationBuilder => + { + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("redis.json", true, true) + ); + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("rabbitMq.json", true, true), "RabbitMqOptions" + ); + configurationBuilder.UseMasaOptions(option => + { + option.Mapping(SectionTypes.Local, "", ""); + option.Mapping(SectionTypes.Local, "", ""); + }); + }); + }); + } + + [TestMethod] + public void TestCreateMasaConfiguration() + { + var services = new ServiceCollection(); + services.CreateMasaConfiguration(configurationBuilder => + { + configurationBuilder.AddSection( + new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("redis.json", true, true) + ); + configurationBuilder.AddSection( + new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("rabbitMq.json", true, true), "RabbitMqOptions" + ); + configurationBuilder.UseMasaOptions(option => + option.Mapping(SectionTypes.Local, "", "") + ); + }, new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", true, true), "Appsettings"); + IServiceProvider serviceProvider = services.BuildServiceProvider(); + var redisOption = serviceProvider.GetRequiredService>(); + Assert.IsTrue(redisOption.Value.Ip == "localhost"); + } + + [TestMethod] + public void TestNullSection() + { + var services = new ServiceCollection(); + var ex = Assert.ThrowsException(() => services.CreateMasaConfiguration(null)); + Assert.IsTrue(ex.Message == "Please add the section to be loaded"); + } + + [TestMethod] + public void TestConfigurationChange() + { + var builder = WebApplication.CreateBuilder(); + + var rootPath = builder.Environment.ContentRootPath; + builder.AddMasaConfiguration(configurationBuilder => + { + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(rootPath) + .AddJsonFile("appsettings.json", true, true), "Appsettings"); + + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(rootPath) + .AddJsonFile("redis.json", true, true), "RedisOptions"); + + configurationBuilder.AddSection(new ConfigurationBuilder() + .SetBasePath(rootPath) + .AddJsonFile("rabbitMq.json", true, true), "RabbitMqOptions" + ); + + configurationBuilder.UseMasaOptions(option => + { + option.Mapping(SectionTypes.Local, ""); + }); + }, typeof(ConfigurationTest).Assembly); + var serviceProvider = builder.Services.BuildServiceProvider(); + var configuration = serviceProvider.GetRequiredService(); + var systemOption = serviceProvider.GetRequiredService>(); + + Assert.IsNotNull(configuration); + Assert.IsNotNull(systemOption); + Assert.IsTrue(systemOption.Value.Name == "MASA TEST"); + + var newRedisOption = systemOption.Value; + newRedisOption.Name = null; + + File.WriteAllText(Path.Combine(rootPath, "appsettings.json"), System.Text.Json.JsonSerializer.Serialize(new { SystemOptions = newRedisOption })); + + Thread.Sleep(2000); + var option = serviceProvider.GetRequiredService>(); + Assert.IsTrue(option.CurrentValue.Name == ""); + } +} diff --git a/test/MASA.Contrib.Configuration.Tests/MASA.Contrib.Configuration.Tests.csproj b/test/MASA.Contrib.Configuration.Tests/MASA.Contrib.Configuration.Tests.csproj new file mode 100644 index 000000000..b45547eb3 --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/MASA.Contrib.Configuration.Tests.csproj @@ -0,0 +1,43 @@ + + + + net6.0 + enable + false + enable + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + Always + + + + Always + + + + Always + + + + diff --git a/test/MASA.Contrib.Configuration.Tests/_Imports.cs b/test/MASA.Contrib.Configuration.Tests/_Imports.cs new file mode 100644 index 000000000..96c264dae --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/_Imports.cs @@ -0,0 +1,8 @@ +global using MASA.BuildingBlocks.Configuration; +global using MASA.Contrib.Configuration.Tests.Config; +global using Microsoft.AspNetCore.Builder; +global using Microsoft.Extensions.Configuration; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Options; +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using System.Text.Json.Serialization; diff --git a/test/MASA.Contrib.Configuration.Tests/appsettings.json b/test/MASA.Contrib.Configuration.Tests/appsettings.json new file mode 100644 index 000000000..9c1279ff5 --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/appsettings.json @@ -0,0 +1,9 @@ +{ + "KafkaOptions": { + "Servers": "Kafka Server", + "int": 10 + }, + "SystemOptions": { + "Name": "MASA TEST" + } +} \ No newline at end of file diff --git a/test/MASA.Contrib.Configuration.Tests/rabbitMq.json b/test/MASA.Contrib.Configuration.Tests/rabbitMq.json new file mode 100644 index 000000000..cbff2c19a --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/rabbitMq.json @@ -0,0 +1,7 @@ +{ + "HostName": "localhost", + "UserName": "admin", + "Password": "admin", + "VirtualHost": "/", + "Port": 5672 +} \ No newline at end of file diff --git a/test/MASA.Contrib.Configuration.Tests/redis.json b/test/MASA.Contrib.Configuration.Tests/redis.json new file mode 100644 index 000000000..ebce8f626 --- /dev/null +++ b/test/MASA.Contrib.Configuration.Tests/redis.json @@ -0,0 +1,5 @@ +{ + "Ip": "localhost", + "Password": "", + "Port": 6379 +} \ No newline at end of file diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/Courses.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/Courses.cs new file mode 100644 index 000000000..cca8d48e7 --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/Courses.cs @@ -0,0 +1,19 @@ +namespace MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests; + +public class Courses : AggregateRoot +{ + public Courses() + { + Id = Guid.NewGuid(); + } + + public Guid Id { get; init; } + + public string Name { get; set; } + + public override IEnumerable<(string Name, object Value)> GetKeys() + => new List<(string Name, object Value)>() + { + ("Names",Name)//Demonstrate that a non-existent key is used as a joint primary key + }; +} diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj new file mode 100644 index 000000000..9dc08646c --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + false + enable + + + + + + + diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/_Imports.cs new file mode 100644 index 000000000..d6a2a9e7d --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/_Imports.cs @@ -0,0 +1 @@ +global using MASA.BuildingBlocks.DDD.Domain.Entities; diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj new file mode 100644 index 000000000..9dc08646c --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + false + enable + + + + + + + diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/Students.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/Students.cs new file mode 100644 index 000000000..490334645 --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/Students.cs @@ -0,0 +1,28 @@ +namespace MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests; + +public class Students : AggregateRoot +{ + public Students() + { + RegisterTime = DateTime.UtcNow; + } + + public string SerialNumber { get; set; } = default!; + + public string Name { get; set; } + + public int Age { get; set; } + + public DateTime RegisterTime { get; private set; } + + /// + /// Test the case of the joint primary key error, no business value + /// + /// + public override IEnumerable<(string Name, object Value)> GetKeys() + => new List<(string Name, object Value)>() + { + ("SerialNumber", SerialNumber), + ("","") + }; +} diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/_Imports.cs new file mode 100644 index 000000000..d6a2a9e7d --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/_Imports.cs @@ -0,0 +1 @@ +global using MASA.BuildingBlocks.DDD.Domain.Entities; diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj index 1f9d41356..453ed369c 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj @@ -4,6 +4,7 @@ net6.0 enable enable + false diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/Hobbies.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/Hobbies.cs new file mode 100644 index 000000000..27a0c0427 --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/Hobbies.cs @@ -0,0 +1,16 @@ +namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Entities; + +public class Hobbies : AggregateRoot +{ + public string Name { get; private set; } + + private Hobbies() + { + this.Id = Guid.NewGuid(); + } + + public Hobbies(string name) : this() + { + this.Name = name; + } +} diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj new file mode 100644 index 000000000..9f97c3017 --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + false + enable + + + + + + + diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/_Imports.cs new file mode 100644 index 000000000..d6a2a9e7d --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/_Imports.cs @@ -0,0 +1 @@ +global using MASA.BuildingBlocks.DDD.Domain.Entities; diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/BaseRepositoryTest.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/BaseRepositoryTest.cs new file mode 100644 index 000000000..b09128716 --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/BaseRepositoryTest.cs @@ -0,0 +1,78 @@ +namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests; + +[TestClass] +public class BaseRepositoryTest : TestBase +{ + private IServiceCollection _services = default!; + private Assembly[] _assemblies; + private Mock _uoW; + private Mock _dispatcherOptions = default!; + + [TestInitialize] + public void Initialize() + { + _services = new ServiceCollection(); + _assemblies = new Assembly[1] + { + typeof(BaseRepositoryTest).Assembly + }; + _uoW = new(); + _dispatcherOptions = new(); + _dispatcherOptions.Setup(options => options.Services).Returns(() => _services); + } + + [TestMethod] + public void TestNullServices() + { + Assert.ThrowsException(() => + { + _dispatcherOptions.Setup(options => options.Services).Returns(() => null); + var options = _dispatcherOptions.Object.UseRepository(); + }); + } + + [TestMethod] + public void TestUseCustomRepositoryAndNotImplementation() + { + Mock uoW = new(); + _services.AddScoped(serviceProvider => uoW.Object); + + Assert.ThrowsException(() + => _dispatcherOptions.Object.UseRepository(typeof(TestBase).Assembly, typeof(IUserRepository).Assembly) + ); + } + + [TestMethod] + public void TestNullUnitOfWork() + { + var ex = Assert.ThrowsException(() => + { + _dispatcherOptions.Object.UseRepository(_assemblies); + }); + Assert.IsTrue(ex.Message == "Please add UoW first."); + } + + [TestMethod] + public void TestNullAssembly() + { + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection)); + + Assert.ThrowsException(() => + { + _dispatcherOptions.Object.UseRepository(null); + }); + } + + [TestMethod] + public void TestAddMultRepository() + { + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection)); + _dispatcherOptions.Object.UseRepository(_assemblies).UseRepository(); + + var serviceProvider = _services.BuildServiceProvider(); + var repository = serviceProvider.GetServices>(); + Assert.IsTrue(repository.Count() == 1); + } +} diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Entities/Orders.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Entities/Orders.cs index 0ed2dada2..09fed6f3c 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Entities/Orders.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Entities/Orders.cs @@ -1,19 +1,40 @@ namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Entities; -public class Orders : AuditAggregateRoot +public class Orders : AuditAggregateRoot { public int OrderNumber { get; set; } - public DateTime OrderDate { get; set; } + public DateTime OrderDate { get; private set; } - public string OrderStatus { get; set; } + public string OrderStatus { get; private set; } - public string Description { get; set; } - - public string BuyerId { get; set; } - - public string BuyerName { get; set; } + public string Description { get; set; } = default!; public List OrderItems { get; set; } + + public Orders() + { + this.OrderDate = DateTime.UtcNow; + this.OrderItems = new(); + this.OrderStatus = "Submitted"; + } + + public Orders(int id) : this() + { + base.Id = id; + } + + /// + /// Joint primary key, when this method does not exist, the primary key is Id + /// + /// + public override IEnumerable<(string Name, object Value)> GetKeys() + { + return new List<(string Name, object value)> + { + ("Id", Id), + ("OrderNumber", OrderNumber) + }; + } } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Repositories/IOrderRepository.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Repositories/IOrderRepository.cs index 39f509ad2..03d6adba4 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Repositories/IOrderRepository.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Repositories/IOrderRepository.cs @@ -2,4 +2,5 @@ namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Repositories; public interface IOrderRepository : IRepository { + Task AddAsync(Orders order); } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/CustomDbContext.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/CustomDbContext.cs new file mode 100644 index 000000000..31e12e8cd --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/CustomDbContext.cs @@ -0,0 +1,23 @@ +namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure; + +public class CustomDbContext : DbContext +{ + public DbSet Orders { get; set; } + + public DbSet Students { get; set; } + + public DbSet Courses { get; set; } + + public DbSet Hobbies { get; set; } + + public CustomDbContext(DbContextOptions options) : base(options) { } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity( + entityTypeBuilder => + { + entityTypeBuilder.HasKey("SerialNumber"); + }); + } +} diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Options/DispatcherOptions.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Options/DispatcherOptions.cs deleted file mode 100644 index 1aadc3d55..000000000 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Options/DispatcherOptions.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure.Options; - -public class DispatcherOptions : IDispatcherOptions -{ - public IServiceCollection Services { get; } - - public DispatcherOptions(IServiceCollection services) => Services = services; -} diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/OrderDbContext.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/OrderDbContext.cs deleted file mode 100644 index 09ca126e4..000000000 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/OrderDbContext.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure; - -public class OrderDbContext : DbContext -{ - public OrderDbContext(DbContextOptions options) : base(options) { } - - public DbSet Orders { get; set; } -} diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Repositories/OrderRepository.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Repositories/OrderRepository.cs index 498158cc6..176bef55e 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Repositories/OrderRepository.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Repositories/OrderRepository.cs @@ -1,8 +1,23 @@ namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure.Repositories; -public class OrderRepository : Repository, IOrderRepository +public class OrderRepository : Repository, IOrderRepository { - public OrderRepository(OrderDbContext context, IUnitOfWork unitOfWork) : base(context, unitOfWork) + public OrderRepository(CustomDbContext context, IUnitOfWork unitOfWork) : base(context, unitOfWork) { } + + public async Task AddAsync(Orders order) + { + try + { + var transaction = base.Transaction; + await base.AddAsync(order, default); + await base.SaveChangesAsync(); + await base.CommitAsync(); + } + catch (Exception ex) + { + await base.RollbackAsync(); + } + } } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj index 2ff0d55c2..abd64b60d 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj @@ -3,22 +3,29 @@ net6.0 enable - false + enable + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + + + + diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs index d382568dd..42dec62e5 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs @@ -3,80 +3,273 @@ namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests; [TestClass] public class RepositoryTest : TestBase { - private readonly Assembly[] _assemblies; + private IServiceCollection _services = default!; + private Assembly[] _assemblies; + private Mock _uoW; + private Mock _dispatcherOptions = default!; - public RepositoryTest() + [TestInitialize] + public void Initialize() { + _services = new ServiceCollection(); _assemblies = new Assembly[1] { - typeof(RepositoryTest).Assembly + typeof(BaseRepositoryTest).Assembly }; + _uoW = new(); + _dispatcherOptions = new(); + _dispatcherOptions.Setup(options => options.Services).Returns(() => _services); + } [TestMethod] - public void TestNoServices() + public async Task TestAsync() { - Assert.ThrowsException(() => + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection)); + _dispatcherOptions.Object.UseRepository(_assemblies); + + var serviceProvider = _services.BuildServiceProvider(); + + _uoW.Setup(u => u.SaveChangesAsync(default)).Callback(() => + { + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + dbContext.SaveChanges(); + }); + _uoW.Setup(u => u.CommitAsync(default)).Verifiable(); + var orders = new List() + { + new Orders(1) + { + OrderNumber = 9999999, + Description = "Apple", + }, + new Orders(2) + { + OrderNumber = 9999999, + Description = "Apple2", + } + }; + + var repository = serviceProvider.GetRequiredService>(); + await repository.AddRangeAsync(orders); + await repository.UnitOfWork.SaveChangesAsync(); + + var orderList = await repository.GetListAsync(order => order.OrderNumber == 9999999, default); + Assert.IsNotNull(orderList); + Assert.IsTrue(orderList.Count() == 2); + + Assert.IsTrue((await repository.GetListAsync(order => order.Description == "Apple", default)).Count() == 1); + Assert.IsTrue(await repository.GetCountAsync(order => order.Description == "Apple", default) == 1); + + var huaweiOrder = await repository.FindAsync(order => order.Description == "Apple2"); + huaweiOrder!.Description = "HuaWei"; + huaweiOrder.OrderNumber = 9999998; + await repository.UnitOfWork.SaveChangesAsync(default); + + Assert.IsTrue((await repository.GetListAsync(order => order.Description == "Apple", default)).Count() == 1); + Assert.IsTrue(await repository.GetCountAsync(order => order.Description == "HuaWei", default) == 1); + + await repository.AddAsync(new Orders(3) + { + OrderNumber = 9999997, + Description = "Google" + }); + await repository.AddAsync(new Orders(4) { - var options = new DispatcherOptions(null).UseRepository(); + OrderNumber = 9999996, + Description = "Microsoft" }); + + await repository.RemoveAsync(order => order.Description == "Apple", default); + await repository.UnitOfWork.SaveChangesAsync(default); + + var list = await repository.GetPaginatedListAsync(0, 10, "desc", default); + + Assert.IsTrue(list.Count == 3); + Assert.IsTrue(list[0].Description == "Microsoft"); + Assert.IsTrue(list[1].Description == "Google"); + + list = await repository.GetPaginatedListAsync(1, 10, null, default); + Assert.IsTrue(list.Count == 2); + Assert.IsTrue(list[0].Description == "Google"); + Assert.IsTrue(list[1].Description == "Microsoft"); + + list = await repository.GetPaginatedListAsync(order => order.Description != "Google", 0, 10, null, default); + Assert.IsTrue(list.Count == 2); + Assert.IsTrue(list[0].Description == "HuaWei"); + + var count = await repository.GetCountAsync(default); + Assert.IsTrue(count == 3); + + var huaWei = await repository.FindAsync(huaweiOrder.Id); + await repository.RemoveAsync(huaWei!, default); + + await repository.UnitOfWork.SaveChangesAsync(default); + Assert.IsTrue(await repository.GetCountAsync(default) == 2); + + var remainingOrders = await repository.GetListAsync(default); + await repository.RemoveRangeAsync(remainingOrders); + await repository.UnitOfWork.SaveChangesAsync(default); + + Assert.IsTrue(await repository.GetCountAsync(default) == 0); } [TestMethod] - public void TestUseCustomRepositoryAndNotImplementation() + public async Task TestTranscationFailedAsync() { - var services = new ServiceCollection(); + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection)); + _dispatcherOptions.Object.UseRepository(_assemblies); - Mock uoW = new(); - services.AddScoped(serviceProvider => uoW.Object); + var serviceProvider = _services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + dbContext.Database.BeginTransaction(); + + _uoW.Setup(u => u.SaveChangesAsync(default)).Callback(() => + { + dbContext.SaveChanges(); + }); + _uoW.Setup(u => u.CommitAsync(default)).Callback(() => + { + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.CurrentTransaction!.Commit(); + }); + _uoW.Setup(u => u.RollbackAsync(default)).Callback(() => + { + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.CurrentTransaction!.RollbackAsync(); + }); + var repository = serviceProvider.GetRequiredService(); - Assert.ThrowsException(() => new DispatcherOptions(services).UseRepository(typeof(TestBase).Assembly, typeof(IUserRepository).Assembly)); + var order = new Orders() + { + OrderNumber = 1, + }; + await repository.AddAsync(order); + Assert.IsTrue(await repository.GetCountAsync(default) == 0); } [TestMethod] - public void TestNoUnitOfWorkAssembly() + public async Task TestTranscationSucceededAsync() { - Assert.ThrowsException(() => + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection)); + _dispatcherOptions.Object.UseRepository(_assemblies); + + var serviceProvider = _services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + + _uoW.Setup(u => u.SaveChangesAsync(default)).Callback(() => + { + dbContext.SaveChanges(); + }); + _uoW.Setup(u => u.CommitAsync(default)).Callback(() => + { + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.CurrentTransaction!.Commit(); + }); + _uoW.Setup(u => u.RollbackAsync(default)).Callback(() => { - var serviceProvider = base.CreateServiceProvider(null, _assemblies); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.CurrentTransaction!.RollbackAsync(); }); + var repository = serviceProvider.GetRequiredService(); + + var order = new Orders(1) + { + OrderNumber = 1, + Description = "Apple" + }; + await repository.AddAsync(order); + Assert.IsTrue(await repository.GetCountAsync(default) == 1); } [TestMethod] - public void TestNullAssembly() + public async Task TestUpdateAsync() { - var serviceProvider = base.CreateDefaultServiceProvider(null)!; - var repository = serviceProvider.GetRequiredService>(); - Assert.IsNotNull(repository); - repository.AddAsync(new Orders() + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)); + _dispatcherOptions.Object.UseRepository(_assemblies); + + var serviceProvider = _services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + + _uoW.Setup(u => u.SaveChangesAsync(default)).Callback(() => { - BuyerName = "lisa" + dbContext.SaveChanges(); }); + var repository = serviceProvider.GetRequiredService(); + + var order = new Orders(1) + { + OrderNumber = 1, + Description = "Apple" + }; + await repository.AddAsync(order, default); + await repository.UnitOfWork.SaveChangesAsync(default); + dbContext.Entry(order).State = EntityState.Detached; + + order = await repository.FindAsync(order => order.Description == "Apple"); + order!.Description = "Apple Company"; + await repository.UnitOfWork.SaveChangesAsync(); + + order = await repository.FindAsync(order => order.Description == "Apple"); + Assert.IsNotNull(order); + + await repository.UpdateAsync(order, default); + await repository.UnitOfWork.SaveChangesAsync(); + dbContext.Entry(order).State = EntityState.Detached; + Assert.IsTrue(await repository.GetCountAsync(default) == 1); + + order = await repository.FindAsync(order => order.Description == "Apple"); + Assert.IsNotNull(order); + + order.Description = "Apple Company"; + await repository.UpdateRangeAsync(new List() { order }, default); + await repository.UnitOfWork.SaveChangesAsync(); + + dbContext.Entry(order).State = EntityState.Detached; + + order = await repository.FindAsync(order => order.Description == "Apple"); + Assert.IsNull(order); } [TestMethod] - public void TestCustomRepository() + public void TestCompositeKeys() { - var serviceProvider = base.CreateDefaultServiceProvider(_assemblies)!; - IOrderRepository orderRepository = serviceProvider.GetRequiredService(); - Assert.IsNotNull(orderRepository); - orderRepository.AddAsync(new Orders() + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection)); + Assert.ThrowsException(() => { - BuyerName = "lisa" + _dispatcherOptions.Object.UseRepository(typeof(BaseRepositoryTest).Assembly, typeof(Students).Assembly); }); } [TestMethod] - public void TestAddMultRepository() + public void TestErrorCompositeKeys() { - var services = new ServiceCollection(); - Mock unitOfWork = new(); - services.AddScoped(typeof(IUnitOfWork), serviceProvider => unitOfWork.Object); - services.AddDbContext(options => options.UseSqlite(_connection)); - new DispatcherOptions(services).UseRepository(_assemblies).UseRepository(_assemblies); - - var serviceProvider = services.BuildServiceProvider(); - var repository = serviceProvider.GetServices>(); - Assert.IsTrue(repository.Count() == 1); + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection)); + Assert.ThrowsException(() => + { + _dispatcherOptions.Object.UseRepository(typeof(BaseRepositoryTest).Assembly, typeof(Courses).Assembly); + }); + } + + [TestMethod] + public void TestErrorEntity() + { + _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); + _services.AddDbContext(options => options.UseSqlite(_connection)); + + Assert.ThrowsException(() => + { + _dispatcherOptions.Object.UseRepository(typeof(BaseRepositoryTest).Assembly, typeof(Hobbies).Assembly); + }); } } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/TestBase.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/TestBase.cs index a99971ce8..574d3fdd8 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/TestBase.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/TestBase.cs @@ -1,6 +1,6 @@ namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests; -public class TestBase +public class TestBase : IDisposable { protected readonly SqliteConnection _connection; @@ -14,24 +14,4 @@ public void Dispose() { _connection.Close(); } - - - protected IServiceProvider CreateDefaultServiceProvider(params Assembly[] assemblies) - { - return CreateServiceProvider(services => - { - Mock unitOfWork = new(); - services.AddScoped(typeof(IUnitOfWork), serviceProvider => unitOfWork.Object); - services.AddDbContext(options => options.UseSqlite(_connection)); - }, assemblies); - } - - protected IServiceProvider CreateServiceProvider(Action? action, params Assembly[] assemblies) - { - var services = new ServiceCollection(); - action?.Invoke(services); - - new DispatcherOptions(services).UseRepository(assemblies); - return services.BuildServiceProvider(); - } } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs index 08bc80fd4..0fb87a53e 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs @@ -4,11 +4,12 @@ global using MASA.BuildingBlocks.DDD.Domain.Repositories; global using MASA.BuildingBlocks.DDD.Domain.Values; global using MASA.BuildingBlocks.Dispatcher.Events; +global using MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests; +global using MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests; global using MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Repositories; global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Entities; global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Repositories; global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure; -global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure.Options; global using Microsoft.Data.Sqlite; global using Microsoft.EntityFrameworkCore; global using Microsoft.Extensions.DependencyInjection; diff --git a/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs b/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs index 9f4ced875..9f0a8a30a 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs +++ b/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs @@ -1,94 +1,129 @@ namespace MASA.Contrib.DDD.Domain.Tests; [TestClass] -public class DomainEventBusTest : TestBase +public class DomainEventBusTest { + private Assembly[] _defaultAssemblies = default!; + private IServiceCollection _services = default!; + private Mock _eventBus = default!; + private Mock _integrationEventBus = default!; + private Mock _uoW = default!; + private IOptions _dispatcherOptions = default!; + + [TestInitialize] + public void Initialize() + { + _defaultAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + _services = new ServiceCollection(); + _eventBus = new(); + _integrationEventBus = new(); + _uoW = new(); + _dispatcherOptions = Options.Create(new DispatcherOptions(new ServiceCollection())); + } + + [TestMethod] + public void TestGetAllEventTypes() + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + var eventTypes = assemblies.SelectMany(assembly => assembly.GetTypes()) + .Where(type => type.IsClass && typeof(IEvent).IsAssignableFrom(type)); + _eventBus.Setup(eventBus => eventBus.GetAllEventTypes()).Returns(() => eventTypes); + _dispatcherOptions.Value.Assemblies = _defaultAssemblies; + var domainEventBus = new DomainEventBus(_eventBus.Object, _integrationEventBus.Object, _uoW.Object, _dispatcherOptions); + + Assert.IsTrue(domainEventBus.GetAllEventTypes().Count() == eventTypes.Count(), ""); + } + [TestMethod] public async Task TestPublishDomainEventAsync() { - PaymentSucceededDomainEvent @event = new PaymentSucceededDomainEvent() + var domainEventBus = new DomainEventBus(_eventBus.Object, _integrationEventBus.Object, _uoW.Object, _dispatcherOptions); + _eventBus.Setup(eventBus => eventBus.PublishAsync(It.IsAny())).Verifiable(); + + var domainEvent = new PaymentSucceededDomainEvent() { OrderId = new Random().Next(10000, 1000000).ToString() }; - var serviceProvider = CreateDefaultProvider(); - var eventBus = serviceProvider.GetRequiredService(); - await eventBus.PublishAsync(@event); + await domainEventBus.PublishAsync(domainEvent); - Assert.IsTrue(eventBus.GetAllEventTypes().Count() == 5); + _eventBus.Verify(eventBus => eventBus.PublishAsync(domainEvent), Times.Once, "PublishAsync is executed multiple times"); + _integrationEventBus.Verify(integrationEventBus => integrationEventBus.PublishAsync(domainEvent), Times.Never, "integrationEventBus should not be executed"); + Assert.IsTrue(domainEvent.UnitOfWork.Equals(_uoW.Object)); } [TestMethod] public async Task TestPublishIntegrationDomainEventAsync() { - PaymentFailedIntegrationDomainEvent @event = new PaymentFailedIntegrationDomainEvent() + var domainEventBus = new DomainEventBus(_eventBus.Object, _integrationEventBus.Object, _uoW.Object, _dispatcherOptions); + _integrationEventBus.Setup(integrationEventBus => integrationEventBus.PublishAsync(It.IsAny())).Verifiable(); + var integrationDomainEvent = new PaymentFailedIntegrationDomainEvent() { OrderId = new Random().Next(10000, 1000000).ToString() }; - var serviceProvider = CreateDefaultProvider(); - var eventBus = serviceProvider.GetRequiredService(); - await eventBus.PublishAsync(@event); + await domainEventBus.PublishAsync(integrationDomainEvent); + + _eventBus.Verify(eventBus => eventBus.PublishAsync(integrationDomainEvent), Times.Never, "eventBus should not be executed"); + _integrationEventBus.Verify(integrationEventBus => integrationEventBus.PublishAsync(integrationDomainEvent), Times.Once, " PublishAsync is executed multiple times"); } [TestMethod] public async Task TestPublishDomainCommandAsync() { + _uoW.Setup(u => u.CommitAsync(default)).Verifiable(); + var domainEventBus = new DomainEventBus(_eventBus.Object, _integrationEventBus.Object, _uoW.Object, _dispatcherOptions); + _eventBus.Setup(eventBus => eventBus.PublishAsync(It.IsAny())) + .Callback((domainEvent) => + { + Mock> userRepository = new(); + var user = new Users() + { + Name = "Jim" + }; + userRepository.Setup(repository => repository.AddAsync(It.IsAny(), CancellationToken.None)).Verifiable(); + domainEvent.UnitOfWork.CommitAsync(); + }); + var @command = new CreateProductDomainCommand() { Name = "Phone" }; + await domainEventBus.PublishAsync(@command); - var serviceProvider = CreateDefaultProvider(); - var eventBus = serviceProvider.GetRequiredService(); - await eventBus.PublishAsync(@command); + _eventBus.Verify(eventBus => eventBus.PublishAsync(@command), Times.Once, "PublishAsync is executed multiple times"); + _uoW.Verify(u => u.CommitAsync(default), Times.Once); } [TestMethod] - public async Task TestAddMultDomainEventBusAsync() + public void TestAddMultDomainEventBusAsync() { - var services = new ServiceCollection(); - - services.AddDomainEventBus(options => - { - options.Assemblies = new System.Reflection.Assembly[1] { typeof(TestBase).Assembly }; - Mock eventBus = new(); - eventBus.Setup(e => e.PublishAsync(It.IsAny())).Verifiable(); - services.AddScoped(typeof(IEventBus), serviceProvider => eventBus.Object); - - Mock unitOfWork = new(); - services.AddScoped(typeof(IUnitOfWork), serviceProvider => unitOfWork.Object); - - Mock integrationEventBus = new(); - integrationEventBus.Setup(e => e.PublishAsync(It.IsAny())).Verifiable(); - services.AddScoped(typeof(IIntegrationEventBus), serviceProvider => integrationEventBus.Object); - }).AddDomainEventBus(); + _services.AddScoped(serviceProvider => _eventBus.Object); + _services.AddScoped(serviceProvider => _integrationEventBus.Object); + _services.AddScoped(serviceProvider => _uoW.Object); - var serviceProvider = services.BuildServiceProvider(); + _services.AddDomainEventBus(options => options.Assemblies = new Assembly[1] { typeof(DomainEventBusTest).Assembly }).AddDomainEventBus(); + var serviceProvider = _services.BuildServiceProvider(); Assert.IsTrue(serviceProvider.GetServices().Count() == 1); - - var userDomainService = serviceProvider.GetService(); - Assert.IsNotNull(userDomainService); - - Assert.IsTrue(await userDomainService.RegisterUserSucceededAsync("tom") == "succeed"); + Assert.IsTrue(serviceProvider.GetServices>().Count() == 1); } [TestMethod] public void TestNotUseEventBus() { - var services = new ServiceCollection(); - - var ex = Assert.ThrowsException(() => services.AddDomainEventBus()); + var ex = Assert.ThrowsException(() + => _services.AddDomainEventBus() + ); Assert.IsTrue(ex.Message == "Please add EventBus first."); } [TestMethod] public void TestNotUseUnitOfWork() { - var services = new ServiceCollection(); - var eventBus = new Mock(); - services.AddScoped(serviceProvider => eventBus.Object); + _services.AddScoped(serviceProvider => eventBus.Object); - var ex = Assert.ThrowsException(() => services.AddDomainEventBus()); + var ex = Assert.ThrowsException(() + => _services.AddDomainEventBus(options => options.Assemblies = new Assembly[1] { typeof(DomainEventBusTest).Assembly }) + ); Assert.IsTrue(ex.Message == "Please add UoW first."); } @@ -103,25 +138,16 @@ public void TestNotUseIntegrationEventBus() var uoW = new Mock(); services.AddScoped(serviceProvider => uoW.Object); - var ex = Assert.ThrowsException(() => services.AddDomainEventBus()); + var ex = Assert.ThrowsException(() + => services.AddDomainEventBus(options => options.Assemblies = new Assembly[1] { typeof(DomainEventBusTest).Assembly }) + ); Assert.IsTrue(ex.Message == "Please add IntegrationEventBus first."); } [TestMethod] public void TestNullAssembly() { - var services = new ServiceCollection(); - - var eventBus = new Mock(); - services.AddScoped(serviceProvider => eventBus.Object); - - var uoW = new Mock(); - services.AddScoped(serviceProvider => uoW.Object); - - var integrationEventBus = new Mock(); - services.AddScoped(serviceProvider => integrationEventBus.Object); - - Assert.ThrowsException(() => services.AddDomainEventBus(options => { options.Assemblies = null; })); + Assert.ThrowsException(() => _dispatcherOptions.Value.Assemblies = null); } [TestMethod] @@ -142,12 +168,11 @@ public void TestNotRepository() { services.AddDomainEventBus(options => { - options.Assemblies = new System.Reflection.Assembly[1] { typeof(User).Assembly }; + options.Assemblies = new Assembly[1] { typeof(Users).Assembly }; }); }); } - [TestMethod] public void TestUserRepository() { @@ -161,76 +186,62 @@ public void TestUserRepository() var integrationEventBus = new Mock(); services.AddScoped(serviceProvider => integrationEventBus.Object); - services.AddScoped, UserRepository>(); + + Mock> repository = new(); + services.AddScoped(serviceProvider => repository.Object); services.AddDomainEventBus(options => { - options.Assemblies = new System.Reflection.Assembly[2] { typeof(User).Assembly, typeof(UserRepository).Assembly }; + options.Assemblies = new Assembly[2] { typeof(Users).Assembly, typeof(DomainEventBusTest).Assembly }; }); } [TestMethod] public async Task TestPublishQueueAsync() { - var services = new ServiceCollection(); - - //todo: Temporary results, used to show the enqueue and dequeue order - int result = 0; - - Mock eventBus = new(); - eventBus - .Setup(e => e.PublishAsync(It.IsAny())) - .Callback(async cmd => - { - if (result == 0) - { - result = 3; - } - else - { - result = 4; - } - await Task.FromResult(result); - }); - Mock integrationEventBus = new(); - integrationEventBus - .Setup(e => e.PublishAsync(It.IsAny())) - .Callback(async cmd => + var domainEvent = new PaymentSucceededDomainEvent() { OrderId = "ef5f84db-76e4-4c79-9815-99a1543b6589" }; + var integrationDomainEvent = new PaymentFailedIntegrationDomainEvent() { OrderId = "d65c1a0c-6e44-40ce-9737-738fa1dcdab4" }; + + _eventBus + .Setup(eventBus => eventBus.PublishAsync(It.IsAny())) + .Callback(() => + { + _integrationEventBus.Verify(integrationEventBus => integrationEventBus.PublishAsync(integrationDomainEvent), Times.Never, "Sent in the wrong order"); + }); + + _integrationEventBus + .Setup(integrationEventBus => integrationEventBus.PublishAsync(It.IsAny())) + .Callback(() => { - if (result == 3) - { - result = 1; - } - else - { - result = 2; - } - await Task.FromResult(result); + _eventBus.Verify(eventBus => eventBus.PublishAsync((IDomainEvent)domainEvent), Times.Once, "Sent in the wrong order"); }); var uoW = new Mock(); uoW.Setup(u => u.CommitAsync(default)).Verifiable(); - var options = Options.Create(new DispatcherOptions(services) { Assemblies = AppDomain.CurrentDomain.GetAssemblies() }); + var options = Options.Create(new DispatcherOptions(_services) { Assemblies = AppDomain.CurrentDomain.GetAssemblies() }); - var domainEventBus = new DomainEventBus(eventBus.Object, integrationEventBus.Object, uoW.Object, options); + var domainEventBus = new DomainEventBus(_eventBus.Object, _integrationEventBus.Object, uoW.Object, options); + + await domainEventBus.Enqueue(domainEvent); + await domainEventBus.Enqueue(integrationDomainEvent); - // todo: It has no practical meaning, just to show the order of entering and leaving the team - await domainEventBus.Enqueue(new PaymentSucceededDomainEvent() { OrderId = "ef5f84db-76e4-4c79-9815-99a1543b6589" }); - await domainEventBus.Enqueue(new PaymentFailedIntegrationDomainEvent() { OrderId = "d65c1a0c-6e44-40ce-9737-738fa1dcdab4" }); await domainEventBus.PublishQueueAsync(); - Assert.IsTrue(result == 1); + + _eventBus.Verify(eventBus => eventBus.PublishAsync((IDomainEvent)domainEvent), Times.Once, "Sent in the wrong order"); + _integrationEventBus.Verify(integrationEventBus => integrationEventBus.PublishAsync(integrationDomainEvent), Times.Never, "Sent in the wrong order"); } [TestMethod] - public async Task TestPublishDomainQuery() + public async Task TestPublishDomainQueryAsync() { var services = new ServiceCollection(); var eventBus = new Mock(); eventBus.Setup(e => e.PublishAsync(It.IsAny())) - .Callback(async query => + .Callback(query => { - query.Result = "apple"; + if (query.ProductId == "2f8d4c3c-1736-4e56-a188-f865da6a63d1") + query.Result = "apple"; }); var integrationEventBus = new Mock(); var uoW = new Mock(); @@ -241,7 +252,104 @@ public async Task TestPublishDomainQuery() var domainEventBus = new DomainEventBus(eventBus.Object, integrationEventBus.Object, uoW.Object, options); var query = new ProductItemDomainQuery() { ProductId = "2f8d4c3c-1736-4e56-a188-f865da6a63d1" }; + await domainEventBus.PublishAsync(query); Assert.IsTrue(query.Result == "apple"); } + + [TestMethod] + public async Task TestCommitAsync() + { + var services = new ServiceCollection(); + + _uoW.Setup(uow => uow.CommitAsync(CancellationToken.None)).Verifiable(); + Mock> options = new(); + + var domainEventBus = new DomainEventBus(_eventBus.Object, _integrationEventBus.Object, _uoW.Object, options.Object); + await domainEventBus.CommitAsync(CancellationToken.None); + + _uoW.Verify(u => u.CommitAsync(default), Times.Once, "CommitAsync must be called only once"); + } + + [TestMethod] + public void TestParameterInitialization() + { + var id = Guid.NewGuid(); + var createTime = DateTime.UtcNow; + + var domainCommand = new DomainCommand(); + Assert.IsTrue(domainCommand.Id != default); + Assert.IsTrue(domainCommand.CreationTime != default && domainCommand.CreationTime >= createTime); + + domainCommand = new DomainCommand(id, createTime); + Assert.IsTrue(domainCommand.Id == id); + Assert.IsTrue(domainCommand.CreationTime == createTime); + + var domainEvent = new DomainEvent(); + Assert.IsTrue(domainEvent.Id != default); + Assert.IsTrue(domainEvent.CreationTime != default && domainEvent.CreationTime >= createTime); + + domainEvent = new DomainEvent(id, createTime); + Assert.IsTrue(domainEvent.Id == id); + Assert.IsTrue(domainEvent.CreationTime == createTime); + + var domainQuery = new ProductItemDomainQuery() + { + ProductId = Guid.NewGuid().ToString() + }; + Assert.IsTrue(domainQuery.Id != default); + Assert.IsTrue(domainQuery.CreationTime != default && domainQuery.CreationTime >= createTime); + } + + [TestMethod] + public void TestDomainQueryUnitOfWork() + { + var domainQuery = new ProductItemDomainQuery() + { + ProductId = Guid.NewGuid().ToString() + }; + Assert.ThrowsException(() => + { + domainQuery.UnitOfWork = _uoW.Object; + }); + Assert.ThrowsException(() => + { + var unitOfWork = domainQuery.UnitOfWork; + }); + } + + [TestMethod] + public async Task TestDomainServiceAsync() + { + _integrationEventBus.Setup(integrationEventBus => integrationEventBus.PublishAsync(It.IsAny())).Verifiable(); + + _services.AddDomainEventBus(options => + { + options.Assemblies = new Assembly[1] { typeof(DomainEventBusTest).Assembly }; + options.Services.AddScoped(serviceProvider => _eventBus.Object); + options.Services.AddScoped(serviceProvider => _integrationEventBus.Object); + options.Services.AddScoped(serviceProvider => _uoW.Object); + }); + var serviceProvider = _services.BuildServiceProvider(); + + var userDomainService = serviceProvider.GetRequiredService(); + var domainIntegrationEvent = new RegisterUserSucceededDomainIntegrationEvent() { Account = "Tom" }; + await userDomainService.RegisterUserSucceededAsync(domainIntegrationEvent); + + _integrationEventBus.Verify(integrationEventBus => integrationEventBus.PublishAsync(domainIntegrationEvent), Times.Once); + } + + [TestMethod] + public async Task TestPublishEvent() + { + var domainEventBus = new DomainEventBus(_eventBus.Object, _integrationEventBus.Object, _uoW.Object, _dispatcherOptions); + _eventBus.Setup(eventBus => eventBus.PublishAsync(It.IsAny())).Verifiable(); + + var @event = new ForgetPasswordEvent() + { + Account = "Tom" + }; + await domainEventBus.PublishAsync(@event); + _eventBus.Verify(eventBus => eventBus.PublishAsync(@event), Times.Once); + } } diff --git a/test/MASA.Contrib.DDD.Domain.Tests/EventHandlers/PaymentSucceededHandlers.cs b/test/MASA.Contrib.DDD.Domain.Tests/EventHandlers/PaymentSucceededHandlers.cs deleted file mode 100644 index 23a753bc0..000000000 --- a/test/MASA.Contrib.DDD.Domain.Tests/EventHandlers/PaymentSucceededHandlers.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace MASA.Contrib.DDD.Domain.Tests.EventHandlers; - -public class PaymentSucceededHandlers : IEventHandler -{ - private readonly ILogger _logger; - - public PaymentSucceededHandlers(ILogger logger) => _logger = logger; - - public Task HandleAsync(PaymentSucceededDomainEvent @event) - { - _logger.LogInformation("Publishing PaymentSucceededDomainEvent {@Event} on {CreationTime}", @event, @event.CreationTime); - return Task.CompletedTask; - } -} diff --git a/test/MASA.Contrib.DDD.Domain.Tests/Events/ForgetPasswordEvent.cs b/test/MASA.Contrib.DDD.Domain.Tests/Events/ForgetPasswordEvent.cs new file mode 100644 index 000000000..7e8bdcf94 --- /dev/null +++ b/test/MASA.Contrib.DDD.Domain.Tests/Events/ForgetPasswordEvent.cs @@ -0,0 +1,10 @@ +namespace MASA.Contrib.DDD.Domain.Tests.Events; + +public class ForgetPasswordEvent : IEvent +{ + public Guid Id { get; init; } = Guid.NewGuid(); + + public DateTime CreationTime { get; init; } = DateTime.UtcNow; + + public string Account { get; set; } +} diff --git a/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj b/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj index 7d8fc395f..933831f6b 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj +++ b/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj @@ -1,4 +1,4 @@ - + net6.0 @@ -8,6 +8,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/test/MASA.Contrib.DDD.Domain.Tests/Repositories/UserRepository.cs b/test/MASA.Contrib.DDD.Domain.Tests/Repositories/UserRepository.cs deleted file mode 100644 index 010fb49b6..000000000 --- a/test/MASA.Contrib.DDD.Domain.Tests/Repositories/UserRepository.cs +++ /dev/null @@ -1,96 +0,0 @@ -namespace MASA.Contrib.DDD.Domain.Tests.Repositories; - -public class UserRepository : IRepository -{ - public IUnitOfWork UnitOfWork => throw new NotImplementedException(); - - public ValueTask AddAsync(User entity, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AddRangeAsync(IEnumerable entities, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public ValueTask FindAsync(params object?[]? keyValues) - { - throw new NotImplementedException(); - } - - public ValueTask FindAsync(object?[]? keyValues, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task FindAsync(Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task GetCountAsync(CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task GetCountAsync(Expression> predicate, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task> GetListAsync(CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task> GetListAsync(Expression> predicate, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task> GetPaginatedListAsync(int skip, int take, string? sorting, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task> GetPaginatedListAsync(Expression> predicate, int skip, int take, string? sorting, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task> GetPaginatedListAsync(PaginatedOptions options, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task> GetPaginatedListAsync(Expression> predicate, PaginatedOptions options, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - public Task RemoveAsync(User entity, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task RemoveAsync(Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task RemoveRangeAsync(IEnumerable entities, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task UpdateAsync(User entity, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task UpdateRangeAsync(IEnumerable entities, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } -} diff --git a/test/MASA.Contrib.DDD.Domain.Tests/Services/UserDomainService.cs b/test/MASA.Contrib.DDD.Domain.Tests/Services/UserDomainService.cs index 61a112e95..52065a304 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/Services/UserDomainService.cs +++ b/test/MASA.Contrib.DDD.Domain.Tests/Services/UserDomainService.cs @@ -6,11 +6,11 @@ public UserDomainService(IDomainEventBus eventBus) : base(eventBus) { } - public async Task RegisterUserSucceededAsync(string account) + public async Task RegisterUserSucceededAsync(RegisterUserSucceededDomainIntegrationEvent domainIntegrationEvent) { // TODO Simulate a successful message for registered users - await EventBus.PublishAsync(new RegisterUserSucceededDomainIntegrationEvent() { Account = account }); + await EventBus.PublishAsync(domainIntegrationEvent); return "succeed"; } } diff --git a/test/MASA.Contrib.DDD.Domain.Tests/TestBase.cs b/test/MASA.Contrib.DDD.Domain.Tests/TestBase.cs deleted file mode 100644 index cd3f308cc..000000000 --- a/test/MASA.Contrib.DDD.Domain.Tests/TestBase.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace MASA.Contrib.DDD.Domain.Tests; - -public class TestBase -{ - protected const string DAPR_PUBSUB_NAME = "pubsub"; - - protected IServiceProvider CreateDefaultProvider() - { - return CreateProvider((services) => - { - Mock integrationEventBus = new(); - integrationEventBus.Setup(e => e.PublishAsync(It.IsAny())).Verifiable(); - services.AddScoped(typeof(IIntegrationEventBus), serviceProvider => integrationEventBus.Object); - }); - } - - protected IServiceProvider CreateProvider(Action? action = null) - { - var services = new ServiceCollection(); - action?.Invoke(services); - services.AddDomainEventBus(options => - { - options.Assemblies = new System.Reflection.Assembly[1] { typeof(TestBase).Assembly }; - Mock eventBus = new(); - eventBus.Setup(e => e.PublishAsync(It.IsAny())).Verifiable(); - services.AddScoped(typeof(IEventBus), serviceProvider => eventBus.Object); - - Mock unitOfWork = new(); - services.AddScoped(typeof(IUnitOfWork), serviceProvider => unitOfWork.Object); - }); - return services.BuildServiceProvider(); - } -} diff --git a/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs index 2992c4d89..3e24c3e5e 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs +++ b/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs @@ -5,7 +5,6 @@ global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using MASA.Contrib.DDD.Domain.Events; global using MASA.Contrib.DDD.Domain.Tests.Events; -global using MASA.Contrib.DDD.Domain.Tests.Repositories; global using MASA.Contrib.DDD.Domain.Tests.Services; global using MASA.Contribs.DDD.Domain.Entities; global using Microsoft.Extensions.DependencyInjection; @@ -13,4 +12,4 @@ global using Microsoft.Extensions.Options; global using Microsoft.VisualStudio.TestTools.UnitTesting; global using Moq; -global using System.Linq.Expressions; +global using System.Reflection; diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Courses.cs b/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Courses.cs new file mode 100644 index 000000000..158e8ceb3 --- /dev/null +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Courses.cs @@ -0,0 +1,16 @@ +namespace MASA.Contrib.Data.Contracts.EF.Test.Domain.Entities; + +public class Courses : AggregateRoot +{ + public Courses() + { + Id = Guid.NewGuid(); + IsDeleted = false; + } + + public Guid Id { get; init; } + + public string Name { get; set; } + + public bool IsDeleted { get; set; } +} diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Students.cs b/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Students.cs new file mode 100644 index 000000000..c99587da6 --- /dev/null +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Students.cs @@ -0,0 +1,16 @@ +namespace MASA.Contrib.Data.Contracts.EF.Test.Domain.Entities; + +public class Students : AuditAggregateRoot +{ + public Students() + { + this.Id = Guid.NewGuid(); + this.RegisterTime = DateTime.UtcNow; + } + + public string Name { get; set; } + + public int Age { get; set; } + + public DateTime RegisterTime { get; private set; } +} diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/Infrastructure/CustomDbContext.cs b/test/MASA.Contrib.Data.Contracts.EF.Test/Infrastructure/CustomDbContext.cs new file mode 100644 index 000000000..cff5509cc --- /dev/null +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/Infrastructure/CustomDbContext.cs @@ -0,0 +1,10 @@ +namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure; + +public class CustomDbContext : MasaDbContext +{ + public DbSet Students { get; set; } + + public DbSet Courses { get; set; } + + public CustomDbContext(MasaDbContextOptions options) : base(options) { } +} diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj new file mode 100644 index 000000000..c245e76f6 --- /dev/null +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj @@ -0,0 +1,29 @@ + + + + net6.0 + enable + false + enable + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs b/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs new file mode 100644 index 000000000..bfa843978 --- /dev/null +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs @@ -0,0 +1,113 @@ +namespace MASA.Contrib.Data.Contracts.EF.Test; + +[TestClass] +public class SoftDeleteTest : IDisposable +{ + protected readonly SqliteConnection _connection; + + public SoftDeleteTest() + { + _connection = new SqliteConnection("DataSource=:memory:"); + _connection.Open(); + } + + public void Dispose() + { + _connection.Close(); + } + + [TestMethod] + public void UseNotUseUoW() + { + var services = new ServiceCollection(); + services.AddMasaDbContext(option => + { + option.UseSqlite(_connection); + Assert.ThrowsException(() => option.UseSoftDelete(services), "Please add UoW first."); + }); + } + + [TestMethod] + public void TestUseSoftDelete() + { + Mock uoW = new(); + uoW.Setup(u => u.Transaction).Verifiable(); + var services = new ServiceCollection(); + services.AddScoped(serviceProvider => uoW.Object); + services.AddMasaDbContext(option => + { + option.UseSqlite(_connection); + option.UseSoftDelete(services); + }); + + var serviceProvider = services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + + dbContext.Set().Add(new Students() + { + Name = "Tom", + Age = 18 + }); + dbContext.SaveChanges(); + Assert.IsTrue(dbContext.Students.Count() == 1); + uoW.Verify(u => u.Transaction, Times.Once); + + var student = dbContext.Students.Where(s => s.Name == "Tom").FirstOrDefault(); + Assert.IsNotNull(student); + dbContext.Set().Remove(student); + dbContext.SaveChanges(); + + Assert.IsTrue(dbContext.Students.Count() == 0); + + student.IsDeleted = false; + dbContext.SaveChanges(); + Assert.IsTrue(dbContext.Students.Count() == 1); + + uoW = new(); + uoW.Setup(u => u.Transaction).Verifiable(); + services = new ServiceCollection(); + services.AddScoped(serviceProvider => uoW.Object); + services.AddMasaDbContext(option => + { + option.UseSqlite(_connection); + option.UseSoftDelete(services); + }); + + serviceProvider = services.BuildServiceProvider(); + dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + + dbContext.Set().Add(new Courses() + { + Name = "Chinese" + }); + dbContext.SaveChanges(); + Assert.IsTrue(dbContext.Courses.Count() == 1); + uoW.Verify(u => u.Transaction, Times.Once); + + var course = dbContext.Set().FirstOrDefault(c => c.Name == "Chinese"); + Assert.IsNotNull(course); + dbContext.Set().Remove(course); + dbContext.SaveChanges(); + Assert.IsTrue(dbContext.Courses.Count() == 0); + + course.IsDeleted = false; + dbContext.SaveChanges(); + Assert.IsTrue(dbContext.Courses.Count() == 0); + } + + [TestMethod] + public void TestUseMultiSoftDelete() + { + Mock uoW = new(); + uoW.Setup(u => u.Transaction).Verifiable(); + var services = new ServiceCollection(); + services.AddScoped(serviceProvider => uoW.Object); + services.AddMasaDbContext(option => + { + option.UseSqlite(_connection); + option.UseSoftDelete(services).UseSoftDelete(services); + }); + } +} diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/_Imports.cs b/test/MASA.Contrib.Data.Contracts.EF.Test/_Imports.cs new file mode 100644 index 000000000..d269e5e5b --- /dev/null +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/_Imports.cs @@ -0,0 +1,11 @@ +global using MASA.BuildingBlocks.Data.UoW; +global using MASA.BuildingBlocks.DDD.Domain.Entities; +global using MASA.BuildingBlocks.DDD.Domain.Entities.Auditing; +global using MASA.Contrib.Data.Contracts.EF.Test.Domain.Entities; +global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure; +global using MASA.Utils.Data.EntityFrameworkCore; +global using Microsoft.Data.Sqlite; +global using Microsoft.EntityFrameworkCore; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using Moq; diff --git a/test/MASA.Contrib.Data.UoW.EF.Tests/CustomerDbContext.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/CustomerDbContext.cs index 8b4a72d28..ce3b81dda 100644 --- a/test/MASA.Contrib.Data.UoW.EF.Tests/CustomerDbContext.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/CustomerDbContext.cs @@ -1,9 +1,12 @@ -using MASA.Utils.Data.EntityFrameworkCore; - namespace MASA.Contrib.Data.UoW.EF.Tests; public class CustomerDbContext : MasaDbContext { + public CustomerDbContext() + { + + } + public CustomerDbContext(MasaDbContextOptions options) : base(options) { } public DbSet User { get; set; } @@ -30,7 +33,12 @@ void ConfigureUserEntry(EntityTypeBuilder builder) public class Users { - public Guid Id { get; set; } + public Guid Id { get; private set; } + + public string Name { get; set; } = default!; - public string Name { get; set; } + public Users() + { + this.Id = Guid.NewGuid(); + } } diff --git a/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj b/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj index ca11a7ee2..7f3dbfe6c 100644 --- a/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj @@ -8,8 +8,12 @@ - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/MASA.Contrib.Data.UoW.EF.Tests/TestBase.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/TestBase.cs index 7d3289cfe..878c8982e 100644 --- a/test/MASA.Contrib.Data.UoW.EF.Tests/TestBase.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/TestBase.cs @@ -1,36 +1,17 @@ -using Microsoft.Data.Sqlite; +namespace MASA.Contrib.Data.UoW.EF.Tests; -namespace MASA.Contrib.Data.UoW.EF.Tests +public class TestBase : IDisposable { - public class TestBase : IDisposable - { - protected readonly SqliteConnection _connection; - - protected TestBase() - { - _connection = new SqliteConnection("DataSource=:memory:"); - _connection.Open(); - } - - public void Dispose() - { - _connection.Close(); - } + protected readonly SqliteConnection _connection; - private IServiceProvider CreateDefaultProvider() - { - var options = new Mock(); - options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); - options.Object.UseUoW(options => options.UseSqlite(_connection)); - return options.Object.Services.BuildServiceProvider(); - } + protected TestBase() + { + _connection = new SqliteConnection("DataSource=:memory:"); + _connection.Open(); + } - protected (IServiceProvider serviceProvider, CustomerDbContext dbContext) CreateDefault() - { - var serviceProvider = CreateDefaultProvider(); - var dbContext = serviceProvider.GetRequiredService(); - dbContext.Database.EnsureCreated(); - return (serviceProvider, dbContext); - } + public void Dispose() + { + _connection.Close(); } } diff --git a/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs index 8e73b038b..4c38d2649 100644 --- a/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs @@ -3,6 +3,15 @@ namespace MASA.Contrib.Data.UoW.EF.Tests; [TestClass] public class TestUnitOfWork : TestBase { + private Mock _options; + + [TestInitialize] + public void Initialize() + { + _options = new(); + _options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); + } + [TestMethod] public void TestAddUoWAndNullServices() { @@ -13,103 +22,179 @@ public void TestAddUoWAndNullServices() [TestMethod] public void TestAddUoW() { - var options = new Mock(); - options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); - options.Object.UseUoW(); - var serviceProvider = options.Object.Services.BuildServiceProvider(); - Assert.ThrowsException(() => serviceProvider.GetRequiredService()); + _options.Object.UseUoW(); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + Assert.ThrowsException(() + => serviceProvider.GetRequiredService() + ); } [TestMethod] public void TestAddUoWAndUseSqlLite() { - var options = new Mock(); - options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); - options.Object.UseUoW(options => options.UseSqlite(_connection)); - var serviceProvider = options.Object.Services.BuildServiceProvider(); + _options.Object.UseUoW(options => options.UseSqlite(_connection)); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); Assert.IsNotNull(serviceProvider.GetRequiredService()); } [TestMethod] public void TestAddMultUoW() { - var options = new Mock(); - options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); - options.Object.UseUoW(options => options.UseSqlite(_connection)).UseUoW(options => options.UseSqlite(_connection)); - var serviceProvider = options.Object.Services.BuildServiceProvider(); + _options.Object + .UseUoW(options => options.UseSqlite(_connection)) + .UseUoW(options => options.UseSqlite(_connection)); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); Assert.IsTrue(serviceProvider.GetServices().Count() == 1); } [TestMethod] - public async Task TestNoTransactionAndCommitAsync() + public void TestTransaction() { - var serviceProviderAndDbContext = base.CreateDefault(); - var serviceProvider = serviceProviderAndDbContext.serviceProvider; - var dbContext = serviceProviderAndDbContext.dbContext; + Mock uoW = new(); + Assert.IsTrue(new Transaction(uoW.Object).UnitOfWork.Equals(uoW.Object)); + } - await using (var unitOfWork = serviceProvider.GetRequiredService()) + [TestMethod] + public async Task TestSaveChangesAsync() + { + _options.Object.UseUoW(options => options.UseSqlite(_connection)); + Mock customerDbContext = new(); + customerDbContext.Setup(dbContext => dbContext.SaveChangesAsync(default)).Verifiable(); + var uoW = new UnitOfWork(customerDbContext.Object, null); + await uoW.SaveChangesAsync(default); + customerDbContext.Verify(dbContext => dbContext.SaveChangesAsync(default), Times.Once); + } + + [TestMethod] + public async Task TestUseTranscationAsync() + { + _options.Object.UseUoW(options => options.UseSqlite(_connection)); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + var uoW = serviceProvider.GetRequiredService(); + + var transaction = uoW.Transaction; + Users user = new Users() { - var transcation = unitOfWork.Transaction; - Assert.IsTrue(unitOfWork == serviceProvider.GetRequiredService().UnitOfWork); - - Users user = new Users() - { - Id = Guid.NewGuid(), - Name = Guid.NewGuid().ToString() - }; - dbContext.Add(user); - await unitOfWork.CommitAsync(); - - Assert.IsTrue(dbContext.User.Any(user => user.Id == user.Id)); - } + Name = Guid.NewGuid().ToString() + }; + dbContext.Add(user); + await uoW.SaveChangesAsync(); + await uoW.RollbackAsync(); + + Assert.IsTrue(dbContext.User.ToList().Count() == 0); } [TestMethod] - public async Task TestUseTransactionAndCommitAsync() + public async Task TestNotUseTranscationAsync() { - var serviceProviderAndDbContext = base.CreateDefault(); - var serviceProvider = serviceProviderAndDbContext.serviceProvider; - var dbContext = serviceProviderAndDbContext.dbContext; + _options.Object.UseUoW(options => options.UseSqlite(_connection)); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + var uoW = new UnitOfWork(dbContext, null); - using (var transcation = await dbContext.Database.BeginTransactionAsync()) + Users user = new Users() { - var unitOfWork = serviceProvider.GetRequiredService(); - - Users user = new Users() - { - Id = Guid.NewGuid(), - Name = Guid.NewGuid().ToString() - }; - dbContext.Add(user); - await unitOfWork.CommitAsync(); ; - } + Name = Guid.NewGuid().ToString() + }; + dbContext.Add(user); + await uoW.SaveChangesAsync(); + await Assert.ThrowsExceptionAsync(async () => await uoW.RollbackAsync()); } [TestMethod] - public async Task TestNoTransactionAsync() + public async Task TestNotTransactionCommitAsync() { - var serviceProviderAndDbContext = base.CreateDefault(); - var serviceProvider = serviceProviderAndDbContext.serviceProvider; - var dbContext = serviceProviderAndDbContext.dbContext; + _options.Object.UseUoW(options => options.UseSqlite(_connection)); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + var uoW = new UnitOfWork(dbContext, null); + await Assert.ThrowsExceptionAsync(async () => await uoW.CommitAsync()); + } - await using (var unitOfWork = serviceProvider.GetRequiredService()) + [TestMethod] + public async Task TestCommitAsync() + { + _options.Object.UseUoW(options => options.UseSqlite(_connection)); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + var uoW = new UnitOfWork(dbContext, null); + var user = new Users() { - Users user = new Users() - { - Id = Guid.NewGuid(), - Name = Guid.NewGuid().ToString().Substring(0, 6) - }; - dbContext.Add(user); - - await unitOfWork.SaveChangesAsync(); - - await Assert.ThrowsExceptionAsync(async () => - { - await unitOfWork.RollbackAsync(); - }); - - Assert.IsTrue(dbContext.User.Any(user => user.Id == user.Id)); - } + Name = "Tom" + }; + var transcation = uoW.Transaction; + dbContext.User.Add(user); + await uoW.SaveChangesAsync(); + await uoW.CommitAsync(); + + Assert.IsTrue(dbContext.User.ToList().Count == 1); + } + + [TestMethod] + public async Task TestCloseRollbackAsync() + { + _options.Object.UseUoW(options => options.UseSqlite(_connection), true); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + var uoW = serviceProvider.GetRequiredService(); + var user = new Users(); + var transcation = uoW.Transaction; + dbContext.User.Add(user); + await Assert.ThrowsExceptionAsync(async () => await uoW.CommitAsync()); + } + + [TestMethod] + public async Task TestAddLoggerAndCloseRollbackAsync() + { + _options.Object.Services.AddLogging(); + _options.Object.UseUoW(options => options.UseSqlite(_connection), true); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + var uoW = serviceProvider.GetRequiredService(); + var user = new Users(); + var transcation = uoW.Transaction; + dbContext.User.Add(user); + await Assert.ThrowsExceptionAsync(async () => await uoW.CommitAsync()); + } + + [TestMethod] + public async Task TestOpenRollbackAsync() + { + _options.Object.UseUoW(options => options.UseSqlite(_connection)); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + var uoW = serviceProvider.GetRequiredService(); + var user = new Users(); + var transcation = uoW.Transaction; + dbContext.User.Add(user); + await uoW.CommitAsync(); + + Assert.IsTrue(!await dbContext.User.AnyAsync()); + } + + [TestMethod] + public async Task TestAddLoggerAndOpenRollbackAsync() + { + _options.Object.Services.AddLogging(); + _options.Object.UseUoW(options => options.UseSqlite(_connection)); + var serviceProvider = _options.Object.Services.BuildServiceProvider(); + var dbContext = serviceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); + var uoW = serviceProvider.GetRequiredService(); + var user = new Users(); + var transcation = uoW.Transaction; + dbContext.User.Add(user); + await uoW.CommitAsync(); + + Assert.IsTrue(!await dbContext.User.AnyAsync()); } } diff --git a/test/MASA.Contrib.Data.UoW.EF.Tests/_Imports.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/_Imports.cs index d13736058..1af16327c 100644 --- a/test/MASA.Contrib.Data.UoW.EF.Tests/_Imports.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/_Imports.cs @@ -1,5 +1,7 @@ global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.Dispatcher.Events; +global using MASA.Utils.Data.EntityFrameworkCore; +global using Microsoft.Data.Sqlite; global using Microsoft.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore.Metadata.Builders; global using Microsoft.Extensions.DependencyInjection; diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj index a0945b095..ce74a9fd5 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net6.0 AnyCPU false enable @@ -17,5 +17,5 @@ - + diff --git a/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests/EventHandlers/AddGoodsHandler.cs b/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests/EventHandlers/AddGoodsHandler.cs index 178e4a9ba..d4be77a2d 100644 --- a/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests/EventHandlers/AddGoodsHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests/EventHandlers/AddGoodsHandler.cs @@ -1,5 +1,3 @@ -using MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests.Events; - namespace MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests.EventHandlers; public class AddGoodsHandler diff --git a/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests/_Imports.cs index 15d889922..61d74bb3c 100644 --- a/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests/_Imports.cs @@ -1 +1,2 @@ +global using MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests.Events; global using Microsoft.Extensions.Logging; diff --git a/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests/EventHandlers/AddCatalogHandler.cs b/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests/EventHandlers/AddCatalogHandler.cs index 17a1bf269..1681085fe 100644 --- a/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests/EventHandlers/AddCatalogHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests/EventHandlers/AddCatalogHandler.cs @@ -1,5 +1,3 @@ -using MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests.Events; - namespace MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests.EventHandlers; public class AddCatalogHandler diff --git a/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests/_Imports.cs index e69de29bb..53869939c 100644 --- a/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests/_Imports.cs @@ -0,0 +1 @@ +global using MASA.Contrib.Dispatcher.Events.CheckMethodsParameterType.Tests.Events; diff --git a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/EventHandlers/UserEventHandler.cs b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/EventHandlers/UserEventHandler.cs index b62ed164a..66356ba86 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/EventHandlers/UserEventHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/EventHandlers/UserEventHandler.cs @@ -1,5 +1,3 @@ -using MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.Events; - namespace MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.EventHandlers; public class UserEventHandler diff --git a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.csproj b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.csproj index 91a682f61..65fe8ba17 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.csproj @@ -10,5 +10,5 @@ - + diff --git a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/_Imports.cs index e69de29bb..fdc78d0c0 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/_Imports.cs @@ -0,0 +1 @@ +global using MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.Events; diff --git a/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/EventHandlers/EditCategoryHandler.cs b/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/EventHandlers/EditCategoryHandler.cs index 37677b5bd..4c926fc98 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/EventHandlers/EditCategoryHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/EventHandlers/EditCategoryHandler.cs @@ -1,5 +1,3 @@ -using MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests.Events; - namespace MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests.EventHandlers; public class EditCategoryHandler : ISagaEventHandler diff --git a/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests.csproj b/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests.csproj index 91a682f61..65fe8ba17 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests.csproj @@ -10,5 +10,5 @@ - + diff --git a/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/_Imports.cs index 7c7bad467..cecf0b334 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests/_Imports.cs @@ -1,2 +1,3 @@ global using MASA.BuildingBlocks.Dispatcher.Events; +global using MASA.Contrib.Dispatcher.Events.OrderEqualBySaga.Tests.Events; global using Microsoft.Extensions.Logging; diff --git a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/EventHandlers/OrderStockConfirmedHandler.cs b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/EventHandlers/OrderStockConfirmedHandler.cs index 31565057f..ee9550afe 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/EventHandlers/OrderStockConfirmedHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/EventHandlers/OrderStockConfirmedHandler.cs @@ -1,5 +1,3 @@ -using MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests.Events; - namespace MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests.EventHandlers; public class OrderStockConfirmedHandler diff --git a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests.csproj b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests.csproj index 91a682f61..65fe8ba17 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests.csproj @@ -10,5 +10,5 @@ - + diff --git a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/_Imports.cs index 15d889922..abbead4e1 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests/_Imports.cs @@ -1 +1,2 @@ +global using MASA.Contrib.Dispatcher.Events.OrderLessThanZeroByFeature.Tests.Events; global using Microsoft.Extensions.Logging; diff --git a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests/EventHandlers/EditGoodsHandler.cs b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests/EventHandlers/EditGoodsHandler.cs index e4256e6b8..43e09b08d 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests/EventHandlers/EditGoodsHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests/EventHandlers/EditGoodsHandler.cs @@ -1,5 +1,3 @@ -using MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests.Events; - namespace MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests.EventHandlers; public class EditGoodsHandler : IEventHandler diff --git a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests/_Imports.cs index 7c7bad467..2fa58832a 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests/_Imports.cs @@ -1,2 +1,3 @@ global using MASA.BuildingBlocks.Dispatcher.Events; +global using MASA.Contrib.Dispatcher.Events.OrderLessThanZeroBySaga.Tests.Events; global using Microsoft.Extensions.Logging; diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs index ea3419e56..b6f500a11 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs @@ -1,5 +1,3 @@ -using Moq; - namespace MASA.Contrib.Dispatcher.Events.Tests; [TestClass] @@ -224,10 +222,10 @@ public async Task TestTransferEventAndOpenTransaction() { base.ResetMemoryEventBus(services => { - var unitOfWork = new Mock(); - unitOfWork.Setup(x => x.TransactionHasBegun).Returns(true); - unitOfWork.Setup(e => e.CommitAsync(CancellationToken.None)).Verifiable(); - services.AddScoped(serviceProvider => unitOfWork.Object); + var uoW = new Mock(); + uoW.Setup(x => x.TransactionHasBegun).Returns(true); + uoW.Setup(e => e.CommitAsync(CancellationToken.None)).Verifiable(); + services.AddScoped(serviceProvider => uoW.Object); return services; }, true, typeof(AssemblyResolutionTests).Assembly); var @event = new DeductionMoneyEvent() @@ -240,13 +238,10 @@ public async Task TestTransferEventAndOpenTransaction() } [TestMethod] - public async Task TestTransferEventAndCloseTransaction() + public async Task TestCommitAsync() { base.ResetMemoryEventBus(services => { - var unitOfWork = new Mock(); - unitOfWork.Setup(e => e.SaveChangesAsync(CancellationToken.None)).Verifiable(); - services.AddScoped(serviceProvider => unitOfWork.Object); return services; }, true, typeof(AssemblyResolutionTests).Assembly); var @event = new DeductionMoneyEvent() @@ -255,19 +250,20 @@ public async Task TestTransferEventAndCloseTransaction() PayeeAccount = "Jim", Money = 100 }; - await _services.BuildServiceProvider().GetRequiredService().PublishAsync(@event); + var serviceProvider = _services.BuildServiceProvider(); + var eventBus = serviceProvider.GetRequiredService(); + + await Assert.ThrowsExceptionAsync(async () => await eventBus.CommitAsync(default)); } [TestMethod] - public async Task TestTransferEventAndOpenTransactionRollback() + public async Task TestUseUoWCommitAsync() { + var uoW = new Mock(); base.ResetMemoryEventBus(services => { - var unitOfWork = new Mock(); - unitOfWork.Setup(x => x.TransactionHasBegun).Returns(true); - unitOfWork.Setup(e => e.CommitAsync(CancellationToken.None)).Throws(new ArgumentOutOfRangeException("The Money is error")); - unitOfWork.Setup(e => e.RollbackAsync(CancellationToken.None)).Verifiable(); - services.AddScoped(serviceProvider => unitOfWork.Object); + uoW.Setup(e => e.CommitAsync(CancellationToken.None)).Verifiable(); + services.AddScoped(serviceProvider => uoW.Object); return services; }, true, typeof(AssemblyResolutionTests).Assembly); var @event = new DeductionMoneyEvent() @@ -276,7 +272,11 @@ public async Task TestTransferEventAndOpenTransactionRollback() PayeeAccount = "Jim", Money = 100 }; + var serviceProvider = _services.BuildServiceProvider(); + var eventBus = serviceProvider.GetRequiredService(); + await eventBus.PublishAsync(@event); - await _services.BuildServiceProvider().GetRequiredService().PublishAsync(@event); + await eventBus.CommitAsync(default); + uoW.Verify(u => u.CommitAsync(default), Times.Once); } } diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj b/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj index 38c8d126a..961cda7cb 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj @@ -12,6 +12,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/_Imports.cs index 63c70300f..dda486fce 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/_Imports.cs @@ -16,4 +16,5 @@ global using Microsoft.Extensions.DependencyInjection.Extensions; global using Microsoft.Extensions.Logging; global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using Moq; global using System.Reflection; diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/Events/ForgetPasswordEvent.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/Events/ForgetPasswordEvent.cs deleted file mode 100644 index b64b74881..000000000 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/Events/ForgetPasswordEvent.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace MASA.Contrib.Dispatcher.IntegrationEvents.Tests.Events; - -public record ForgetPasswordEvent : IntegrationEvent -{ - public override string Topic { get; set; } = nameof(ForgetPasswordEvent); - - public string Account { get; set; } -} diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/Events/RegisterUserIntegrationEvent.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/Events/RegisterUserIntegrationEvent.cs index 9ba051162..d1f551f25 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/Events/RegisterUserIntegrationEvent.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/Events/RegisterUserIntegrationEvent.cs @@ -2,6 +2,16 @@ namespace MASA.Contrib.Dispatcher.IntegrationEvents.Tests.Events; public record RegisterUserIntegrationEvent : IntegrationEvent { + public RegisterUserIntegrationEvent() + { + + } + + public RegisterUserIntegrationEvent(Guid id, DateTime creationTime) : base(id, creationTime) + { + + } + public string Account { get; set; } public string Password { get; set; } diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/IntegrationEventBusTest.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/IntegrationEventBusTest.cs index 1376996a7..3a75473bd 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/IntegrationEventBusTest.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/IntegrationEventBusTest.cs @@ -1,199 +1,338 @@ -using MASA.Utils.Models.Config; -using Microsoft.Extensions.Options; - namespace MASA.Contrib.Dispatcher.IntegrationEvents.Tests; [TestClass] -public class IntegrationEventBusTest : TestBase +public class IntegrationEventBusTest { - [TestMethod] - public async Task TestPublishSuccessAsync() + private Mock _options; + private Mock> _dispatcherOptions; + private Mock _daprClient; + private Mock> _logger; + private Mock _eventLog; + private Mock> _appConfig; + private Mock _eventBus; + private Mock _uoW; + + [TestInitialize] + public void Initialize() { - var serviceProvider = CreateDefaultProvider("RegisterUser"); - var eventBus = serviceProvider.GetRequiredService(); - RegisterUserIntegrationEvent @event = new RegisterUserIntegrationEvent() + _options = new(); + _options.Setup(option => option.Services).Returns(new ServiceCollection()).Verifiable(); + _dispatcherOptions = new(); + _dispatcherOptions.Setup(option => option.Value).Returns(() => new DispatcherOptions(_options.Object.Services)); + _daprClient = new(); + _logger = new(); + _eventLog = new(); + _eventLog.Setup(eventLog => eventLog.SaveEventAsync(It.IsAny(), null)).Verifiable(); + _eventLog.Setup(eventLog => eventLog.MarkEventAsInProgressAsync(It.IsAny())).Verifiable(); + _eventLog.Setup(eventLog => eventLog.MarkEventAsPublishedAsync(It.IsAny())).Verifiable(); + _eventLog.Setup(eventLog => eventLog.MarkEventAsFailedAsync(It.IsAny())).Verifiable(); + _appConfig = new(); + _appConfig.Setup(appConfig => appConfig.CurrentValue).Returns(() => new AppConfig() { - Account = "lisa", - Password = "123456" - }; - await eventBus.PublishAsync(@event); + AppId = "Test" + }); + _eventBus = new(); + _uoW = new(); + _uoW.Setup(uoW => uoW.CommitAsync(default)).Verifiable(); + _uoW.Setup(uoW => uoW.Transaction).Returns(() => null); } [TestMethod] - public void TestAddMultDaprEventBusAsync() + public void TestDispatcherOption() { - var options = new DispatcherOptions(new ServiceCollection()) + var services = new ServiceCollection(); + DispatcherOptions options; + + Assert.ThrowsException(() => { - Assemblies = AppDomain.CurrentDomain.GetAssemblies() + options = new DispatcherOptions(services) + { + Assemblies = null + }; + }); + Assert.ThrowsException(() => + { + options = new DispatcherOptions(services) + { + Assemblies = new System.Reflection.Assembly[0] + }; + }); + options = new DispatcherOptions(services) + { + Assemblies = new System.Reflection.Assembly[1] { typeof(IntegrationEventBusTest).Assembly } }; - options.UseDaprEventBus() + Assert.IsTrue(options.Services.Equals(services)); + var allEventTypes = new System.Reflection.Assembly[1] { typeof(IntegrationEventBusTest).Assembly } + .SelectMany(assembly => assembly.GetTypes()) + .Where(type => type.IsClass && type != typeof(IntegrationEvent) && typeof(IEvent).IsAssignableFrom(type)).ToList(); + Assert.IsTrue(options.AllEventTypes.Count == allEventTypes.Count()); + + } + + [TestMethod] + public void TestAddMultDaprEventBus() + { + _dispatcherOptions.Object.Value.UseDaprEventBus() .UseDaprEventBus(); - var serviceProvider = options.Services.BuildServiceProvider(); + var serviceProvider = _dispatcherOptions.Object.Value.Services.BuildServiceProvider(); Assert.IsTrue(serviceProvider.GetServices().Count() == 1); } [TestMethod] - public void TestAddDaprEventBusAndNullServicesAsync() + public void TestAddDaprEventBus() { - var options = new DispatcherOptions(null); - var ex = Assert.ThrowsException(() => options.UseDaprEventBus()); - Assert.IsTrue(ex.Message == $"Value cannot be null. (Parameter '{nameof(options.Services)}')"); + IServiceCollection services = new ServiceCollection(); + services.AddDaprEventBus(); + var serviceProvider = services.BuildServiceProvider(); + var integrationEventBus = serviceProvider.GetRequiredService(); + Assert.IsNotNull(integrationEventBus); } [TestMethod] - public void TestAddDaprEventBusAndNullAssemblyAsync() + public void TestEmptyPubSub() { - Assert.ThrowsException(() => new DispatcherOptions(new ServiceCollection()) + IServiceCollection services = new ServiceCollection(); + Assert.ThrowsException(() => { - Assemblies = null + services.AddDaprEventBus(option => + { + option.PubSubName = ""; + }); }); } [TestMethod] - public async Task TestPublishAsync() + public void TestAddDaprEventBusAndChangeAssemblies() { - var services = new ServiceCollection(); - Mock unitWork = new(); - Mock dbTransaction = new(); - unitWork.Setup(u => u.Transaction).Returns(dbTransaction.Object); - services.AddScoped((serviceProvider) => unitWork.Object); - services.AddOptions(); - services.AddLogging(); - services.AddDaprEventBus(options => + IServiceCollection services = new ServiceCollection(); + + services.AddDaprEventBus(option => { + option.Assemblies = AppDomain.CurrentDomain.GetAssemblies(); + option.PubSubName = "pubsub"; }); - RegisterUserIntegrationEvent @event = new RegisterUserIntegrationEvent() - { - Account = "lisa", - Password = "123456" - }; var serviceProvider = services.BuildServiceProvider(); var integrationEventBus = serviceProvider.GetRequiredService(); - await integrationEventBus.PublishAsync(@event); + Assert.IsNotNull(integrationEventBus); + } - Assert.IsTrue(integrationEventBus.GetAllEventTypes().Count() == 3); + [TestMethod] + public void TestAddDaprEventBusAndNullServicesAsync() + { + _options.Setup(option => option.Services).Returns(() => null); + var ex = Assert.ThrowsException(() => _options.Object.UseDaprEventBus()); + Assert.IsTrue(ex.Message == $"Value cannot be null. (Parameter '{nameof(_options.Object.Services)}')"); } [TestMethod] - public async Task TestPublishFailedAsync() + public async Task TestPublishIntegrationEventAsync() { + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + _eventBus.Object, + _uoW.Object); RegisterUserIntegrationEvent @event = new RegisterUserIntegrationEvent() { Account = "lisa", Password = "123456" }; - var serviceProvider = CreateCustomerDaprPubSubProvider(DAPR_PUBSUB_NAME, (services) => - { - Mock daprClient = new(); - daprClient.Setup(e => e.PublishEventAsync(DAPR_PUBSUB_NAME, @event.Topic, It.IsAny(), default)) - .Throws(new Exception("send failure")); - services.AddSingleton(_ => daprClient.Object); - services.AddLogging(loggingBuilder => loggingBuilder.AddConsole()); - }); - var eventBus = serviceProvider.GetRequiredService(); - await eventBus.PublishAsync(@event); + _daprClient.Setup(client => client.PublishEventAsync(_dispatcherOptions.Object.Value.PubSubName, @event.Topic, @event, default)).Verifiable(); + await integrationEventBus.PublishAsync(@event); + + _daprClient.Verify(dapr => dapr.PublishEventAsync(_dispatcherOptions.Object.Value.PubSubName, @event.Topic, @event, default), Times.Once); } [TestMethod] - public async Task TestDbTransactionPublishSuccessAsync() + public async Task TestPublishIntegrationEventAndFailedAsync() { + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + _eventBus.Object, + _uoW.Object); RegisterUserIntegrationEvent @event = new RegisterUserIntegrationEvent() { Account = "lisa", Password = "123456" }; - var serviceProvider = CreateDefaultProvider(@event.Topic); - var eventBus = serviceProvider.GetRequiredService(); - await eventBus.PublishAsync(@event); + _eventLog.Setup(eventLog => eventLog.MarkEventAsPublishedAsync(It.IsAny())).Throws(); + _daprClient.Setup(client => client.PublishEventAsync(_dispatcherOptions.Object.Value.PubSubName, @event.Topic, @event, default)).Verifiable(); + await integrationEventBus.PublishAsync(@event); + + _eventLog.Verify(eventLog => eventLog.MarkEventAsInProgressAsync(@event.Id), Times.Once); + _daprClient.Verify(client => client.PublishEventAsync(_dispatcherOptions.Object.Value.PubSubName, @event.Topic, @event, default), Times.Once); + _eventLog.Verify(eventLog => eventLog.MarkEventAsPublishedAsync(@event.Id), Times.Once); + _eventLog.Verify(eventLog => eventLog.MarkEventAsFailedAsync(@event.Id), Times.Once); } [TestMethod] - public async Task TestDbTransactionPublishFailedAsync() + public async Task TestPublishIntegrationEventAndNotUoWAsync() { + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + _eventBus.Object, + _uoW.Object); RegisterUserIntegrationEvent @event = new RegisterUserIntegrationEvent() { Account = "lisa", - Password = "123456" + Password = "123456", + UnitOfWork = _uoW.Object }; - var serviceProvider = CreateCustomerDaprPubSubProvider(DAPR_PUBSUB_NAME, (services) => - { - Mock daprClient = new(); - daprClient.Setup(e => e.PublishEventAsync(DAPR_PUBSUB_NAME, @event.Topic, It.IsAny(), default)) - .Throws(new Exception("send failure")); - services.AddSingleton(_ => daprClient.Object); - services.AddLogging(loggingBuilder => loggingBuilder.AddConsole()); - }); - var eventBus = serviceProvider.GetRequiredService(); - await eventBus.PublishAsync(@event); + _daprClient.Setup(client => client.PublishEventAsync(_dispatcherOptions.Object.Value.PubSubName, @event.Topic, @event, default)).Verifiable(); + await integrationEventBus.PublishAsync(@event); + + _daprClient.Verify(dapr => dapr.PublishEventAsync(_dispatcherOptions.Object.Value.PubSubName, @event.Topic, @event, default), Times.Once); } [TestMethod] - public async Task CheckCustomerPubSubName() + public async Task TestPublishEventAsync() { - RegisterUserIntegrationEvent @event = new RegisterUserIntegrationEvent() + _eventBus.Setup(eventBus => eventBus.PublishAsync(It.IsAny())).Verifiable(); + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + _eventBus.Object, + _uoW.Object); + CreateUserEvent @event = new CreateUserEvent() { - Account = "lisa", - Password = "123456" + Name = "Tom" }; - var daprPubSubName = "PUBSUB"; - var serviceProvider = CreateCustomerDaprPubSubProvider(daprPubSubName, @event.Topic); - var eventBus = serviceProvider.GetRequiredService(); - await eventBus.PublishAsync(@event); - } + await integrationEventBus.PublishAsync(@event); + _eventBus.Verify(eventBus => eventBus.PublishAsync(It.IsAny()), Times.Once); + } [TestMethod] - public async Task CheckPublishEvent() + public async Task TestPublishEventAndNotEventBusAsync() { - ForgetPasswordEvent @event = new ForgetPasswordEvent() + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + null, + _uoW.Object); + CreateUserEvent @event = new CreateUserEvent() { - Account = "lisa" + Name = "Tom" }; - var daprPubSubName = "PUBSUB"; - var serviceProvider = CreateCustomerDaprPubSubProvider(daprPubSubName, ""); - var eventBus = serviceProvider.GetRequiredService(); - await eventBus.PublishAsync(@event); + await Assert.ThrowsExceptionAsync(async () => + { + await integrationEventBus.PublishAsync(@event); + }); } [TestMethod] - public async Task TestPublishEventAndNotUseEventBusAsync() + public async Task TestCommitAsync() { - IOptions options = Options.Create(new DispatcherOptions(new ServiceCollection())); - Mock client = new(); - Mock eventLogService = new(); - Mock> appConfig = new(); - Mock> logger = new(); + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + _eventBus.Object, + _uoW.Object); - var integrationEventBus = new IntegrationEventBus(options, client.Object, eventLogService.Object, appConfig.Object, logger.Object); - var @event = new CreateUserEvent("tom"); - await Assert.ThrowsExceptionAsync(async () => await integrationEventBus.PublishAsync(@event)); + await integrationEventBus.CommitAsync(default); + _uoW.Verify(uoW => uoW.CommitAsync(default), Times.Once); } [TestMethod] - public async Task TestPublishEventAsync() + public async Task TestNotUseUowCommitAsync() + { + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + _eventBus.Object, + null); + + await Assert.ThrowsExceptionAsync(async () => await integrationEventBus.CommitAsync()); + } + + [TestMethod] + public void TestGetAllEventTypes() { - IOptions options = Options.Create(new DispatcherOptions(new ServiceCollection()) + _dispatcherOptions.Setup(option => option.Value).Returns(() => new DispatcherOptions(_options.Object.Services) { - Assemblies = AppDomain.CurrentDomain.GetAssemblies() + Assemblies = new System.Reflection.Assembly[1] { typeof(IntegrationEventBusTest).Assembly } }); - Mock client = new(); - Mock eventLogService = new(); - Mock> appConfig = new(); - Mock> logger = new(); - - Mock eventBus = new(); - eventBus.Setup(e => e.PublishAsync(It.IsAny())).Verifiable(); - eventBus.Setup(e => e.GetAllEventTypes()).Returns(() => new List() - { - typeof(CreateUserEvent), - typeof(ForgetPasswordEvent), - typeof(RegisterUserIntegrationEvent) + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + null, + null); + + Assert.IsTrue(integrationEventBus.GetAllEventTypes().Count() == _dispatcherOptions.Object.Value.AllEventTypes.Count()); + } + + + [TestMethod] + public void TestUseEventBusGetAllEventTypes() + { + var defaultAssembly = new System.Reflection.Assembly[1] { typeof(IntegrationEventBusTest).Assembly }; + _dispatcherOptions.Setup(option => option.Value).Returns(() => new DispatcherOptions(_options.Object.Services) + { + Assemblies = defaultAssembly }); + var allEventType = defaultAssembly + .SelectMany(assembly => assembly.GetTypes()) + .Where(type => type.IsClass && typeof(IEvent).IsAssignableFrom(type)) + .ToList(); + _eventBus.Setup(eventBus => eventBus.GetAllEventTypes()).Returns(() => allEventType).Verifiable(); + var integrationEventBus = new IntegrationEventBus( + _dispatcherOptions.Object, + _daprClient.Object, + _eventLog.Object, + _appConfig.Object, + _logger.Object, + _eventBus.Object, + null); - var integrationEventBus = new IntegrationEventBus(options, client.Object, eventLogService.Object, appConfig.Object, logger.Object, eventBus.Object); - var @event = new CreateUserEvent("tom"); - await integrationEventBus.PublishAsync(@event); + Assert.IsTrue(integrationEventBus.GetAllEventTypes().Count() == _dispatcherOptions.Object.Value.AllEventTypes.Count()); + Assert.IsTrue(integrationEventBus.GetAllEventTypes().Count() == allEventType.Count()); + } - Assert.IsTrue(integrationEventBus.GetAllEventTypes().Count() == 3); + [TestMethod] + public void TestIntegrationEvent() + { + DateTime date = DateTime.UtcNow; + Guid id = Guid.NewGuid(); + RegisterUserIntegrationEvent @event = new RegisterUserIntegrationEvent() + { + Account = "lisa", + Password = "123456" + }; + Assert.IsTrue(@event.CreationTime > date); + Assert.IsTrue(@event.Id != default(Guid)); + + @event = new RegisterUserIntegrationEvent(id, date) + { + Account = "lisa", + Password = "123456" + }; + Assert.IsTrue(@event.CreationTime == date); + Assert.IsTrue(@event.Id == id); } public class IntegrationEventLogService : IIntegrationEventLogService diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.csproj b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.csproj index fbaf82443..408fa3576 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.csproj @@ -9,6 +9,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/RegisterServicesBusTest.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/RegisterServicesBusTest.cs deleted file mode 100644 index 8925a032c..000000000 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/RegisterServicesBusTest.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace MASA.Contrib.Dispatcher.IntegrationEvents.Tests; - -[TestClass] -public class RegisterServicesBusTest : TestBase -{ - [TestMethod] - public void TestEmptyDaprPubSubName() - { - var daprPubSubName = string.Empty; - Assert.ThrowsException(() => - { - var serviceProvider = CreateCustomerDaprPubSubProvider(daprPubSubName, "topic"); - }); - } -} diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/TestBase.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/TestBase.cs deleted file mode 100644 index 8c6a8dd03..000000000 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/TestBase.cs +++ /dev/null @@ -1,86 +0,0 @@ -namespace MASA.Contrib.Dispatcher.IntegrationEvents.Tests; - -[TestClass] -public class TestBase -{ - protected const string DAPR_PUBSUB_NAME = "pubsub"; - - protected IServiceProvider CreateDefaultProvider(string topic, Action? action = null) - { - return CreateProvider(services => - { - action?.Invoke(services); - Mock daprClient = new(); - daprClient.Setup(e => e.PublishEventAsync(DAPR_PUBSUB_NAME, topic, It.IsAny(), default)).Verifiable(); - services.AddSingleton(_ => daprClient.Object); - - services.AddDaprEventBus(); - }); - } - - protected IServiceProvider CreateCustomerDaprPubSubProvider(string daprPubSubName, string topic, Action? action = null) - { - return CreateCustomerDaprPubSubProvider(daprPubSubName, (services) => - { - action?.Invoke(services); - Mock daprClient = new(); - daprClient.Setup(e => e.PublishEventAsync(daprPubSubName, topic, It.IsAny(), default)).Verifiable(); - services.AddSingleton(_ => daprClient.Object); - }); - } - - protected IServiceProvider CreateCustomerDaprPubSubProvider(string daprPubSubName, Action? action = null) - { - return CreateProvider(services => - { - action?.Invoke(services); - services.AddDaprEventBus(options => options.PubSubName = daprPubSubName); - }); - } - - private IServiceProvider CreateProvider(Action? action = null) - { - var services = new ServiceCollection(); - services.AddLogging(loggingBuilder => loggingBuilder.AddConsole()); - - Mock eventBus = new(); - eventBus.Setup(e => e.PublishAsync(It.IsAny())).Verifiable(); - services.AddScoped((serviceProvider) => eventBus.Object); - - Mock unitWork = new(); - Mock dbTransaction = new(); - unitWork.Setup(u => u.Transaction).Returns(dbTransaction.Object); - services.AddScoped((serviceProvider) => unitWork.Object); - - action?.Invoke(services); - return services.BuildServiceProvider(); - } -} - -public class IntegrationEventLogService : IIntegrationEventLogService -{ - public Task MarkEventAsFailedAsync(Guid eventId) - { - return Task.CompletedTask; - } - - public Task MarkEventAsInProgressAsync(Guid eventId) - { - return Task.CompletedTask; - } - - public Task MarkEventAsPublishedAsync(Guid eventId) - { - return Task.CompletedTask; - } - - public Task> RetrieveEventLogsPendingToPublishAsync(Guid transactionId) - { - return Task.FromResult(new List().AsEnumerable()); - } - - public Task SaveEventAsync(IIntegrationEvent @event, DbTransaction transaction) - { - return Task.CompletedTask; - } -} diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/_Imports.cs index 6a4e8b6aa..d2b2f3b43 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/_Imports.cs @@ -7,8 +7,10 @@ global using MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Options; global using MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.Events; global using MASA.Contrib.Dispatcher.IntegrationEvents.Tests.Events; +global using MASA.Utils.Models.Config; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.Logging; +global using Microsoft.Extensions.Options; global using Microsoft.VisualStudio.TestTools.UnitTesting; global using Moq; global using System.Data.Common; diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/IntegrationEventLogServiceTest.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/IntegrationEventLogServiceTest.cs index f5d6b64a0..93555862f 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/IntegrationEventLogServiceTest.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/IntegrationEventLogServiceTest.cs @@ -1,6 +1,3 @@ -using MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.Infrastructure; -using Moq; - namespace MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests; [TestClass] @@ -42,28 +39,34 @@ public async Task TestEventLogServiceAsync() var eventLog = dbContext.EventLogs.FirstOrDefault(); Assert.IsNotNull(eventLog); Assert.IsTrue(eventLog.State == IntegrationEventStates.NotPublished); - Assert.IsTrue(eventLog.Id == @event.Id); + Assert.IsTrue(eventLog.EventId == @event.Id); var eventLogs = await eventLogService.RetrieveEventLogsPendingToPublishAsync(transactionId); Assert.IsNotNull(eventLogs.Count() == 1); eventLog = dbContext.EventLogs.FirstOrDefault(); Assert.IsNotNull(eventLog); Assert.IsTrue(eventLog.State == IntegrationEventStates.NotPublished); - Assert.IsTrue(eventLog.Id == @event.Id); + Assert.IsTrue(eventLog.EventId == @event.Id); + + + await Assert.ThrowsExceptionAsync(async () => + { + await eventLogService.MarkEventAsInProgressAsync(eventLog.Id); + }); + await eventLogService.MarkEventAsInProgressAsync(eventLog.EventId); - await eventLogService.MarkEventAsInProgressAsync(eventLog.Id); eventLog = dbContext.EventLogs.Where(x => x.Id == eventLog.Id).FirstOrDefault(); Assert.IsNotNull(eventLog); Assert.IsTrue(eventLog.State == IntegrationEventStates.InProgress); Assert.IsTrue(eventLog.TimesSent == 1); - await eventLogService.MarkEventAsPublishedAsync(eventLog.Id); + await eventLogService.MarkEventAsPublishedAsync(eventLog.EventId); eventLog = dbContext.EventLogs.Where(x => x.Id == eventLog.Id).FirstOrDefault(); Assert.IsNotNull(eventLog); Assert.IsTrue(eventLog.State == IntegrationEventStates.Published); - await eventLogService.MarkEventAsFailedAsync(eventLog.Id); + await eventLogService.MarkEventAsFailedAsync(eventLog.EventId); eventLog = dbContext.EventLogs.Where(x => x.Id == eventLog.Id).FirstOrDefault(); Assert.IsNotNull(eventLog); Assert.IsTrue(eventLog.State == IntegrationEventStates.PublishedFailed); @@ -124,7 +127,7 @@ public void TestGenericEventLog() public async Task TestCustomDbContextAsync() { var options = new DispatcherOptions(new ServiceCollection()); - options.Services.AddMasaDbContext(options => options.UseSqlite(_connection)); + options.Services.AddMasaDbContext(options => options.UseSqlite(_connection).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)); var integrationEventBus = new Mock(); integrationEventBus.Setup(e => e.GetAllEventTypes()).Returns(() => AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).Where(type => typeof(IIntegrationEvent).IsAssignableFrom(type))); diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.csproj b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.csproj index 1eaa4b8dc..49ddad2a7 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.csproj @@ -9,7 +9,11 @@ - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/TestBase.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/TestBase.cs index 012f5741b..57215634b 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/TestBase.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/TestBase.cs @@ -1,7 +1,3 @@ -using MASA.BuildingBlocks.Dispatcher.Events; -using Microsoft.Data.Sqlite; -using Moq; - namespace MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests; public class TestBase diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/_Imports.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/_Imports.cs index cb7e74de8..df7c1433c 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/_Imports.cs @@ -1,11 +1,15 @@ global using MASA.BuildingBlocks.Data.UoW; +global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents.Logs; global using MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.Domain.Entities; global using MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.Events; +global using MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.Infrastructure; global using MASA.Utils.Data.EntityFrameworkCore; +global using Microsoft.Data.Sqlite; global using Microsoft.EntityFrameworkCore; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using Moq; global using System.Data.Common; global using System.Text.Json.Serialization; diff --git a/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/Commands/CreateProductionCommand.cs b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/Commands/CreateProductionCommand.cs new file mode 100644 index 000000000..f4c4a22c3 --- /dev/null +++ b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/Commands/CreateProductionCommand.cs @@ -0,0 +1,8 @@ +namespace MASA.Contrib.ReadWriteSpliting.CQRS.Tests.Commands; + +public record CreateProductionCommand : Command +{ + public string Name { get; set; } + + public int Count { get; set; } +} diff --git a/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/CqrsTest.cs b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/CqrsTest.cs new file mode 100644 index 000000000..43f185bed --- /dev/null +++ b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/CqrsTest.cs @@ -0,0 +1,51 @@ +namespace MASA.Contrib.ReadWriteSpliting.CQRS.Tests; + +[TestClass] +public class CqrsTest +{ + private IServiceCollection _services; + private IServiceProvider _serviceProvider; + private IEventBus _eventBus; + + [TestInitialize] + public void Initialize() + { + _services = new ServiceCollection(); + _services.AddEventBus(); + _serviceProvider = _services.BuildServiceProvider(); + _eventBus = _serviceProvider.GetRequiredService(); + } + + + [DataTestMethod] + [DataRow("")] + [DataRow("tom")] + public void TestCommand(string name) + { + var command = new CreateProductionCommand() + { + Name = name, + Count = 0 + }; + _eventBus.PublishAsync(command); + if (string.IsNullOrEmpty(name)) + { + Assert.IsTrue(command.Count == 2); + } + else + { + Assert.IsTrue(command.Count == 1); + } + } + + [TestMethod] + public void TestQuery() + { + var query = new ProductionItemQuery() + { + ProductionId = "1" + }; + _eventBus.PublishAsync(query); + Assert.IsTrue(query.Result == "Apple"); + } +} diff --git a/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/CreateProductionCommandHandler.cs b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/CreateProductionCommandHandler.cs new file mode 100644 index 000000000..b87ada809 --- /dev/null +++ b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/CreateProductionCommandHandler.cs @@ -0,0 +1,24 @@ +namespace MASA.Contrib.ReadWriteSpliting.CQRS.Tests; + +public class CreateProductionCommandHandler : CommandHandler +{ + [EventHandler(1, Dispatcher.Events.Enums.FailureLevels.ThrowAndCancel, false)] + public override Task HandleAsync(CreateProductionCommand @event) + { + @event.Count++; + if (string.IsNullOrEmpty(@event.Name)) + throw new ArgumentNullException(nameof(@event)); + + if (@event.Id == default(Guid) || @event.CreationTime > DateTime.UtcNow) + throw new ArgumentNullException(nameof(@event)); + + return Task.CompletedTask; + } + + [EventHandler(1)] + public override Task CancelAsync(CreateProductionCommand @event) + { + @event.Count++; + return base.CancelAsync(@event); + } +} diff --git a/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/MASA.Contrib.ReadWriteSpliting.CQRS.Tests.csproj b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/MASA.Contrib.ReadWriteSpliting.CQRS.Tests.csproj new file mode 100644 index 000000000..16dccc410 --- /dev/null +++ b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/MASA.Contrib.ReadWriteSpliting.CQRS.Tests.csproj @@ -0,0 +1,27 @@ + + + + net6.0 + enable + false + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + diff --git a/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/ProductionQueryHandler.cs b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/ProductionQueryHandler.cs new file mode 100644 index 000000000..43deb0445 --- /dev/null +++ b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/ProductionQueryHandler.cs @@ -0,0 +1,18 @@ +namespace MASA.Contrib.ReadWriteSpliting.CQRS.Tests; + +public class ProductionQueryHandler : QueryHandler +{ + public override Task HandleAsync(ProductionItemQuery @event) + { + if (string.IsNullOrEmpty(@event.ProductionId)) + throw new ArgumentNullException(nameof(@event)); + + if (@event.Id == default(Guid) || @event.CreationTime > DateTime.UtcNow) + throw new ArgumentNullException(nameof(@event)); + + if (@event.ProductionId == "1") + @event.Result = "Apple"; + + return Task.CompletedTask; + } +} diff --git a/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/Queries/ProductionItemQuery.cs b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/Queries/ProductionItemQuery.cs new file mode 100644 index 000000000..2560231b3 --- /dev/null +++ b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/Queries/ProductionItemQuery.cs @@ -0,0 +1,8 @@ +namespace MASA.Contrib.ReadWriteSpliting.CQRS.Tests.Queries; + +public record ProductionItemQuery : Query +{ + public override string Result { get; set; } + + public string ProductionId { get; set; } +} diff --git a/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/_Imports.cs b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/_Imports.cs new file mode 100644 index 000000000..e01b69ac4 --- /dev/null +++ b/test/MASA.Contrib.ReadWriteSpliting.CQRS.Tests/_Imports.cs @@ -0,0 +1,8 @@ +global using MASA.BuildingBlocks.Dispatcher.Events; +global using MASA.Contrib.Dispatcher.Events; +global using MASA.Contrib.ReadWriteSpliting.CQRS.Commands; +global using MASA.Contrib.ReadWriteSpliting.CQRS.Queries; +global using MASA.Contrib.ReadWriteSpliting.CQRS.Tests.Commands; +global using MASA.Contrib.ReadWriteSpliting.CQRS.Tests.Queries; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/test/MASA.Contrib.Service.MinimalAPIs.Tests/MASA.Contrib.Service.MinimalAPIs.Tests.csproj b/test/MASA.Contrib.Service.MinimalAPIs.Tests/MASA.Contrib.Service.MinimalAPIs.Tests.csproj new file mode 100644 index 000000000..6d6fbd4ec --- /dev/null +++ b/test/MASA.Contrib.Service.MinimalAPIs.Tests/MASA.Contrib.Service.MinimalAPIs.Tests.csproj @@ -0,0 +1,26 @@ + + + + net6.0 + enable + false + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/test/MASA.Contrib.Service.MinimalAPIs.Tests/MinimalAPITest.cs b/test/MASA.Contrib.Service.MinimalAPIs.Tests/MinimalAPITest.cs new file mode 100644 index 000000000..dacff249c --- /dev/null +++ b/test/MASA.Contrib.Service.MinimalAPIs.Tests/MinimalAPITest.cs @@ -0,0 +1,48 @@ +namespace MASA.Contrib.Service.MinimalAPIs.Tests; + +[TestClass] +public class MinimalAPITest +{ + private WebApplicationBuilder _builder; + + [TestInitialize] + public void Initialize() + { + _builder = WebApplication.CreateBuilder(); + } + + [TestMethod] + public void TestAddMultiServices() + { + _builder.Services.AddServices(_builder); + _builder.Services.AddServices(_builder); + var servicePrvider = _builder.Services.BuildServiceProvider(); + Assert.IsTrue(servicePrvider.GetServices>().Count() == 1); + } + + [TestMethod] + public void AddService() + { + var app = _builder.AddServices(); + Assert.IsTrue(_builder.Services.Any(service => service.ServiceType == typeof(CustomService) && service.Lifetime == ServiceLifetime.Scoped)); + + var servicePrvider = _builder.Services.BuildServiceProvider(); + var customService = servicePrvider.GetService(); + Assert.IsNotNull(customService); + + Assert.ReferenceEquals(customService.App, app); + + Assert.ReferenceEquals(customService.Services, _builder.Services); + + Assert.IsNotNull(customService.GetRequiredService()); + Assert.IsNotNull(customService.GetService()); + + Assert.IsTrue(customService.Test() == 1); + + var newCustomService = servicePrvider.CreateScope().ServiceProvider.GetService(); + Assert.IsNotNull(newCustomService); + + Assert.IsTrue(newCustomService.Test() == 1); + + } +} diff --git a/test/MASA.Contrib.Service.MinimalAPIs.Tests/Services/CustomService.cs b/test/MASA.Contrib.Service.MinimalAPIs.Tests/Services/CustomService.cs new file mode 100644 index 000000000..b0ce6d588 --- /dev/null +++ b/test/MASA.Contrib.Service.MinimalAPIs.Tests/Services/CustomService.cs @@ -0,0 +1,13 @@ +namespace MASA.Contrib.Service.MinimalAPIs.Tests.Services; + +public class CustomService : ServiceBase +{ + private int _times = 0; + + public CustomService(IServiceCollection services) : base(services) + { + _times++; + } + + public int Test() => _times; +} diff --git a/test/MASA.Contrib.Service.MinimalAPIs.Tests/_Imports.cs b/test/MASA.Contrib.Service.MinimalAPIs.Tests/_Imports.cs new file mode 100644 index 000000000..7315683bd --- /dev/null +++ b/test/MASA.Contrib.Service.MinimalAPIs.Tests/_Imports.cs @@ -0,0 +1,4 @@ +global using MASA.Contrib.Service.MinimalAPIs.Tests.Services; +global using Microsoft.AspNetCore.Builder; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/test/MASA.Contribs.DDD.Domain.Entities/User.cs b/test/MASA.Contribs.DDD.Domain.Entities/Users.cs similarity index 68% rename from test/MASA.Contribs.DDD.Domain.Entities/User.cs rename to test/MASA.Contribs.DDD.Domain.Entities/Users.cs index 780cc5262..5d0a693ba 100644 --- a/test/MASA.Contribs.DDD.Domain.Entities/User.cs +++ b/test/MASA.Contribs.DDD.Domain.Entities/Users.cs @@ -1,6 +1,6 @@ namespace MASA.Contribs.DDD.Domain.Entities; -public class User : AggregateRoot +public class Users : AggregateRoot { public string Name { get; set; } } From ff884b8552bda1abaff741452866edc61a3a706c Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Mon, 15 Nov 2021 13:34:51 +0800 Subject: [PATCH 05/39] chore: support net6.0 --- .../MASA.Contrib.BasicAbility.Dcc.csproj | 12 +++---- .../MASA.Contrib.Configuration.csproj | 2 +- .../ServiceCollectionExtensions.cs | 26 +++++++++++++-- ...SA.Contrib.DDD.Domain.Repository.EF.csproj | 6 ++-- .../MASA.Contrib.DDD.Domain.csproj | 6 ++-- .../MASA.Contrib.Data.Contracts.EF.csproj | 10 +++--- .../MASA.Contrib.Data.UoW.EF.csproj | 10 +++--- .../MASA.Contrib.Dispatcher.Events.csproj | 14 ++++---- ...b.Dispatcher.IntegrationEvents.Dapr.csproj | 8 ++--- ...cher.IntegrationEvents.EventLogs.EF.csproj | 8 ++--- ...MASA.Contrib.ReadWriteSpliting.CQRS.csproj | 8 ++--- .../MASA.Contrib.Service.MinimalAPIs.csproj | 8 ++--- ...MASA.Contrib.BasicAbility.Dcc.Tests.csproj | 2 +- .../ConfigurationTest.cs | 32 ++----------------- ...trib.DDD.Domain.Repository.EF.Tests.csproj | 2 +- .../MASA.Contrib.DDD.Domain.Tests.csproj | 2 +- ...MASA.Contrib.Data.Contracts.EF.Test.csproj | 6 ++-- .../MASA.Contrib.Data.UoW.EF.Tests.csproj | 4 +-- ...spatcher.Events.BenchmarkDotnetTest.csproj | 2 +- ...ASA.Contrib.Dispatcher.Events.Tests.csproj | 2 +- ...atcher.IntegrationEvents.Dapr.Tests.csproj | 2 +- ...ntegrationEvents.EventLogs.EF.Tests.csproj | 4 +-- 22 files changed, 85 insertions(+), 91 deletions(-) diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj index e93f58247..728f6f733 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj @@ -7,14 +7,14 @@ - + - - - - - + + + + + diff --git a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj index 4cb44403d..e67c1cdb6 100644 --- a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj +++ b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Configuration/MASA.Contrib.Configuration/ServiceCollectionExtensions.cs b/src/Configuration/MASA.Contrib.Configuration/ServiceCollectionExtensions.cs index 8930bda1e..d1e7e2b83 100644 --- a/src/Configuration/MASA.Contrib.Configuration/ServiceCollectionExtensions.cs +++ b/src/Configuration/MASA.Contrib.Configuration/ServiceCollectionExtensions.cs @@ -6,16 +6,18 @@ public static WebApplicationBuilder AddMasaConfiguration( this WebApplicationBuilder builder, Action? configureDelegate = null) => builder.AddMasaConfiguration(configureDelegate, + "Appsettings", AppDomain.CurrentDomain.GetAssemblies()); public static WebApplicationBuilder AddMasaConfiguration( this WebApplicationBuilder builder, Action? configureDelegate, + string defaultSectionName = "Appsettings", params Assembly[] assemblies) { - // TODO Currently builder.Configuration does not support updating after refresh, wait for the problem to be fixed before processing - // https://github.com/dotnet/core/blob/main/release-notes/6.0/known-issues.md#configuration-not-reloaded-on-changes - var masaConfiguration = builder.Services.CreateMasaConfiguration(configureDelegate, assemblies: assemblies); + var configurationBuilder = GetConfigurationBuilder(builder.Configuration); + + IConfigurationRoot masaConfiguration = builder.Services.CreateMasaConfiguration(configureDelegate, configurationBuilder, defaultSectionName, assemblies); if (!masaConfiguration.Providers.Any()) return builder; @@ -80,6 +82,24 @@ public static IConfigurationRoot CreateMasaConfiguration( return configuration; } + private static IConfigurationBuilder GetConfigurationBuilder(ConfigurationManager configuration) + { + var configurationBuilder = new ConfigurationBuilder(); + foreach (var source in ((IConfigurationBuilder)configuration).Sources) + { + configurationBuilder.Add(source); + } + return configurationBuilder; + } + + private static void ClearSource(this WebApplicationBuilder builder) + { + Microsoft.Extensions.Hosting.HostingHostBuilderExtensions.ConfigureAppConfiguration(builder.Host, configBuilder => + { + configBuilder.Sources.Clear(); + }); + } + internal static void ConfigureOption( this IServiceCollection services, IConfiguration configuration, diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj index ae978ffb0..157469430 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj index 32938df06..bf611659f 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj index c6c6f6e88..fc6ac3d53 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj @@ -7,10 +7,10 @@ - - - - - + + + + + diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj index c4d0854ef..69bf5eaf1 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj +++ b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj @@ -7,11 +7,11 @@ - - - - - + + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj index 8c5760882..97c3c8cfb 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj @@ -7,13 +7,13 @@ - - - - - - - + + + + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj index 52fdcd26e..25023f0a6 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj index 87db25155..ed2f68ad2 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj index 029b97a4f..f157e9fb5 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj index 8cdd6f22d..d5abb9bb6 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj @@ -6,10 +6,10 @@ - - - - + + + + diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/MASA.Contrib.BasicAbility.Dcc.Tests.csproj b/test/MASA.Contrib.BasicAbility.Dcc.Tests/MASA.Contrib.BasicAbility.Dcc.Tests.csproj index d1fac8015..8d6f3f437 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/MASA.Contrib.BasicAbility.Dcc.Tests.csproj +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/MASA.Contrib.BasicAbility.Dcc.Tests.csproj @@ -21,7 +21,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs b/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs index 95555d15c..4c9f73154 100644 --- a/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs +++ b/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs @@ -53,10 +53,6 @@ public void TestAddCustomSection() var builder = WebApplication.CreateBuilder(); builder.AddMasaConfiguration(configurationBuilder => { - configurationBuilder.AddSection(new ConfigurationBuilder() - .SetBasePath(builder.Environment.ContentRootPath) - .AddJsonFile("appsettings.json", true, true), "Appsettings"); - configurationBuilder.AddSection(new ConfigurationBuilder() .SetBasePath(builder.Environment.ContentRootPath) .AddJsonFile("redis.json", true, true), "RedisOptions"); @@ -87,10 +83,6 @@ public void TestAddMasaConfiguration() var builder = WebApplication.CreateBuilder(); builder.AddMasaConfiguration(configurationBuilder => { - configurationBuilder.AddSection(new ConfigurationBuilder() - .SetBasePath(builder.Environment.ContentRootPath) - .AddJsonFile("appsettings.json", true, true), "Appsettings"); - configurationBuilder.AddSection(new ConfigurationBuilder() .SetBasePath(builder.Environment.ContentRootPath) .AddJsonFile("redis.json", true, true) @@ -120,10 +112,6 @@ public void TestAddMultiMasaConfiguration() var builder = WebApplication.CreateBuilder(); builder.AddMasaConfiguration(configurationBuilder => { - configurationBuilder.AddSection(new ConfigurationBuilder() - .SetBasePath(builder.Environment.ContentRootPath) - .AddJsonFile("appsettings.json", true, true), "Appsettings"); - configurationBuilder.AddSection(new ConfigurationBuilder() .SetBasePath(builder.Environment.ContentRootPath) .AddJsonFile("redis.json", true, true) @@ -160,12 +148,7 @@ public void TestAutoMapSectionError() Assert.ThrowsException(() => builder.AddMasaConfiguration(configurationBuilder => { - configurationBuilder.AddSection( - new ConfigurationBuilder() - .SetBasePath(builder.Environment.ContentRootPath) - .AddJsonFile("appsettings.json", true, true), "Appsettings" - ); - }, typeof(ConfigurationTest).Assembly, typeof(KafkaOptions).Assembly)); + }, "Appsettings", typeof(ConfigurationTest).Assembly, typeof(KafkaOptions).Assembly)); } [TestMethod] @@ -176,16 +159,11 @@ public void TestAutoMapAndErrorSection() { return builder.AddMasaConfiguration(configurationBuilder => { - configurationBuilder.AddSection(new ConfigurationBuilder() - .SetBasePath(builder.Environment.ContentRootPath) - .AddJsonFile("appsettings.json", true, true), "Appsettings" - ); - configurationBuilder.AddSection(new ConfigurationBuilder() .SetBasePath(builder.Environment.ContentRootPath) .AddJsonFile("redis.json", true, true) ); //Mount to the Local section - }, typeof(ConfigurationTest).Assembly, typeof(MountSectionRedisOptions).Assembly); + }, "Appsettings", typeof(ConfigurationTest).Assembly, typeof(MountSectionRedisOptions).Assembly); }); } @@ -257,10 +235,6 @@ public void TestConfigurationChange() var rootPath = builder.Environment.ContentRootPath; builder.AddMasaConfiguration(configurationBuilder => { - configurationBuilder.AddSection(new ConfigurationBuilder() - .SetBasePath(rootPath) - .AddJsonFile("appsettings.json", true, true), "Appsettings"); - configurationBuilder.AddSection(new ConfigurationBuilder() .SetBasePath(rootPath) .AddJsonFile("redis.json", true, true), "RedisOptions"); @@ -274,7 +248,7 @@ public void TestConfigurationChange() { option.Mapping(SectionTypes.Local, ""); }); - }, typeof(ConfigurationTest).Assembly); + }, "Appsettings", typeof(ConfigurationTest).Assembly); var serviceProvider = builder.Services.BuildServiceProvider(); var configuration = serviceProvider.GetRequiredService(); var systemOption = serviceProvider.GetRequiredService>(); diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj index abd64b60d..83b835a62 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj b/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj index 933831f6b..e4486a855 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj +++ b/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj index c245e76f6..ed6df73cc 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj @@ -17,9 +17,9 @@ - - - + + + diff --git a/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj b/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj index 7f3dbfe6c..78360345b 100644 --- a/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/MASA.Contrib.Data.UoW.EF.Tests.csproj @@ -12,8 +12,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj index ce74a9fd5..3b730f7ce 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj @@ -11,7 +11,7 @@ - + diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj b/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj index 961cda7cb..8f816f4b7 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj @@ -22,7 +22,7 @@ - + diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.csproj b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.csproj index 408fa3576..cedee4cdf 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.csproj b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.csproj index 49ddad2a7..dd5292367 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests.csproj @@ -13,12 +13,12 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + From f994c803f29e91ee158db79c38eb10ff21164fbb Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Wed, 17 Nov 2021 11:24:33 +0000 Subject: [PATCH 06/39] Doc/contrib --- README.md | 24 +- README.zh-CN.md | 34 ++- .../ConfigurationAPIClient.cs | 2 +- .../ConfigurationAPIManage.cs | 2 +- .../Internal/ConfigurationAPIBase.cs | 4 +- .../MASA.Contrib.BasicAbility.Dcc.csproj | 6 +- .../MasaConfigurationExtensions.cs | 25 +- .../Options/DccConfigurationOptions.cs | 6 +- .../MASA.Contrib.BasicAbility.Dcc/README.md | 164 ++++++++++++ .../README.zh-CN.md | 155 ++++++++++++ .../MASA.Contrib.BasicAbility.Dcc/_Imports.cs | 1 + .../MASA.Contrib.Configuration.csproj | 2 +- .../MASA.Contrib.Configuration/README.md | 135 ++++++++++ .../README.zh-CN.md | 140 +++++++++++ ...SA.Contrib.DDD.Domain.Repository.EF.csproj | 2 +- .../MASA.Contrib.DDD.Domain.csproj | 2 +- .../MASA.Contrib.Data.Contracts.EF.csproj | 6 +- .../MASA.Contrib.Data.Contracts.EF/README.md | 11 +- .../RREADME.zh-CN.md | 9 + .../MASA.Contrib.Data.UoW.EF.csproj | 6 +- src/Data/MASA.Contrib.Data.UoW.EF/README.md | 19 ++ .../MASA.Contrib.Data.UoW.EF/RREADME.zh-CN.md | 19 ++ .../MASA.Contrib.Dispatcher.Events.csproj | 8 +- ...b.Dispatcher.IntegrationEvents.Dapr.csproj | 4 +- ...cher.IntegrationEvents.EventLogs.EF.csproj | 4 +- ...MASA.Contrib.ReadWriteSpliting.CQRS.csproj | 4 +- .../MASA.Contrib.Service.MinimalAPIs.csproj | 6 +- .../DccManageTest.cs | 2 +- .../DccTest.cs | 233 +++++++++++------- ...MASA.Contrib.Data.Contracts.EF.Test.csproj | 4 +- 30 files changed, 878 insertions(+), 161 deletions(-) create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.md create mode 100644 src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.zh-CN.md create mode 100644 src/Configuration/MASA.Contrib.Configuration/README.md create mode 100644 src/Configuration/MASA.Contrib.Configuration/README.zh-CN.md create mode 100644 src/Data/MASA.Contrib.Data.UoW.EF/README.md create mode 100644 src/Data/MASA.Contrib.Data.UoW.EF/RREADME.zh-CN.md diff --git a/README.md b/README.md index 12df8110f..2dff7b60c 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,16 @@ MASA.Contrib ├── solution items │ ├── nuget.config ├── src +│ ├── BasicAbility +│ │ ├── MASA.Contrib.BasicAbility.Dcc ConfigurationAPI +│ ├── Configuration +│ │ ├── MASA.Contrib.Configuration │ ├── Data │ │ ├── MASA.Contrib.Data.UoW.EF Unit of work -│ │ └── MASA.Contribs.Data.Contracts.EF Protocol EF version +│ │ └── MASA.Contrib.Data.Contracts.EF Protocol EF version │ ├── DDD -│ │ ├── MASA.Contribs.DDD.Domain In-process and cross-process support -│ │ └── MASA.Contribs.DDD.Domain.Repository.EF +│ │ ├── MASA.Contrib.DDD.Domain In-process and cross-process support +│ │ └── MASA.Contrib.DDD.Domain.Repository.EF │ ├── Dispatcher │ │ ├── MASA.Contrib.Dispatcher.Events In-process event │ │ ├── MASA.Contrib.Dispatcher.IntegrationEvents.Dapr @@ -38,8 +42,8 @@ MASA.Contrib │ │ ├── MASA.Contrib.Dispatcher.Events.Tests │ ├── MASA.Contrib.Data.UoW.EF.Tests │ ├── MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests -│ ├── MASA.Contribs.DDD.Domain.Tests -│ ├── MASA.Contribs.DDD.Domain.Repository.EF.Tests +│ ├── MASA.Contrib.DDD.Domain.Tests +│ ├── MASA.Contrib.DDD.Domain.Repository.EF.Tests ``` ## Feature @@ -83,7 +87,7 @@ Realize cross-process events based on Dapr。[Usage introduction](/src/Dispatche ### 5. DomainEventBus -[Usage introduction](/src/DDD/MASA.Contribs.DDD.Domain/README.md) +[Usage introduction](/src/DDD/MASA.Contrib.DDD.Domain/README.md) > Advantage: > @@ -99,7 +103,7 @@ Realize cross-process events based on Dapr。[Usage introduction](/src/Dispatche ### 7. Contracts.EF -Protocol based on EF implementation,[Usage introduction](/Data/MASA.Contribs.Data.Contracts.EF/README.md) +Protocol based on EF implementation,[Usage introduction](/Data/MASA.Contrib.Data.Contracts.EF/README.md) > Advantage: > @@ -108,7 +112,7 @@ Protocol based on EF implementation,[Usage introduction](/Data/MASA.Contribs.D > 3. Soft delete ```C# -Install-Package MASA.Contribs.Data.Contracts.EF +Install-Package MASA.Contrib.Data.Contracts.EF ``` ```C# @@ -124,6 +128,10 @@ builder.Services > Do not query the data marked as soft deleted when querying > When combined with EventBus, the transaction is opened after the first CUD, and the transaction rollback is supported when the entire Handler is abnormal. +### 8. MASA.Contrib.Configuration + +Redefine Configuration, support the management of Local and ConfigurationAPI nodes, combine IOptions and IOptionsMonitor to complete configuration acquisition and configuration update subscription [Local Usage introduction](src/Configuration/MASA.Contrib.Configuration/README.md) 、[Dcc Usage introduction](src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.md) + ## Unit testing rules To ensure the reliability of the entire source code, the unit test coverage is at least 90% diff --git a/README.zh-CN.md b/README.zh-CN.md index 36a97a2a1..3ba8b29be 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,4 +1,4 @@ -中 | [EN](README.md) +中 | [EN](README.md) # MASA.Contrib @@ -11,12 +11,16 @@ MASA.Contrib ├── solution items │ ├── nuget.config ├── src +│ ├── BasicAbility +│ │ ├── MASA.Contrib.BasicAbility.Dcc ConfigurationAPI +│ ├── Configuration +│ │ ├── MASA.Contrib.Configuration │ ├── Data │ │ ├── MASA.Contrib.Data.UoW.EF 工作单元 -│ │ └── MASA.Contribs.Data.Contracts.EF 规约EF版 +│ │ └── MASA.Contrib.Data.Contracts.EF 规约EF版 │ ├── DDD -│ │ ├── MASA.Contribs.DDD.Domain 进程内、跨进程都支持 -│ │ └── MASA.Contribs.DDD.Domain.Repository.EF +│ │ ├── MASA.Contrib.DDD.Domain 进程内、跨进程都支持 +│ │ └── MASA.Contrib.DDD.Domain.Repository.EF │ ├── Dispatcher │ │ ├── MASA.Contrib.Dispatcher.Events 进程内事件 │ │ ├── MASA.Contrib.Dispatcher.IntegrationEvents.Dapr @@ -38,15 +42,15 @@ MASA.Contrib │ │ ├── MASA.Contrib.Dispatcher.Events.Tests │ ├── MASA.Contrib.Data.UoW.EF.Tests │ ├── MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests -│ ├── MASA.Contribs.DDD.Domain.Tests -│ ├── MASA.Contribs.DDD.Domain.Repository.EF.Tests +│ ├── MASA.Contrib.DDD.Domain.Tests +│ ├── MASA.Contrib.DDD.Domain.Repository.EF.Tests ``` ## 特性 ### 1. MinimalAPI -什么是[MinimalAPI](https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis)?[用法介绍](/src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-cn.md) +什么是[MinimalAPI](https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/#introducing-minimal-apis)?[用法介绍](/src/Service/MASA.Contrib.Service.MinimalAPIs/README.zh-CN.md) > 优势: > @@ -54,7 +58,7 @@ MASA.Contrib ### 2. EventBus -[用法介绍](/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-cn.md) +[用法介绍](/src/Dispatcher/MASA.Contrib.Dispatcher.Events/README.zh-CN.md) > 优势: > @@ -73,17 +77,17 @@ MASA.Contrib ### 3. CQRS -什么是[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)?[用法介绍](/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-cn.md) +什么是[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)?[用法介绍](/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/README.zh-CN.md) ### 4. IntegrationEventBus -基于Dapr实现跨进程的事件。[用法介绍](/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-cn.md) +基于Dapr实现跨进程的事件。[用法介绍](/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/README.zh-CN.md) > 优势:将用户自定义上下文与日志使用同一事务提交,确保原子性、一致性 ### 5. DomainEventBus -[用法介绍](/src/DDD/MASA.Contribs.DDD.Domain/README.zh-cn.md) +[用法介绍](/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md) > 优势: > @@ -99,7 +103,7 @@ MASA.Contrib ### 7. Contracts.EF -基于EF实现的规约,[用法介绍](/Data/MASA.Contribs.Data.Contracts.EF/README.zh-cn.md) +基于EF实现的规约,[用法介绍](src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-CN.md) > 优势: > @@ -108,7 +112,7 @@ MASA.Contrib > 3. 软删除 ```C# -Install-Package MASA.Contribs.Data.Contracts.EF +Install-Package MASA.Contrib.Data.Contracts.EF ``` ```C# @@ -124,6 +128,10 @@ builder.Services > 支持查询的时候不查询被标记软删除的数据 > 与EventBus结合使用时,做到了第一次CUD后开启事务,当整个Handler出现异常后支持事务回滚 +### 8. MASA.Contrib.Configuration + +重定义Configuration,支持Local、ConfigurationAPI节点的管理,结合IOptions、IOptionsMonitor完成配置的获取以及配置的更新订阅 [Local用法介绍](src/Configuration/MASA.Contrib.Configuration/README.zh-CN.md) 、[Dcc用法介绍](src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.zh-CN.md) + ## 单元测试规则 为确保整个源码的可靠性,单元测试覆盖率最低为90% diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs index 4ae0fab47..69cd2c7c1 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs @@ -115,5 +115,5 @@ public async Task GetDynamicAsync(string environment, string cluster, s } private string FomartKey(string environment, string cluster, string appId, string configObject) - => $"{GetEnvironment(environment)}-{GetCluster(cluster)}-{GetAppid(appId)}-{GetConfigObject(configObject)}".ToLower(); + => $"{GetEnvironment(environment)}-{GetCluster(cluster)}-{GetAppId(appId)}-{GetConfigObject(configObject)}".ToLower(); } diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIManage.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIManage.cs index 406a03583..530106401 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIManage.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIManage.cs @@ -15,7 +15,7 @@ public ConfigurationAPIManage( public async Task UpdateAsync(string environment, string cluster, string appId, string configObject, object value) { - var requestUri = $"open-api/releasing/{GetEnvironment(environment)}/{GetCluster(cluster)}/{GetAppid(appId)}/{GetConfigObject(configObject)}?secret={GetSecret(appId)}"; + var requestUri = $"open-api/releasing/{GetEnvironment(environment)}/{GetCluster(cluster)}/{GetAppId(appId)}/{GetConfigObject(configObject)}?secret={GetSecret(appId)}"; var result = await _callerProvider.PutAsync(requestUri, value, default); // 299 is the status code when throwing a UserFriendlyException in masa.framework diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigurationAPIBase.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigurationAPIBase.cs index 19ccc2214..cbbd6b8c5 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigurationAPIBase.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/ConfigurationAPIBase.cs @@ -13,7 +13,7 @@ protected ConfigurationAPIBase(DccSectionOptions defaultSectionOption, List x.AppId == appId); @@ -29,7 +29,7 @@ protected string GetEnvironment(string environment) protected string GetCluster(string cluster) => !string.IsNullOrEmpty(cluster) ? cluster : _defaultSectionOption.Cluster!; - protected string GetAppid(string appId) + protected string GetAppId(string appId) => !string.IsNullOrEmpty(appId) ? appId : _defaultSectionOption.AppId!; protected string GetConfigObject(string configObject) diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj index 728f6f733..3fdf48994 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj @@ -7,11 +7,11 @@ - + - - + + diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs index 9840f628d..1ba1baf72 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs @@ -2,14 +2,14 @@ namespace MASA.Contrib.BasicAbility.Dcc; public static class MasaConfigurationExtensions { - public static IMasaConfigurationBuilder UseDCC( + public static IMasaConfigurationBuilder UseDcc( this IMasaConfigurationBuilder builder, IServiceCollection services, Action? jsonSerializerOptions = null, Action? callerOptions = null) - => builder.UseDCC(services, "Appsettings", jsonSerializerOptions, callerOptions); + => builder.UseDcc(services, "Appsettings", jsonSerializerOptions, callerOptions); - public static IMasaConfigurationBuilder UseDCC( + public static IMasaConfigurationBuilder UseDcc( this IMasaConfigurationBuilder builder, IServiceCollection services, string defaultSectionName, @@ -29,7 +29,7 @@ public static IMasaConfigurationBuilder UseDCC( configurationExpandSection.Bind(expandSections); } - return builder.UseDCC(services, () => dccOptions, option => + return builder.UseDcc(services, () => dccOptions, option => { option.Environment = configuration["Environment"]; option.Cluster = configuration["Cluster"]; @@ -39,7 +39,7 @@ public static IMasaConfigurationBuilder UseDCC( }, option => option.ExpandSections = expandSections, jsonSerializerOptions, callerOptions); } - public static IMasaConfigurationBuilder UseDCC( + public static IMasaConfigurationBuilder UseDcc( this IMasaConfigurationBuilder builder, IServiceCollection services, Func configureOptions, @@ -65,7 +65,7 @@ public static IMasaConfigurationBuilder UseDCC( if (callerOptions == null) { Options.UseHttpClient(() - => new MasaHttpClientBuilder(DEFAULT_CLIENT_NAME, string.Empty, opt => opt.BaseAddress = new Uri(config.DccConfigurationOption.DccServiceAddress), jsonSerializerOption) + => new MasaHttpClientBuilder(DEFAULT_CLIENT_NAME, string.Empty, opt => opt.BaseAddress = new Uri(config.DccConfigurationOption.ManageServiceAddress), jsonSerializerOption) ); } else @@ -74,7 +74,7 @@ public static IMasaConfigurationBuilder UseDCC( } }); - services.AddMasaRedisCache(DEFAULT_CLIENT_NAME, config.DccConfigurationOption).AddSharedMasaMemoryCache(config.DccConfigurationOption.SubscribeKeyPrefix ?? DEFAULT_SUBSCRIBE_KEY_PREFIX); + services.AddMasaRedisCache(DEFAULT_CLIENT_NAME, config.DccConfigurationOption.RedisOptions).AddSharedMasaMemoryCache(config.DccConfigurationOption.SubscribeKeyPrefix ?? DEFAULT_SUBSCRIBE_KEY_PREFIX); TryAddConfigurationAPIClient(services, config.DefaultSectionOption, config.ExpansionSectionOptions, jsonSerializerOption); TryAddConfigurationAPIManage(services, config.DefaultSectionOption, config.ExpansionSectionOptions); @@ -129,11 +129,14 @@ private static (DccSectionOptions DefaultSectionOption, List if (dccConfigurationOption == null) throw new ArgumentNullException(nameof(configureOptions)); - if (string.IsNullOrEmpty(dccConfigurationOption.DccServiceAddress)) - throw new ArgumentNullException(nameof(dccConfigurationOption.DccServiceAddress)); + if (string.IsNullOrEmpty(dccConfigurationOption.ManageServiceAddress)) + throw new ArgumentNullException(nameof(dccConfigurationOption.ManageServiceAddress)); - if (dccConfigurationOption.Servers == null || dccConfigurationOption.Servers.Count == 0 || dccConfigurationOption.Servers.Any(service => string.IsNullOrEmpty(service.Host) || service.Port <= 0)) - throw new ArgumentNullException(nameof(dccConfigurationOption.Servers)); + if (dccConfigurationOption.RedisOptions == null) + throw new ArgumentNullException(nameof(dccConfigurationOption.RedisOptions)); + + if (dccConfigurationOption.RedisOptions.Servers == null || dccConfigurationOption.RedisOptions.Servers.Count == 0 || dccConfigurationOption.RedisOptions.Servers.Any(service => string.IsNullOrEmpty(service.Host) || service.Port <= 0)) + throw new ArgumentNullException(nameof(dccConfigurationOption.RedisOptions.Servers)); if (defaultSectionOptions == null) throw new ArgumentNullException(nameof(defaultSectionOptions)); diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccConfigurationOptions.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccConfigurationOptions.cs index 2ecfb9da2..6ee6baf4f 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccConfigurationOptions.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Options/DccConfigurationOptions.cs @@ -1,8 +1,10 @@ namespace MASA.Contrib.BasicAbility.Dcc.Options; -public class DccConfigurationOptions : RedisConfigurationOptions +public class DccConfigurationOptions { - public string DccServiceAddress { get; set; } = default!; + public RedisConfigurationOptions RedisOptions { get; set; } + + public string ManageServiceAddress { get; set; } = default!; /// /// The prefix of Dcc PubSub, it is not recommended to modify diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.md b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.md new file mode 100644 index 000000000..d74017c3a --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.md @@ -0,0 +1,164 @@ +[中](README.zh-CN.md) | EN + +## MASA.Contrib.BasicAbility.Dcc + +Effect: + +Extend the ability of IConfiguration to manage remote configuration through Dcc. + +```c# +IConfiguration +├── Local Local node (fixed) +├── ConfigurationAPI Remote node (fixed Dcc to expand its capacity) +│ ├── AppId Replace-With-Your-AppId +│ ├── AppId ├── Platforms Custom node +│ ├── AppId ├── Platforms ├── Name Parameter Name +│ ├── AppId ├── DataDictionary Dictionary (fixed) The type of Text in DCC is mounted here +``` + +Example: + +```C# +Install-Package MASA.Contrib.Configuration +Install-Package MASA.Contrib.BasicAbility.Dcc //Provides the ability to remotely configure +``` + +appsettings.json +``` +{ + //Dcc configuration, extended Configuration capabilities, support remote configuration + "DccOptions": { + "ManageServiceAddress": "http://localhost:8890", + "RedisOptions": { + "Servers": [ + { + "Host": "localhost", + "Port": 8889 + } + ], + "DefaultDatabase": 0, + "Password": "" + } + }, + "AppId": "Replace-With-Your-AppId", + "Environment": "Development", + "ConfigObjects": [ "Platforms" ], //The name of the object to be mounted, the Platforms configuration will be mounted here under the ConfigurationAPI: node + "Secret": "", //Dcc App key + "Cluster": "Default" +} + +``` + +```C# +builder.AddMasaConfiguration(configurationBuilder => +{ + configurationBuilder.UseDcc(builder.Services);//Use Dcc + + options.Mapping(SectionTypes.Local, "Appsettings", ""); //Map CustomDccSectionOptions to the Appsettings node under Local +}); + +/// +/// Automatically map node relationships +/// +public class PlatformOptions : MasaConfigurationOptions +{ + public override SectionTypes SectionType { get; init; } = SectionTypes.ConfigurationAPI; + + [JsonIgnore] + public virtual string? ParentSection { get; init; } = "AppId"; + + [JsonIgnore] + public virtual string? Section { get; init; } = "Platforms"; + + public string Name { get; set; } +} + +public class CustomDccSectionOptions +{ + /// + /// The environment name. + /// Get from the environment variable ASPNETCORE_ENVIRONMENT when Environment is null or empty + /// + public string? Environment { get; set; } = null; + + /// + /// The cluster name. + /// + public string? Cluster { get; set; } + + /// + /// The app id. + /// + public string AppId { get; set; } = default!; + + public List ConfigObjects { get; set; } = default!; + + public string? Secret { get; set; } +} +``` + +How to use configuration: + +```c# +var app = builder.Build(); + +app.MapGet("/GetPlatform", ([FromServices] IOptions option) => +{ + //recommend + return System.Text.Json.JsonSerializer.Serialize(option.Value);//Or use IOptionsMonitor to support monitoring changes +}); + +app.MapGet("/GetPlatformByMonitor", ([FromServices] IOptionsMonitor options) => +{ + options.OnChange(option => + { + //TODO Configuration update + }); + return System.Text.Json.JsonSerializer.Serialize(option.CurrentValue); +}); + +app.MapGet("/GetPlatformName", ([FromServices] IConfiguration configuration) => +{ + //Format ConfigurationAPI::: + return configuration["ConfigurationAPI::Platforms:Name"]; +}); + +app.MapPut("/UpdatePlatform", ([FromServices] IConfigurationAPIManage configurationAPIManage, + [FromServices] IOptions configuration, + PlatformOptions newPlatform) => +{ + //Modify Dcc configuration + return configurationAPIManage.UpdateAsync(option.Value.Environment, + option.Value.Cluster, + option.Value.AppId, + "",newPlatform);//Here Replace-With-Your-ConfigObject is Platforms +}); +app.Run(); +``` + +How to update the configuration: + +```c# +var app = builder.Build(); + +app.MapPut("/UpdatePlatform", ([FromServices] IConfigurationAPIManage configurationAPIManage, + [FromServices] IOptions configuration, + PlatformOptions newPlatform) => +{ + //Modify Dcc configuration + return configurationAPIManage.UpdateAsync(option.Value.Environment, + option.Value.Cluster, + option.Value.AppId, + "" + ,newPlatform); + //Here Replace-With-Your-ConfigObject is Platforms +}); + +app.Run(); +``` + +Summarize: + +Dcc provides remote configuration management and viewing capabilities for IConfiguration. For the complete capabilities of IConfiguration, please refer to the [document](../../Configuration/MASA.Contrib.Configuration/README.md) + +Platforms here is remote configuration, which introduces the effect and usage of remote configuration after mounting to IConfiguration. This configuration has nothing to do with Platforms in MASA.Contrib.Configuration. It just shows the use of the same configuration information in two sources. Ways and differences in mapping node relationships \ No newline at end of file diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.zh-CN.md b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.zh-CN.md new file mode 100644 index 000000000..d55b20ac9 --- /dev/null +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/README.zh-CN.md @@ -0,0 +1,155 @@ +中 | [EN](README.md) + +## MASA.Contrib.BasicAbility.Dcc + +作用: + +通过Dcc扩展IConfiguration管理远程配置的能力。 + +```c# +IConfiguration +├── Local 本地节点(固定) +├── ConfigurationAPI 远程节点(固定 Dcc扩展其能力) +│ ├── AppId Replace-With-Your-AppId +│ ├── AppId ├── Platforms 自定义节点 +│ ├── AppId ├── Platforms ├── Name 参数 +│ ├── AppId ├── DataDictionary 字典(固定)DCC中类型为Text的挂载到此处 +``` + +用例: + +```C# +Install-Package MASA.Contrib.Configuration +Install-Package MASA.Contrib.BasicAbility.Dcc //提供远程配置的能力 +``` + +appsettings.json +``` +{ + //Dcc配置,扩展Configuration能力,支持远程配置 + "DccOptions": { + "ManageServiceAddress ": "http://localhost:8890", + "RedisOptions": { + "Servers": [ + { + "Host": "localhost", + "Port": 8889 + } + ], + "DefaultDatabase": 0, + "Password": "" + } + }, + "AppId": "Replace-With-Your-AppId", + "Environment": "Development", + "ConfigObjects": [ "Platforms" ], //待挂载的对象名, 此处会将Platforms配置挂载到ConfigurationAPI:节点下 + "Secret": "", //Dcc App 秘钥 + "Cluster": "Default" +} + +``` + +```C# +builder.AddMasaConfiguration(configurationBuilder => +{ + configurationBuilder.UseDcc(builder.Services);//使用Dcc提供远程配置的能力 + + options.Mapping(SectionTypes.Local, "Appsettings", ""); //将CustomDccSectionOptions映射到Local下的Appsettings节点 +}); + +/// +/// 自动映射节点关系 +/// +public class PlatformOptions : MasaConfigurationOptions +{ + public override SectionTypes SectionType { get; init; } = SectionTypes.ConfigurationAPI; + + [JsonIgnore] + public virtual string? ParentSection { get; init; } = "Replace-With-Your-AppId"; + + [JsonIgnore] + public virtual string? Section { get; init; } = "Platforms"; + + public string Name { get; set; } +} + +public class CustomDccSectionOptions +{ + /// + /// The environment name. + /// Get from the environment variable ASPNETCORE_ENVIRONMENT when Environment is null or empty + /// + public string? Environment { get; set; } = null; + + /// + /// The cluster name. + /// + public string? Cluster { get; set; } + + /// + /// The app id. + /// + public string AppId { get; set; } = default!; + + public List ConfigObjects { get; set; } = default!; + + public string? Secret { get; set; } +} +``` + +如何使用配置: + +```c# +var app = builder.Build(); + +app.MapGet("/GetPlatform", ([FromServices] IOptions option) => +{ + //推荐 + return System.Text.Json.JsonSerializer.Serialize(option.Value); +}); + +app.MapGet("/GetPlatformByMonitor", ([FromServices] IOptionsMonitor options) => +{ + options.OnChange(option => + { + //TODO 配置更新 + }); + return System.Text.Json.JsonSerializer.Serialize(option.CurrentValue); +}); + +app.MapGet("/GetPlatformName", ([FromServices] IConfiguration configuration) => +{ + //格式:ConfigurationAPI::: + return configuration["ConfigurationAPI::Platforms:Name"]; +}); + +app.Run(); +``` + +如何更新配置 + + +```c# +var app = builder.Build(); + +app.MapPut("/UpdatePlatform", ([FromServices] IConfigurationAPIManage configurationAPIManage, + [FromServices] IOptions configuration, + PlatformOptions newPlatform) => +{ + //修改Dcc配置 + return configurationAPIManage.UpdateAsync(option.Value.Environment, + option.Value.Cluster, + option.Value.AppId, + "" + ,newPlatform); + //此处Replace-With-Your-ConfigObject是Platforms +}); + +app.Run(); +``` + +总结: + +Dcc为IConfiguration提供了远程配置的管理以及查看能力,IConfiguration完整的能力请查看[文档](../../Configuration/MASA.Contrib.Configuration/README.zh-CN.md) + +此处Platforms为远程配置,介绍的是远程配置挂载到IConfiguration之后的效果以及用法,此配置与MASA.Contrib.Configuration中Platforms的毫无关系,仅仅是展示同一个配置信息在两个源的使用方式以及映射节点关系的差别 \ No newline at end of file diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/_Imports.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/_Imports.cs index b31c76679..a25cf5516 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/_Imports.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/_Imports.cs @@ -21,3 +21,4 @@ global using System.Dynamic; global using System.Text.Json; global using static MASA.Contrib.BasicAbility.Dcc.Internal.Constants; + diff --git a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj index e67c1cdb6..466710bf9 100644 --- a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj +++ b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Configuration/MASA.Contrib.Configuration/README.md b/src/Configuration/MASA.Contrib.Configuration/README.md new file mode 100644 index 000000000..921dd0058 --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/README.md @@ -0,0 +1,135 @@ +[中](README.zh-CN.md) | EN + +## MASA.Contrib.Configuration + +Structure: + +```c# +IConfiguration +├── Local Local node (fixed) +│ ├── Appsettings Default local node +│ ├── ├── Platforms Custom configuration +│ ├── ├── ├── Name Parameter name +├── ConfigurationAPI Remote node (fixed) +│ ├── AppId Replace-With-Your-AppId +│ ├── AppId ├── Platforms Custom node +│ ├── AppId ├── Platforms ├── Name Parameter name +│ ├── AppId ├── DataDictionary Dictionary (fixed) +``` + +Example: + +```C# +Install-Package MASA.Contrib.Configuration +Install-Package MASA.Contrib.BasicAbility.Dcc //DCC can provide remote configuration capabilities +```json +{ + //Custom configuration + "Platforms": { + "Name": "Masa.Demo" + }, + //Dcc configuration, extended Configuration capabilities, support remote configuration + "DccOptions": { + "ManageServiceAddress": "http://localhost:8890", + "RedisOptions": { + "Servers": [ + { + "Host": "localhost", + "Port": 8889 + } + ], + "DefaultDatabase": 0, + "Password": "" + } + }, + "AppId": "Replace-With-Your-AppId", + "ConfigObjects": [ "Platforms" ], //The name of the object to be mounted. Here, the Platforms configuration will be mounted under the ConfigurationAPI: node + "Secret": "", //Dcc App key + "Cluster": "Default" +} +``` + +Automatically map node relationships: + +```c# +public class PlatformOptions : MasaConfigurationOptions +{ + public override SectionTypes SectionType { get; init; } = SectionTypes.Local; + + [JsonIgnore] + public override string? ParentSection { get; init; } = "Appsettings"; + + [JsonIgnore] + public override string? Section { get; init; } = "Platforms"; + + public string Name { get; set; } +} + +//Use MasaConfiguration to take over Configuration, and mount the current Configuration to Local:Appsettings section by default +builder.AddMasaConfiguration(configurationBuilder => +{ + //configurationBuilder.UseDcc(builder.Services);//Use Dcc to extend Configuration capabilities and support remote configuration +}); +``` + +Or manually map node relationships: + +```C# +builder.AddMasaConfiguration(configurationBuilder => +{ + //configurationBuilder.UseDcc(builder.Services);//Use Dcc to extend Configuration capabilities and support remote configuration + + configurationBuilder.UseMasaOptions(options => + { + options.Mapping(SectionTypes.Local, "Appsettings", "Platforms"); //Map the PlatformOptions binding to the Local:Appsettings:Platforms node + }); +}); +``` + +how to use: + +```c# +var app = builder.Build(); + +app.Map("/GetPlatform", ([FromServices] IOptions option) => +{ + //Recommended (need to automatically or manually map the node relationship before it can be used) + return System.Text.Json.JsonSerializer.Serialize(option.Value); +}); + +app.Map("/GetPlatform", ([FromServices] IOptionsMonitor option) => +{ + //Recommended (need to automatically or manually map the node relationship before it can be used) + options.OnChange(option => + { + //TODO Configuration update service + }); + + return System.Text.Json.JsonSerializer.Serialize(option.CurrentValue); +}); + +app.Map("/GetPlatformName", ([FromServices] IConfiguration configuration) => +{ + //Base + return configuration["Local:Appsettings:Platforms:Name"]; +}); + +app.Run(); +``` + +How to take over more local nodes? + +```c# +builder.AddMasaConfiguration(builder =>{ + + builder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("custom.json", true, true), "Custom");//Mount the custom.json configuration under the Local:Custom node +}); +``` + +Tip: + +Configuration automatically obtains classes that inherit the IMasaConfigurationOptions interface by default, and maps the node relationship to facilitate obtaining configuration information through IOptions, IOptionsSnapshot, and IOptionsMonitor + +The above Platforms is a local configuration, used to demonstrate the effect and usage of the local configuration after being mounted to IConfiguration \ No newline at end of file diff --git a/src/Configuration/MASA.Contrib.Configuration/README.zh-CN.md b/src/Configuration/MASA.Contrib.Configuration/README.zh-CN.md new file mode 100644 index 000000000..0bd1a1830 --- /dev/null +++ b/src/Configuration/MASA.Contrib.Configuration/README.zh-CN.md @@ -0,0 +1,140 @@ +中 | [EN](README.md) + +## MASA.Contrib.Configuration + +结构: + +```c# +IConfiguration +├── Local 本地节点(固定) +│ ├── Appsettings 默认本地节点 +│ ├── ├── Platforms 自定义配置 +│ ├── ├── ├── Name 参数 +├── ConfigurationAPI 远程节点(固定) +│ ├── AppId Replace-With-Your-AppId +│ ├── AppId ├── Platforms 自定义节点 +│ ├── AppId ├── Platforms ├── Name 参数 +│ ├── AppId ├── DataDictionary 字典(固定) +``` + +用例: + +```C# +Install-Package MASA.Contrib.Configuration +Install-Package MASA.Contrib.BasicAbility.Dcc //DCC可提供远程配置的能力 +``` + +appsettings.json +```json +{ + //自定义配置 + "Platforms": { + "Name": "Masa.Demo" + }, + //Dcc配置,扩展Configuration能力,支持远程配置 + "DccOptions": { + "ManageServiceAddress ": "http://localhost:8890", + "RedisOptions": { + "Servers": [ + { + "Host": "localhost", + "Port": 8889 + } + ], + "DefaultDatabase": 0, + "Password": "" + } + }, + "AppId": "Replace-With-Your-AppId", + "ConfigObjects": [ "Platforms" ], // 要挂载的对象名称,此处会将Platforms配置挂载到ConfigurationAPI:节点下 + "Secret": "", //Dcc App 秘钥 + "Cluster": "Default" +} +``` + +自动映射节点关系: + +```c# +/// +/// 自动映射节点关系 +/// +public class PlatformOptions : MasaConfigurationOptions +{ + public override SectionTypes SectionType { get; init; } = SectionTypes.Local; + + [JsonIgnore] + public override string? ParentSection { get; init; } = "Appsettings"; + + [JsonIgnore] + public override string? Section { get; init; } = "Platforms"; + + public string Name { get; set; } +} + +//使用MasaConfiguration接管Configuration,默认会将当前的Configuration挂载到Local:Appsettings节点 +builder.AddMasaConfiguration(configurationBuilder => +{ + //configurationBuilder.UseDcc(builder.Services);//使用Dcc 扩展Configuration能力,支持远程配置 +}); +``` + +或手动添加映射节点关系: + +```C# +builder.AddMasaConfiguration(configurationBuilder => +{ + //configurationBuilder.UseDcc(builder.Services);//使用Dcc 扩展Configuration能力,支持远程配置 + + configurationBuilder.UseMasaOptions(options => + { + options.Mapping(SectionTypes.Local, "Appsettings", "Platforms"); //将PlatformOptions绑定映射到Local:Appsettings:Platforms节点 + }); +}); +``` + +如何使用: + +```c# +var app = builder.Build(); + +app.Map("/GetPlatform", ([FromServices] IOptions option) => +{ + //推荐(需要自动或手动映射节点关系后才能使用) + return System.Text.Json.JsonSerializer.Serialize(option.Value); +}); + +app.Map("/GetPlatform", ([FromServices] IOptionsMonitor option) => +{ + options.OnChange(option => + { + //TODO 配置更新业务 + }); + + return System.Text.Json.JsonSerializer.Serialize(option.CurrentValue); +});//推荐(需要自动或手动映射节点关系后才能使用) + +app.Map("/GetPlatformName", ([FromServices] IConfiguration configuration) => +{ + //基础 + return configuration["Local:Appsettings:Platforms:Name"]; +}); + +app.Run(); +``` + +如何接管更多的本地节点? + +```c# +builder.AddMasaConfiguration(builder =>{ + + builder.AddSection(new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("custom.json", true, true), "Custom");//将custom.json配置挂载到Local:Custom节点下 +}); +``` + +提示: + +Configuration默认自动获取继承IMasaConfigurationOptions接口的类,并映射节点关系,方便通过IOptions、IOptionsSnapshot、IOptionsMonitor获取配置信息 + +上文Platforms为本地配置,用于演示本地配置挂载到IConfiguration后的效果以及使用用法 \ No newline at end of file diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj index 157469430..5763e3601 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj index bf611659f..041391a63 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj index fc6ac3d53..9f64f7774 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/README.md b/src/Data/MASA.Contrib.Data.Contracts.EF/README.md index e4e2fc04e..9d0a41218 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/README.md +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/README.md @@ -1,10 +1,11 @@ -[中](RREADME.zh-CN.md) | EN +[中](README.zh-CN.md) | EN ## Contracts.EF Example: ```C# +Install-Package MASA.Contrib.Data.UoW.EF Install-Package MASA.Contrib.Data.Contracts.EF ``` @@ -20,3 +21,11 @@ builder.Services > When the entity inherits ISoftware and is deleted, change the delete state to the modified state, and cooperate with the custom Remove operation to achieve soft deletion > Do not query the data marked as soft deleted when querying > When combined with EventBus, the transaction is opened after the first CUD, and the transaction rollback is supported when the entire Handler is abnormal. + +> Frequently Asked Questions: + +- Problem 1: After using UseSoftDelete, there is a problem that the submission cannot be saved + + After using Uow, the transaction will be enabled by default after Add、 Modified、 and Deleted + and the transaction can be saved normally after the transaction is submitted + If the EventBus is used, the transaction will be automatically submitted \ No newline at end of file diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md b/src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md index f2e2e8357..8ec6e7b50 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md @@ -5,6 +5,7 @@ 用例: ```C# +Install-Package MASA.Contrib.Data.UoW.EF Install-Package MASA.Contrib.Data.Contracts.EF ``` @@ -20,3 +21,11 @@ builder.Services > 当实体继承ISoftware,且被删除时,将删除状态改为修改状态,并配合自定义Remove操作,实现软删除 > 支持查询的时候不查询被标记软删除的数据 > 与EventBus结合使用时,做到了第一次CUD后开启事务,当整个Handler出现异常后支持事务回滚 + +> 常见问题: + +- 问题1:使用UseSoftDelete后出现提交保存不上的问题 + + 使用Uow后,默认在进行Add、Modified、Deleted后会启用事务 + 需要提交事务之后才能正常保存 + 如果使用EventBus则会自动提交事务 \ No newline at end of file diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj index 69bf5eaf1..7414a8ac7 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj +++ b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/README.md b/src/Data/MASA.Contrib.Data.UoW.EF/README.md new file mode 100644 index 000000000..b7f924b4e --- /dev/null +++ b/src/Data/MASA.Contrib.Data.UoW.EF/README.md @@ -0,0 +1,19 @@ +[中](README.zh-CN.md) | EN + +## Contracts.EF + +Example: + +```C# +Install-Package MASA.Contrib.Data.UoW.EF +Install-Package MASA.Contrib.Data.Contracts.EF +``` + +```C# +builder.Services + .AddUoW(dbOptions => + { + dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"); + }) +``` + diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/RREADME.zh-CN.md b/src/Data/MASA.Contrib.Data.UoW.EF/RREADME.zh-CN.md new file mode 100644 index 000000000..c2f15f5b3 --- /dev/null +++ b/src/Data/MASA.Contrib.Data.UoW.EF/RREADME.zh-CN.md @@ -0,0 +1,19 @@ +中 | [EN](README.md) + +## Contracts.EF + +用例: + +```C# +Install-Package MASA.Contrib.Data.UoW.EF +Install-Package MASA.Contrib.Data.Contracts.EF +``` + +```C# +builder.Services + .AddUoW(dbOptions => + { + dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"); + }) +``` + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj index 97c3c8cfb..1c7b9fc52 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj @@ -7,10 +7,10 @@ - - - - + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj index 25023f0a6..650578184 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj index ed2f68ad2..9a36d8215 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj index f157e9fb5..fdb11c5db 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj index d5abb9bb6..13493c99c 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs index 26ae27118..5c2530483 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs @@ -157,7 +157,7 @@ public CustomConfigurationAPI(DccSectionOptions defaultSectionOption, List base.GetCluster(cluster); - public string GetAppid(string appId) => base.GetAppid(appId); + public string GetAppid(string appId) => base.GetAppId(appId); public string GetConfigObject(string configObject) => base.GetConfigObject(configObject); } diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs index 52691207f..d787ac0c2 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs @@ -40,7 +40,7 @@ public void Initialize() public void TestErrorDccSection() { _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary()).Verifiable(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(new ServiceCollection())); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(new ServiceCollection())); } [TestMethod] @@ -100,13 +100,13 @@ public void TestUseDCCAndErrorSection() { _services.AddCaller(options => options.UseHttpClient()); _masaConfigurationBuilder.Setup(builder => builder.GetSectionRelations()).Returns(new Dictionary()).Verifiable(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, "", null, null), "configureOptions"); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, "", null, null), "configureOptions"); } [TestMethod] public void TestUseDCCAndNullDccConfigurationOption() { - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => null, option => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => null, option => { option.AppId = "Test"; option.Environment = "Test"; @@ -115,7 +115,7 @@ public void TestUseDCCAndNullDccConfigurationOption() Initialize(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, null, option => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, null, option => { option.AppId = "Test"; option.Environment = "Test"; @@ -129,10 +129,12 @@ public void TestCustomCaller() Mock configurationAPIClient = new(); configurationAPIClient.Setup(client => client.GetRawAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), null).Result).Returns(() => ("", ConfigurationTypes.Text)); _services.AddSingleton(configurationAPIClient.Object); - _masaConfigurationBuilder.Object.UseDCC(_services, () => new DccConfigurationOptions() + _masaConfigurationBuilder.Object.UseDcc(_services, () => new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions + { + Servers = new List() { new Utils.Caching.Redis.Models.RedisServerOptions() { @@ -140,6 +142,7 @@ public void TestCustomCaller() Port = 6379 } } + } }, option => { option.AppId = "Test"; @@ -166,11 +169,11 @@ public void TestCustomCaller() [TestMethod] public void TestUseDCCAndEmptyDccServiceAddress() { - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "", + ManageServiceAddress = "", }; }, null, null), "DccServiceAddress"); } @@ -178,54 +181,66 @@ public void TestUseDCCAndEmptyDccServiceAddress() [TestMethod] public void TestUseDCCAndErrorDccService() { - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = null + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() + { + Servers = null + } }; }, null, null), "Servers"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions + { + Servers = new List() + } }; }, null, null), "Servers"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host="", - Port=8080 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host="", + Port=8080 + } } } }; }, null, null), "Servers"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host="localhost", - Port=-1 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host="localhost", + Port=-1 + } } } }; @@ -235,34 +250,40 @@ public void TestUseDCCAndErrorDccService() [TestMethod] public void TestUseDCCAndErrorDefaultSectionOption() { - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; }, null, null), "defaultSectionOptions"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -272,17 +293,20 @@ public void TestUseDCCAndErrorDefaultSectionOption() }, null), "AppId cannot be empty"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -293,17 +317,20 @@ public void TestUseDCCAndErrorDefaultSectionOption() }, null), "ConfigObjects cannot be empty"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -314,17 +341,20 @@ public void TestUseDCCAndErrorDefaultSectionOption() }, null), "ConfigObjects cannot be empty"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -343,17 +373,20 @@ public void TestUseDCCAndErrorExpansionSectionOptions() { System.Environment.SetEnvironmentVariable(DefaultEnvironmentName, "Test"); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -376,17 +409,20 @@ public void TestUseDCCAndErrorExpansionSectionOptions() }), "ConfigObjects in the extension section cannot be empty"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -410,17 +446,20 @@ public void TestUseDCCAndErrorExpansionSectionOptions() }), "ConfigObjects in the extension section cannot be empty"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -447,17 +486,20 @@ public void TestUseDCCAndErrorExpansionSectionOptions() }), "The current section already exists, no need to mount repeatedly"); _services = new ServiceCollection(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services, () => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -503,17 +545,20 @@ public void TestUseDCCAndSuccess(string environment, string cluster, string appI => new(brand.Serialize(_jsonSerializerOptions), ConfigurationTypes.Json) ).Verifiable(); _services.AddSingleton(configurationAPIClient.Object); - _masaConfigurationBuilder.Object.UseDCC(_services, () => + _masaConfigurationBuilder.Object.UseDcc(_services, () => { return new DccConfigurationOptions() { - DccServiceAddress = "https://github.com", - Servers = new List() + ManageServiceAddress = "https://github.com", + RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - new Utils.Caching.Redis.Models.RedisServerOptions() + Servers = new List() { - Host = "localhost", - Port = 6379 + new Utils.Caching.Redis.Models.RedisServerOptions() + { + Host = "localhost", + Port = 6379 + } } } }; @@ -559,7 +604,7 @@ public void TestUseDccAndSingleSection(string environment, string cluster, strin { "Appsettings",chainedConfiguration.Build() } }).Verifiable(); - _masaConfigurationBuilder.Object.UseDCC(_services); + _masaConfigurationBuilder.Object.UseDcc(_services); configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); trigger.Execute(); @@ -583,7 +628,7 @@ public void TestUseDccAndSingleSection(string environment, string cluster, strin { "Appsettings",chainedConfiguration.Build() } }).Verifiable(); - _masaConfigurationBuilder.Object.UseDCC(_services); + _masaConfigurationBuilder.Object.UseDcc(_services); configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); Initialize(); @@ -602,7 +647,7 @@ public void TestUseDccAndSingleSection(string environment, string cluster, strin { "Appsettings",chainedConfiguration.Build() } }).Verifiable(); - _masaConfigurationBuilder.Object.UseDCC(_services); + _masaConfigurationBuilder.Object.UseDcc(_services); configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); Initialize(); @@ -621,7 +666,7 @@ public void TestUseDccAndSingleSection(string environment, string cluster, strin { "Appsettings",chainedConfiguration.Build() } }).Verifiable(); - _masaConfigurationBuilder.Object.UseDCC(_services); + _masaConfigurationBuilder.Object.UseDcc(_services); configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); @@ -641,7 +686,7 @@ public void TestUseDccAndSingleSection(string environment, string cluster, strin { "Appsettings",chainedConfiguration.Build() } }).Verifiable(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDCC(_services), "configurationType"); + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services), "configurationType"); configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); } @@ -666,7 +711,7 @@ public void TestUseDccAndExpandSections() { "Appsettings",chainedConfiguration.Build() } }).Verifiable(); - _masaConfigurationBuilder.Object.UseDCC(_services); + _masaConfigurationBuilder.Object.UseDcc(_services); configurationAPIClient.Verify(client => client.GetRawAsync("Test", "Default", "DccTest", "Test1", It.IsAny>()), Times.Once); configurationAPIClient.Verify(client => client.GetRawAsync("Test2", "Default", "DccTest2", "Test3", It.IsAny>()), Times.Once); configurationAPIClient.Verify(client => client.GetRawAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()), Times.Exactly(2)); @@ -691,7 +736,7 @@ public void TestUseMultiDcc(string environment, string cluster, string appId, st { "Appsettings",chainedConfiguration.Build() } }).Verifiable(); - _masaConfigurationBuilder.Object.UseDCC(_services).UseDCC(_services); + _masaConfigurationBuilder.Object.UseDcc(_services).UseDcc(_services); configurationAPIClient.Verify(client => client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), Times.Once); var httpClient = _services.BuildServiceProvider().GetRequiredService().CreateClient(DEFAULT_CLIENT_NAME); diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj index ed6df73cc..ee2e76853 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj @@ -18,8 +18,8 @@ - - + + From 94b59f38849976092e00fe3e68d957affd32ed79 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Tue, 23 Nov 2021 07:18:04 +0000 Subject: [PATCH 07/39] Feature/optimize --- .../ConfigurationAPIClient.cs | 49 ++++++++- .../Internal/DccFactory.cs | 5 +- .../MASA.Contrib.BasicAbility.Dcc.csproj | 2 +- .../MasaConfigurationExtensions.cs | 10 +- .../MASA.Contrib.Configuration.csproj | 2 +- .../Internal/LinqExtensions.cs | 54 +++++++--- .../ServiceCollectionRepositoryExtensions.cs | 9 +- ...SA.Contrib.DDD.Domain.Repository.EF.csproj | 2 +- .../Repository.cs | 47 +++++++-- .../Events/DomainCommand.cs | 2 +- .../Events/DomainEvent.cs | 2 +- .../Events/DomainQuery.cs | 4 +- .../MASA.Contrib.DDD.Domain.csproj | 2 +- .../MASA.Contrib.Data.Contracts.EF.csproj | 4 +- .../TransactionSaveChangesFilter.cs | 2 +- .../DispatcherOptionsExtensions.cs | 6 +- .../MASA.Contrib.Data.UoW.EF.csproj | 4 +- .../MASA.Contrib.Data.UoW.EF/Transaction.cs | 2 +- .../MASA.Contrib.Data.UoW.EF/UnitOfWork.cs | 14 ++- .../EventBus.cs | 3 +- .../Internal/Dispatch/Dispatcher.cs | 6 +- .../Internal/Dispatch/DispatcherBase.cs | 7 +- .../Internal/Dispatch/SagaDispatcher.cs | 20 ++-- .../Middleware/TransactionMiddleware.cs | 32 ++++-- .../MASA.Contrib.Dispatcher.Events.csproj | 7 +- .../Options/DispatcherOptions.cs | 7 ++ .../ServiceCollectionExtensions.cs | 14 +-- .../_Imports.cs | 1 + .../IntegrationEvent.cs | 2 +- .../IntegrationEventBus.cs | 37 +++---- ...b.Dispatcher.IntegrationEvents.Dapr.csproj | 2 +- .../ServiceCollectionExtensions.cs | 14 ++- .../IntegrationEventLogService.cs | 8 +- ...cher.IntegrationEvents.EventLogs.EF.csproj | 2 +- ...MASA.Contrib.ReadWriteSpliting.CQRS.csproj | 4 +- .../MASA.Contrib.Service.MinimalAPIs.csproj | 2 +- .../DccClientTest.cs | 99 ++++++++++++++----- .../appsettings.json | 22 +++-- .../expandSections.json | 20 ++-- .../Repositories/OrderRepository.cs | 2 +- .../RepositoryTest.cs | 16 ++- .../DomainEventBusTest.cs | 5 +- ...MASA.Contrib.Data.Contracts.EF.Test.csproj | 2 +- .../SoftDeleteTest.cs | 3 +- .../Events/DeductionMoneyEvent.cs | 2 +- .../Events/IncreaseMoneyEvent.cs | 2 +- .../OrderPaymentFailedIntegrationEvent.cs | 2 +- ...ASA.Contrib.Dispatcher.Events.Tests.csproj | 1 + .../Events/IntegrationEvent.cs | 2 +- 49 files changed, 385 insertions(+), 183 deletions(-) diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs index 69cd2c7c1..8f862567c 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/ConfigurationAPIClient.cs @@ -2,6 +2,7 @@ namespace MASA.Contrib.BasicAbility.Dcc; public class ConfigurationAPIClient : ConfigurationAPIBase, IConfigurationAPIClient { + private readonly IServiceProvider _serviceProvider; private readonly IMemoryCacheClient _client; private readonly JsonSerializerOptions _jsonSerializerOptions; @@ -9,24 +10,26 @@ public class ConfigurationAPIClient : ConfigurationAPIBase, IConfigurationAPICli private readonly ConcurrentDictionary>> _taskJsonObjects = new(); public ConfigurationAPIClient( + IServiceProvider serviceProvider, IMemoryCacheClient client, JsonSerializerOptions jsonSerializerOptions, DccSectionOptions defaultSectionOption, List? expandSectionOptions) : base(defaultSectionOption, expandSectionOptions) { + _serviceProvider = serviceProvider; _client = client; _jsonSerializerOptions = jsonSerializerOptions; } - public Task<(string Raw, ConfigurationTypes ConfigurationType)> GetRawAsync(string environment, string cluster, string appId, string configObject, Action valueChanged) + public Task<(string Raw, ConfigurationTypes ConfigurationType)> GetRawAsync(string environment, string cluster, string appId, + string configObject, Action valueChanged) { var key = FomartKey(environment, cluster, appId, configObject); return GetRawByKeyAsync(key, valueChanged); } public async Task GetAsync(string environment, string cluster, string appId, string configObject, Action valueChanged) - where T : class { var key = FomartKey(environment, cluster, appId, configObject); @@ -43,15 +46,22 @@ public async Task GetAsync(string environment, string cluster, string appI _taskJsonObjects.AddOrUpdate(k, newValue, (_, _) => newValue); valueChanged?.Invoke(result!); }); + if (typeof(T).GetInterfaces().Any(type => type == typeof(IConvertible))) + { + if (result.ConfigurationType == ConfigurationTypes.Text) + return Convert.ChangeType(result.Raw, typeof(T)); - return JsonSerializer.Deserialize(result.Raw, options) ?? throw new ArgumentException(nameof(configObject)); + throw new FormatException(result.Raw); + } + return JsonSerializer.Deserialize(result.Raw, options) ?? throw new ArgumentException(nameof(configObject)); })).Value; - return (value as T)!; + return (T)value; } - public async Task GetDynamicAsync(string environment, string cluster, string appId, string configObject, Action valueChanged) + public async Task GetDynamicAsync(string environment, string cluster, string appId, string configObject, + Action valueChanged) { var key = FomartKey(environment, cluster, appId, configObject); @@ -74,6 +84,16 @@ public async Task GetDynamicAsync(string environment, string cluster, s return await value; } + public async Task GetDynamicAsync(string key) + { + if (string.IsNullOrEmpty(key)) + throw new ArgumentNullException(nameof(key)); + + var configuration = _serviceProvider.GetRequiredService(); + key = key.Replace(".", ConfigurationPath.KeyDelimiter); + return await Task.FromResult(Format(configuration.GetSection(key))); + } + private async Task<(string Raw, ConfigurationTypes ConfigurationType)> GetRawByKeyAsync(string key, Action valueChanged) { var raw = await _client.GetAsync(key, (value) => @@ -116,4 +136,23 @@ public async Task GetDynamicAsync(string environment, string cluster, s private string FomartKey(string environment, string cluster, string appId, string configObject) => $"{GetEnvironment(environment)}-{GetCluster(cluster)}-{GetAppId(appId)}-{GetConfigObject(configObject)}".ToLower(); + + private dynamic Format(IConfigurationSection section) + { + var childrenSections = section.GetChildren(); + if (!section.Exists() || !childrenSections.Any()) + { + return section.Value; + } + else + { + var result = new ExpandoObject(); + var parent = result as IDictionary; + foreach (var child in childrenSections) + { + parent[child.Key] = Format(child); + } + return result; + } + } } diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccFactory.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccFactory.cs index ac199e966..709cfc5d2 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccFactory.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/DccFactory.cs @@ -1,16 +1,15 @@ -using MASA.Utils.Caller.Core; - namespace MASA.Contrib.BasicAbility.Dcc.Internal; internal class DccFactory { public static IConfigurationAPIClient CreateClient( + IServiceProvider serviceProvider, IMemoryCacheClient client, JsonSerializerOptions jsonSerializerOptions, DccSectionOptions defaultSectionOption, List? expandSectionOptions) { - return new ConfigurationAPIClient(client, jsonSerializerOptions, defaultSectionOption, expandSectionOptions); + return new ConfigurationAPIClient(serviceProvider, client, jsonSerializerOptions, defaultSectionOption, expandSectionOptions); } public static IConfigurationAPIManage CreateManage( diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj index 3fdf48994..cdac58bc6 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs index 1ba1baf72..747d4b061 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs @@ -103,7 +103,12 @@ public static IServiceCollection TryAddConfigurationAPIClient(IServiceCollection if (client == null) throw new ArgumentNullException(nameof(client)); - return DccFactory.CreateClient(client, jsonSerializerOption, defaultSectionOption, expansionSectionOptions); + return DccFactory.CreateClient( + serviceProvider, + client, + jsonSerializerOption, + defaultSectionOption, + expansionSectionOptions); }); return services; } @@ -168,7 +173,8 @@ private static (DccSectionOptions DefaultSectionOption, List if (expansionOption.ConfigObjects == null || !expansionOption.ConfigObjects.Any()) throw new ArgumentNullException("ConfigObjects in the extension section cannot be empty"); - if (expansionOption.AppId == defaultSectionOption.AppId || expansionOptions.Any(section => section.AppId == expansionOption.AppId)) + if (expansionOption.AppId == defaultSectionOption.AppId || + expansionOptions.Any(section => section.AppId == expansionOption.AppId)) throw new ArgumentNullException("The current section already exists, no need to mount repeatedly"); expansionOptions.Add(expansionOption); diff --git a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj index 466710bf9..2265db45e 100644 --- a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj +++ b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/LinqExtensions.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/LinqExtensions.cs index 95ceb5ef3..b47f613b9 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/LinqExtensions.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/LinqExtensions.cs @@ -2,40 +2,66 @@ namespace MASA.Contrib.DDD.Domain.Repository.EF.Internal; internal static class LinqExtensions { - public static IQueryable OrderBy(this IQueryable query, string[] fields, bool desc) where T : class + public static IQueryable GetQueryable(this IQueryable query, Dictionary fields) where TEntity : class { - for (int i = 0; i < fields.Length; i++) + foreach (var field in fields) { - if (i == 0) - query = query.OrderBy(fields[i], desc); + query = query.GetQueryable(field.Key, field.Value); + } + return query; + } + + private static IQueryable GetQueryable(this IQueryable query, string field, object val) where TEntity : class + { + Type type = typeof(TEntity); + var parameter = Expression.Parameter(type, "entity"); + + PropertyInfo property = type.GetProperty(field)!; + Expression expProperty = Expression.Property(parameter, property.Name); + + Expression> valueLamda = () => val; + Expression expValue = Expression.Convert(valueLamda.Body, property.PropertyType); + Expression expression = Expression.Equal(expProperty, expValue); + Expression> filter = (Expression>)Expression.Lambda(expression, parameter); + return query.Where(filter); + } + + public static IQueryable OrderBy(this IQueryable query, Dictionary fields) where TEntity : class + { + var index = 0; + foreach (var field in fields) + { + if (index == 0) + query = query.OrderBy(field.Key, field.Value); else - query = query.ThenBy(fields[i], desc); + query = query.ThenBy(field.Key, field.Value); + index++; } return query; } - public static IQueryable OrderBy(this IQueryable query, string field, bool desc) where T : class + private static IQueryable OrderBy(this IQueryable query, string field, bool desc) where TEntity : class { - ParameterExpression parameterExpression = Expression.Parameter(typeof(T)); + ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntity)); Expression key = Expression.Property(parameterExpression, field); - var propertyInfo = GetPropertyInfo(typeof(T), field); - var orderExpression = GetOrderExpression(typeof(T), propertyInfo); + var propertyInfo = GetPropertyInfo(typeof(TEntity), field); + var orderExpression = GetOrderExpression(typeof(TEntity), propertyInfo); if (desc) { var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "OrderByDescending" && m.GetParameters().Length == 2); - var genericMethod = method!.MakeGenericMethod(typeof(T), propertyInfo.PropertyType); - return (genericMethod.Invoke(null, new object[] { query, orderExpression }) as IQueryable)!; + var genericMethod = method!.MakeGenericMethod(typeof(TEntity), propertyInfo.PropertyType); + return (genericMethod.Invoke(null, new object[] { query, orderExpression }) as IQueryable)!; } else { var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "OrderBy" && m.GetParameters().Length == 2); - var genericMethod = method!.MakeGenericMethod(typeof(T), propertyInfo.PropertyType); - return (IQueryable)genericMethod.Invoke(null, new object[] { query, orderExpression })!; + var genericMethod = method!.MakeGenericMethod(typeof(TEntity), propertyInfo.PropertyType); + return (IQueryable)genericMethod.Invoke(null, new object[] { query, orderExpression })!; } } - public static IQueryable ThenBy(this IQueryable query, string field, bool desc) where T : class + private static IQueryable ThenBy(this IQueryable query, string field, bool desc) where T : class { ParameterExpression parameterExpression = Expression.Parameter(typeof(T)); Expression key = Expression.Property(parameterExpression, field); diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs index a51b8bdb5..52997fba0 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs @@ -40,7 +40,14 @@ private static string[] GetKeys(Type entityType) IAggregateRoot aggregateRoot; try { - aggregateRoot = (IAggregateRoot)(Activator.CreateInstance(entityType))!; + var constructorInfo = entityType + .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .FirstOrDefault(con => !con.CustomAttributes.Any()); + + if (constructorInfo == null) + throw new ArgumentNullException("The entity needs to have an empty constructor"); + + aggregateRoot = (IAggregateRoot)Activator.CreateInstance(entityType, constructorInfo.IsPrivate)!; } catch (Exception ex) { diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj index 5763e3601..4c704c871 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs index 9a804fdce..11096f1cf 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs @@ -19,14 +19,22 @@ public override DbTransaction Transaction { get { + if (!UseTransaction) + throw new NotSupportedException(nameof(Transaction)); + if (TransactionHasBegun) - { return _context.Database.CurrentTransaction!.GetDbTransaction(); - } + return _context.Database.BeginTransaction().GetDbTransaction(); } } + public override bool UseTransaction + { + get => UnitOfWork.UseTransaction; + set => UnitOfWork.UseTransaction = value; + } + public override IUnitOfWork UnitOfWork { get; } public override async ValueTask AddAsync(TEntity entity, CancellationToken cancellationToken = default) @@ -40,8 +48,21 @@ public override Task CommitAsync(CancellationToken cancellationToken = default) public override async ValueTask DisposeAsync() => await ValueTask.CompletedTask; - public override ValueTask FindAsync(object?[]? keyValues, CancellationToken cancellationToken) - => _context.Set().FindAsync(keyValues, cancellationToken); + public override Task FindAsync(object?[]? keyValues, CancellationToken cancellationToken) + { + if (keyValues == null) + return null; + + var keys = GetKeys(typeof(TEntity)); + Dictionary fields = new(); + for (var i = 0; i < keys.Length; i++) + { + fields.Add(keys[i], keyValues[i]!); + } + + return _context.Set().IgnoreQueryFilters().GetQueryable(fields).FirstOrDefaultAsync(cancellationToken); + } + public override Task FindAsync( Expression> predicate, @@ -72,10 +93,12 @@ public override async Task> GetListAsync( /// asc or desc, default asc /// /// - public override Task> GetPaginatedListAsync(int skip, int take, string? sorting, CancellationToken cancellationToken) + public override Task> GetPaginatedListAsync(int skip, int take, Dictionary? sorting, CancellationToken cancellationToken) { - var isDesc = !string.Equals(sorting ?? "asc", "asc", StringComparison.CurrentCultureIgnoreCase); - return _context.Set().OrderBy(GetKeys(typeof(TEntity)), isDesc).Skip(skip).Take(take).ToListAsync(cancellationToken); + if (sorting == null) + sorting = new Dictionary(GetKeys(typeof(TEntity)).Select(x => new KeyValuePair(x, false))); + + return _context.Set().OrderBy(sorting).Skip(skip).Take(take).ToListAsync(cancellationToken); } /// @@ -87,10 +110,14 @@ public override Task> GetPaginatedListAsync(int skip, int take, st /// asc or desc, default asc /// /// - public override Task> GetPaginatedListAsync(Expression> predicate, int skip, int take, string? sorting, CancellationToken cancellationToken) + public override Task> GetPaginatedListAsync(Expression> predicate, int skip, int take, Dictionary? sorting, CancellationToken cancellationToken) { - var isDesc = !string.Equals(sorting ?? "asc", "asc", StringComparison.CurrentCultureIgnoreCase); - return _context.Set().Where(predicate).OrderBy(GetKeys(typeof(TEntity)), isDesc).Skip(skip).Take(take).ToListAsync(cancellationToken); + if (sorting == null) + { + sorting = new Dictionary(GetKeys(typeof(TEntity)).Select(x => new KeyValuePair(x, false))); + } + + return _context.Set().Where(predicate).OrderBy(sorting).Skip(skip).Take(take).ToListAsync(cancellationToken); } public override Task RemoveAsync(TEntity entity, CancellationToken cancellationToken = default) diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainCommand.cs b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainCommand.cs index 9fba0e906..bd05fed21 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainCommand.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainCommand.cs @@ -7,7 +7,7 @@ public record DomainCommand : IDomainCommand public DateTime CreationTime { get; init; } [JsonIgnore] - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork? UnitOfWork { get; set; } public DomainCommand() : this(Guid.NewGuid(), DateTime.UtcNow) { } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs index af5a97433..fc8a28c63 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs @@ -7,7 +7,7 @@ public record DomainEvent : IDomainEvent public DateTime CreationTime { get; init; } [JsonIgnore] - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork? UnitOfWork { get; set; } public DomainEvent() : this(Guid.NewGuid(), DateTime.UtcNow) { } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs index f622ae736..8be4b1563 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs @@ -8,9 +8,9 @@ public abstract record DomainQuery : IDomainQuery public DateTime CreationTime { get; init; } [JsonIgnore] - public IUnitOfWork UnitOfWork + public IUnitOfWork? UnitOfWork { - get => throw new NotSupportedException(nameof(UnitOfWork)); + get => null; set => throw new NotSupportedException(nameof(UnitOfWork)); } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj index 041391a63..08faf8c1b 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj index 9f64f7774..83d7a6f43 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs b/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs index aaffad5bf..f65b7c942 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/SoftDelete/TransactionSaveChangesFilter.cs @@ -10,7 +10,7 @@ public void OnExecuting(ChangeTracker changeTracker) { changeTracker.DetectChanges(); var unitOfWork = _serviceProvider.GetRequiredService(); - if (changeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) && !unitOfWork.TransactionHasBegun) + if (unitOfWork.UseTransaction && changeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) && !unitOfWork.TransactionHasBegun) { var transaction = unitOfWork.Transaction; // Open the transaction } diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs b/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs index c9bcd3cfa..b549686ef 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/DispatcherOptionsExtensions.cs @@ -5,7 +5,8 @@ public static class DispatcherOptionsExtensions public static IDispatcherOptions UseUoW( this IDispatcherOptions options, Action? optionsBuilder = null, - bool disableRollbackOnFailure = false) + bool disableRollbackOnFailure = false, + bool useTransaction = true) where TDbContext : MasaDbContext { if (options.Services == null) @@ -22,7 +23,8 @@ public static IDispatcherOptions UseUoW( var logger = serviceProvider.GetService>>(); return new UnitOfWork(dbContext, logger) { - DisableRollbackOnFailure = disableRollbackOnFailure + DisableRollbackOnFailure = disableRollbackOnFailure, + UseTransaction = useTransaction }; }); if (options.Services.All(service => service.ServiceType != typeof(MasaDbContextOptions))) diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj index 7414a8ac7..20753b006 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj +++ b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs b/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs index a54b487cb..f7fdf6f2b 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/Transaction.cs @@ -5,5 +5,5 @@ public class Transaction : ITransaction public Transaction(IUnitOfWork unitOfWork) => UnitOfWork = unitOfWork; [JsonIgnore] - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork? UnitOfWork { get; set; } } diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs b/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs index 052dca91c..bf03eaf0e 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs +++ b/src/Data/MASA.Contrib.Data.UoW.EF/UnitOfWork.cs @@ -7,10 +7,12 @@ public DbTransaction Transaction { get { + if (!UseTransaction) + throw new NotSupportedException("Doesn't support transaction opening"); + if (TransactionHasBegun) - { return _context.Database.CurrentTransaction!.GetDbTransaction(); - } + return _context.Database.BeginTransaction().GetDbTransaction(); } } @@ -19,6 +21,8 @@ public DbTransaction Transaction public bool DisableRollbackOnFailure { get; set; } + public bool UseTransaction { get; set; } = true; + private readonly DbContext _context; private readonly ILogger>? _logger; @@ -36,7 +40,7 @@ public async Task SaveChangesAsync(CancellationToken cancellationToken = default public async Task CommitAsync(CancellationToken cancellationToken = default) { - if (!TransactionHasBegun) + if (!UseTransaction || !TransactionHasBegun) throw new NotSupportedException("Transaction not opened"); try @@ -59,8 +63,8 @@ public async Task CommitAsync(CancellationToken cancellationToken = default) public async Task RollbackAsync(CancellationToken cancellationToken = default) { - if (!TransactionHasBegun) - throw new NotSupportedException("Transactions are not started and rollback is not supported"); + if (!UseTransaction || !TransactionHasBegun) + throw new NotSupportedException("Transactions are not opened and rollback is not supported"); await _context.Database.RollbackTransactionAsync(cancellationToken); } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs index 3ef2f01f0..0abb86540 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs @@ -25,8 +25,9 @@ public async Task PublishAsync(TEvent @event) where TEvent : IEvent } var middlewares = _serviceProvider.GetRequiredService>>(); - if (@event is ITransaction transactionEvent) + if (_options.UnitOfWorkRelation[typeof(TEvent)]) { + ITransaction transactionEvent = (ITransaction)@event; var unitOfWork = _serviceProvider.GetService(); if (unitOfWork != null) { diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/Dispatcher.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/Dispatcher.cs index 3e789509b..412d5ab03 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/Dispatcher.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/Dispatcher.cs @@ -2,11 +2,11 @@ namespace MASA.Contrib.Dispatcher.Events.Internal.Dispatch; internal class Dispatcher : DispatcherBase { - public Dispatcher(IServiceCollection services, bool forceInit = false) : base(services, forceInit) { } + public Dispatcher(IServiceCollection services, Assembly[] assemblies, bool forceInit = false) : base(services, assemblies, forceInit) { } - public Dispatcher Build(ServiceLifetime lifetime, params Assembly[] assemblies) + public Dispatcher Build(ServiceLifetime lifetime) { - foreach (var assembly in assemblies) + foreach (var assembly in _assemblies) { AddRelationNetwork(assembly); } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/DispatcherBase.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/DispatcherBase.cs index 6dd13ab60..b3e0900af 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/DispatcherBase.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/DispatcherBase.cs @@ -6,11 +6,14 @@ internal class DispatcherBase protected readonly IServiceCollection _services; + protected readonly Assembly[] _assemblies; + private readonly ILogger _logger; - public DispatcherBase(IServiceCollection services, bool forceInit) + public DispatcherBase(IServiceCollection services, Assembly[] assemblies, bool forceInit) { _services = services; + _assemblies = assemblies; var serviceProvider = services.BuildServiceProvider(); if (_sharingRelationNetwork == null || forceInit) { @@ -25,7 +28,7 @@ public async Task PublishEventAsync(IServiceProvider serviceProvider, TE var eventType = typeof(TEvent); if (!_sharingRelationNetwork.RelationNetwork.TryGetValue(eventType, out List? dispatchRelations) || dispatchRelations == null) { - if(@event is IIntegrationEvent) + if (@event is IIntegrationEvent) { _logger.LogError($"Dispatcher: The current event is an out-of-process event. You should use IIntegrationEventBus or IDomainEventBus to send it"); throw new ArgumentNullException($"The current event is an out-of-process event. You should use IIntegrationEventBus or IDomainEventBus to send it"); diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/SagaDispatcher.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/SagaDispatcher.cs index af24ed1e8..c68170662 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/SagaDispatcher.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Dispatch/SagaDispatcher.cs @@ -2,18 +2,18 @@ namespace MASA.Contrib.Dispatcher.Events.Internal.Dispatch; internal class SagaDispatcher : DispatcherBase { - public SagaDispatcher(IServiceCollection services, bool forceInit = false) : base(services, forceInit) { } + public SagaDispatcher(IServiceCollection services, Assembly[] assemblies, bool forceInit = false) : base(services, assemblies, forceInit) { } - public SagaDispatcher Build(ServiceLifetime lifetime, params Assembly[] assemblies) + public SagaDispatcher Build(ServiceLifetime lifetime) { - AddSagaDispatchRelation(_services, typeof(IEventHandler<>), lifetime, assemblies); - AddSagaDispatchRelation(_services, typeof(ISagaEventHandler<>), lifetime, assemblies); + AddSagaDispatchRelation(_services, typeof(IEventHandler<>), lifetime); + AddSagaDispatchRelation(_services, typeof(ISagaEventHandler<>), lifetime); return this; } - private IServiceCollection AddSagaDispatchRelation(IServiceCollection services, Type eventBusHandlerType, ServiceLifetime lifetime, params Assembly[] assemblies) + private IServiceCollection AddSagaDispatchRelation(IServiceCollection services, Type eventBusHandlerType, ServiceLifetime lifetime) { - foreach (var item in GetAddSagaServices(eventBusHandlerType, assemblies)) + foreach (var item in GetAddSagaServices(eventBusHandlerType)) { services.Add(item.ServiceType, item.ImplementationType, lifetime); AddSagaRelationNetwork(item.ImplementationType); @@ -80,10 +80,10 @@ private List GetSagaHandlers(Type eventBusHandlerType) return eventHandlers; } - private List<(Type ServiceType, Type ImplementationType)> GetAddSagaServices(Type eventBusHandlerType, params Assembly[] assemblies) + private List<(Type ServiceType, Type ImplementationType)> GetAddSagaServices(Type eventBusHandlerType) { List<(Type ServiceType, Type ImplementationType)> list = new(); - var serviceTypeAndImplementationInfo = GetSagaServiceTypeAndImplementations(eventBusHandlerType, assemblies); + var serviceTypeAndImplementationInfo = GetSagaServiceTypeAndImplementations(eventBusHandlerType); foreach (var serviceType in serviceTypeAndImplementationInfo.ServiceTypeList) { var implementationTypes = serviceTypeAndImplementationInfo.ImplementationType.Where(implementationType => serviceType.IsAssignableFrom(implementationType)).ToList(); @@ -97,11 +97,11 @@ private List GetSagaHandlers(Type eventBusHandlerType) return list; } - private (List ServiceTypeList, List ImplementationType) GetSagaServiceTypeAndImplementations(Type eventBusHandlerType, params Assembly[] assemblies) + private (List ServiceTypeList, List ImplementationType) GetSagaServiceTypeAndImplementations(Type eventBusHandlerType) { var concretions = new List(); var interfaces = new List(); - foreach (var type in assemblies.SelectMany(a => a.DefinedTypes).Where(t => !t.IsGeneric())) + foreach (var type in _assemblies.SelectMany(a => a.DefinedTypes).Where(t => !t.IsGeneric())) { if (type.IsConcrete()) { diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs index 882a9ad00..272894574 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Internal/Middleware/TransactionMiddleware.cs @@ -3,20 +3,36 @@ namespace MASA.Contrib.Dispatcher.Events.Internal.Middleware; public class TransactionMiddleware : IMiddleware where TEvent : notnull, IEvent { - private readonly ILogger> _logger; - - public TransactionMiddleware(ILogger> logger) + public async Task HandleAsync(TEvent @event, EventHandlerDelegate next) { - _logger = logger; + try + { + await next(); + + if (IsUseTransaction(@event, out ITransaction? transaction)) + { + await transaction!.UnitOfWork!.CommitAsync(); + } + } + catch (Exception) + { + if (IsUseTransaction(@event, out ITransaction? transaction)) + { + await transaction!.UnitOfWork!.RollbackAsync(); + } + throw; + } } - public async Task HandleAsync(TEvent @event, EventHandlerDelegate next) + private bool IsUseTransaction(TEvent @event, out ITransaction? transaction) { - await next(); - if (@event is ITransaction transactionEvent && transactionEvent.UnitOfWork != null && transactionEvent.UnitOfWork.TransactionHasBegun) { - await transactionEvent.UnitOfWork.CommitAsync(); + transaction = transactionEvent; + return true; } + + transaction = null; + return false; } } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj index 1c7b9fc52..135d58413 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj @@ -7,9 +7,10 @@ - - - + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs index 8a2dd3fce..ad57330d0 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs @@ -18,9 +18,16 @@ public Assembly[] Assemblies .SelectMany(assembly => assembly.GetTypes()) .Where(type => type.IsClass && typeof(IEvent).IsAssignableFrom(type)) .ToList(); + + UnitOfWorkRelation = AllEventTypes.ToDictionary(type => type, type => IsSupportUnitOfWork(type)); } } + private bool IsSupportUnitOfWork(Type eventType) + => typeof(ITransaction).IsAssignableFrom(eventType) && !typeof(IDomainQuery<>).IsGenericInterfaceAssignableFrom(eventType); + + internal Dictionary UnitOfWorkRelation { get; set; } = new(); + public IEnumerable AllEventTypes { get; private set; } public IServiceCollection Services { get; } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/ServiceCollectionExtensions.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/ServiceCollectionExtensions.cs index 24b55c4e3..b587c5736 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/ServiceCollectionExtensions.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/ServiceCollectionExtensions.cs @@ -12,11 +12,11 @@ public static IServiceCollection AddEventBus( ServiceLifetime lifetime, Action? options = null) { - if (services.Any(service => service.ImplementationType == typeof (EventBusProvider))) return services; + if (services.Any(service => service.ImplementationType == typeof(EventBusProvider))) return services; services.AddSingleton(); services.AddLogging(); - + DispatcherOptions dispatcherOptions = new DispatcherOptions(services); options?.Invoke(dispatcherOptions); if (dispatcherOptions.Assemblies.Length == 0) @@ -25,8 +25,8 @@ public static IServiceCollection AddEventBus( } services.AddSingleton(typeof(IOptions), serviceProvider => Microsoft.Extensions.Options.Options.Create(dispatcherOptions)); - services.AddSingleton(new SagaDispatcher(services).Build(lifetime, dispatcherOptions.Assemblies)); - services.AddSingleton(new Internal.Dispatch.Dispatcher(services).Build(lifetime, dispatcherOptions.Assemblies)); + services.AddSingleton(new SagaDispatcher(services, dispatcherOptions.Assemblies).Build(lifetime)); + services.AddSingleton(new Internal.Dispatch.Dispatcher(services, dispatcherOptions.Assemblies).Build(lifetime)); services.TryAdd(typeof(IExecutionStrategy), typeof(ExecutionStrategy), ServiceLifetime.Singleton); services.AddTransient(typeof(IMiddleware<>), typeof(TransactionMiddleware<>)); services.AddScoped(typeof(IEventBus), typeof(EventBus)); @@ -36,7 +36,7 @@ public static IServiceCollection AddEventBus( public static IServiceCollection AddTestEventBus(this IServiceCollection services, ServiceLifetime lifetime, Action? options = null) { - if (services.Any(service => service.ImplementationType == typeof (EventBusProvider))) return services; + if (services.Any(service => service.ImplementationType == typeof(EventBusProvider))) return services; services.AddSingleton(); services.AddLogging(); @@ -49,8 +49,8 @@ public static IServiceCollection AddTestEventBus(this IServiceCollection service } services.AddSingleton(typeof(IOptions), serviceProvider => Microsoft.Extensions.Options.Options.Create(dispatcherOptions)); - services.AddSingleton(new SagaDispatcher(services, true).Build(lifetime, dispatcherOptions.Assemblies)); - services.AddSingleton(new Internal.Dispatch.Dispatcher(services).Build(lifetime, dispatcherOptions.Assemblies)); + services.AddSingleton(new SagaDispatcher(services, dispatcherOptions.Assemblies, true).Build(lifetime)); + services.AddSingleton(new Internal.Dispatch.Dispatcher(services, dispatcherOptions.Assemblies).Build(lifetime)); services.TryAdd(typeof(IExecutionStrategy), typeof(ExecutionStrategy), ServiceLifetime.Singleton); services.AddTransient(typeof(IMiddleware<>), typeof(TransactionMiddleware<>)); services.AddScoped(typeof(IEventBus), typeof(EventBus)); diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs index 331c6737c..708ca8761 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs @@ -1,4 +1,5 @@ global using MASA.BuildingBlocks.Data.UoW; +global using MASA.BuildingBlocks.DDD.Domain.Events; global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.BuildingBlocks.Dispatcher.IntegrationEvents; global using MASA.Contrib.Dispatcher.Events.Enums; diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEvent.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEvent.cs index 604def92e..5af45246d 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEvent.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEvent.cs @@ -7,7 +7,7 @@ public abstract record IntegrationEvent : IIntegrationEvent public DateTime CreationTime { get; init; } [JsonIgnore] - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork? UnitOfWork { get; set; } public abstract string Topic { get; set; } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs index b0880c91f..78dadd4d1 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEventBus.cs @@ -54,32 +54,35 @@ public async Task PublishAsync(TEvent @event) private async Task PublishIntegrationAsync(TEvent @event) where TEvent : IIntegrationEvent { - try + if (@event.UnitOfWork == null && _unitOfWork != null) + @event.UnitOfWork = _unitOfWork; + + var topicName = @event.Topic; + if (@event.UnitOfWork != null && !@event.UnitOfWork.UseTransaction) { - if (@event.UnitOfWork == null && _unitOfWork != null) - { - @event.UnitOfWork = _unitOfWork; - } - if (@event.UnitOfWork != null) + try { _logger.LogInformation("----- Saving changes and integrationEvent: {IntegrationEventId}", @event.Id); - await _eventLogService.SaveEventAsync(@event, @event.UnitOfWork.Transaction); - } + await _eventLogService.SaveEventAsync(@event, @event.UnitOfWork!.Transaction); - _logger.LogInformation("----- Publishing integration event: {IntegrationEventId_published} from {AppId} - ({IntegrationEvent})", @event.Id, _appConfig.CurrentValue.AppId, @event); + _logger.LogInformation("----- Publishing integration event: {IntegrationEventId_published} from {AppId} - ({IntegrationEvent})", @event.Id, _appConfig.CurrentValue.AppId, @event); - await _eventLogService.MarkEventAsInProgressAsync(@event.Id); + await _eventLogService.MarkEventAsInProgressAsync(@event.Id); - var topicName = @event.Topic; - _logger.LogInformation("Publishing event {Event} to {PubsubName}.{TopicName}", @event, _daprPubsubName, topicName); - await _dapr.PublishEventAsync(_daprPubsubName, topicName, (dynamic)@event); + _logger.LogInformation("Publishing event {Event} to {PubsubName}.{TopicName}", @event, _daprPubsubName, topicName); + await _dapr.PublishEventAsync(_daprPubsubName, topicName, (dynamic)@event); - await _eventLogService.MarkEventAsPublishedAsync(@event.Id); + await _eventLogService.MarkEventAsPublishedAsync(@event.Id); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error Publishing integration event: {IntegrationEventId} from {AppId} - ({IntegrationEvent})", @event.Id, _appConfig.CurrentValue.AppId, @event); + await _eventLogService.MarkEventAsFailedAsync(@event.Id); + } } - catch (Exception ex) + else { - _logger.LogError(ex, "Error Publishing integration event: {IntegrationEventId} from {AppId} - ({IntegrationEvent})", @event.Id, _appConfig.CurrentValue.AppId, @event); - await _eventLogService.MarkEventAsFailedAsync(@event.Id); + await _dapr.PublishEventAsync(_daprPubsubName, topicName, (dynamic)@event); } } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj index 650578184..e60c5db20 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/ServiceCollectionExtensions.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/ServiceCollectionExtensions.cs index 6aed6ff7f..d5ae19493 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/ServiceCollectionExtensions.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/ServiceCollectionExtensions.cs @@ -14,15 +14,17 @@ internal static IServiceCollection TryAddDaprEventBus? options = null) where TIntegrationEventLogService : class, IIntegrationEventLogService { - if (services.Any(service => service.ImplementationType == typeof (IntegrationEventBusProvider))) return services; + if (services.Any(service => service.ImplementationType == typeof(IntegrationEventBusProvider))) + return services; + services.AddSingleton(); var dispatcherOptions = new DispatcherOptions(services); options?.Invoke(dispatcherOptions); + if (dispatcherOptions.Assemblies.Length == 0) - { dispatcherOptions.Assemblies = AppDomain.CurrentDomain.GetAssemblies(); - } + services.TryAddSingleton(typeof(IOptions), serviceProvider => Microsoft.Extensions.Options.Options.Create(dispatcherOptions)); services.AddLogging(); @@ -31,6 +33,12 @@ internal static IServiceCollection TryAddDaprEventBus(); services.AddScoped(); + if (!services.Any(service => service.ServiceType == typeof(IUnitOfWork))) + { + var logger = services.BuildServiceProvider().GetRequiredService>(); + logger.LogWarning("UoW is not enabled, local messages will not be integrated"); + } + return services; } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs index d991b8f61..605b4aafe 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/IntegrationEventLogService.cs @@ -32,9 +32,13 @@ public async Task> RetrieveEventLogsPendingToPu public async Task SaveEventAsync(IIntegrationEvent @event, DbTransaction transaction) { - if (transaction == null) throw new ArgumentNullException(nameof(transaction)); + + if (transaction == null) + throw new ArgumentNullException(nameof(transaction)); + if (_eventLogContext.Database.CurrentTransaction == null) await _eventLogContext.Database.UseTransactionAsync(transaction, Guid.NewGuid()); + var eventLogEntry = new IntegrationEventLog(@event, _eventLogContext.Database.CurrentTransaction!.TransactionId); await _eventLogContext.EventLogs.AddAsync(eventLogEntry); await _eventLogContext.SaveChangesAsync(); @@ -62,7 +66,7 @@ private async Task UpdateEventStatus(Guid eventId, IntegrationEventStates status var eventLogEntry = _eventLogContext.EventLogs.FirstOrDefault(e => e.EventId == eventId); if (eventLogEntry == null) throw new ArgumentException(nameof(eventId)); - + eventLogEntry.State = status; if (status == IntegrationEventStates.InProgress) diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj index 9a36d8215..f845563ae 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj index fdb11c5db..cfddea1de 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj index 13493c99c..7fbd788b8 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj @@ -6,7 +6,7 @@ - + diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs index b50eebe3c..72191684a 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs @@ -4,6 +4,8 @@ namespace MASA.Contrib.BasicAbility.Dcc.Tests; public class DccClientTest { private Mock _client; + private IServiceCollection _services; + private IServiceProvider _serviceProvider => _services.BuildServiceProvider(); private JsonSerializerOptions _jsonSerializerOptions; private DccSectionOptions _dccSectionOptions; private CustomTrigger _trigger; @@ -12,6 +14,7 @@ public class DccClientTest public void Initialize() { _client = new(); + _services = new ServiceCollection(); _jsonSerializerOptions = new JsonSerializerOptions() { PropertyNameCaseInsensitive = true @@ -34,22 +37,23 @@ public void Initialize() [DataRow("Test", "Default", "DccTest", "Brand")] public async Task TestGetRawAsync(string environment, string cluster, string appId, string configObject) { + Action valueChanged = delegate (string val) { }; _client.Setup(client => client.GetAsync(It.IsAny(), valueChanged).Result).Returns(() => null).Verifiable(); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); await Assert.ThrowsExceptionAsync(async () - => await client.GetRawAsync(environment, cluster, appId, configObject, valueChanged), "configObject invalid" + => await client.GetRawAsync(environment, cluster, appId, configObject, valueChanged), "configObject invalid" ); _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => "test").Verifiable(); - client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); await Assert.ThrowsExceptionAsync(async () => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()) ); _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => "{}").Verifiable(); await Assert.ThrowsExceptionAsync(async () - => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), "configObject invalid" + => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), "configObject invalid" ); _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new @@ -58,7 +62,7 @@ await Assert.ThrowsExceptionAsync(async () Content = "" }.Serialize(_jsonSerializerOptions)).Verifiable(); await Assert.ThrowsExceptionAsync(async () - => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), "configObject invalid" + => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), "configObject invalid" ); _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease @@ -66,14 +70,16 @@ await Assert.ThrowsExceptionAsync(async () ConfigFormat = (ConfigFormats)5, Content = "" }.Serialize(_jsonSerializerOptions)).Verifiable(); - await Assert.ThrowsExceptionAsync(async () => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), "Unsupported configuration type"); + await Assert.ThrowsExceptionAsync( + async () => await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()), + "Unsupported configuration type"); } [DataTestMethod] [DataRow("Test", "Default", "DccTest", "Brand")] public async Task TestGetRawAsyncByJson(string environment, string cluster, string appId, string configObject) { - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); var brand = new Brands("Apple"); _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() @@ -95,7 +101,7 @@ public async Task TestGetRawAsyncByText(string environment, string cluster, stri ConfigFormat = ConfigFormats.Text, Content = "test" }.Serialize(_jsonSerializerOptions)).Verifiable(); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); var ret = await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()); Assert.IsTrue(ret.Raw == "test"); Assert.IsTrue(ret.ConfigurationType == ConfigurationTypes.Text); @@ -109,8 +115,8 @@ public async Task TestGetRawAsyncByProperty(string environment, string cluster, { new Property() { - Key="Brand", - Value="Microsoft" + Key = "Brand", + Value = "Microsoft" } }; _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() @@ -118,7 +124,7 @@ public async Task TestGetRawAsyncByProperty(string environment, string cluster, ConfigFormat = ConfigFormats.Text, Content = properties.Serialize(_jsonSerializerOptions) }.Serialize(_jsonSerializerOptions)).Verifiable(); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); var ret = await client.GetRawAsync(environment, cluster, appId, configObject, It.IsAny>()); Assert.IsTrue(ret.Raw == properties.Serialize(_jsonSerializerOptions)); Assert.IsTrue(ret.ConfigurationType == ConfigurationTypes.Text); @@ -141,7 +147,7 @@ public async Task GetAsyncByJson(string environment, string cluster, string appI _trigger.Content = newBrand.Serialize(_jsonSerializerOptions); _trigger.Action = action; }); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); var ret = await client.GetAsync(environment, cluster, appId, configObject, (Brands br) => { Assert.IsTrue(br.Id == newBrand.Id); @@ -168,7 +174,7 @@ public async Task GetAsyncByJson(string environment, string cluster, string appI _trigger.Content = newBrand.Serialize(_jsonSerializerOptions); _trigger.Action = action; }); - client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); ret = await client.GetAsync(environment, cluster, appId, configObject, null); Assert.IsNotNull(ret); Assert.IsTrue(ret.Id == brand.Id && ret.Name == brand.Name); @@ -181,10 +187,22 @@ public async Task GetAsyncByJson(string environment, string cluster, string appI ConfigFormat = ConfigFormats.Json, Content = brand.Serialize(_jsonSerializerOptions) }.Serialize(_jsonSerializerOptions)); - client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); ret = await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); Assert.IsNotNull(ret); Assert.IsTrue(ret.Id == brand.Id && ret.Name == brand.Name); + + Initialize(); + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Json, + Content = brand.Serialize(_jsonSerializerOptions) + }.Serialize(_jsonSerializerOptions)).Verifiable(); + client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () => + { + await client.GetAsync(environment, cluster, appId, configObject, null); + }); } [TestMethod] @@ -196,8 +214,20 @@ public async Task GetAsyncByText(string environment, string cluster, string appI ConfigFormat = ConfigFormats.Text, Content = "test" }.Serialize(_jsonSerializerOptions)).Verifiable(); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); - await Assert.ThrowsExceptionAsync(async () => await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>())); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () => + { + await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); + }); + + Initialize(); + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() + { + ConfigFormat = ConfigFormats.Text, + Content = "1" + }.Serialize(_jsonSerializerOptions)).Verifiable(); + client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + Assert.IsTrue(await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()) == 1); } [TestMethod] @@ -209,7 +239,7 @@ public async Task GetAsyncByProperty(string environment, string cluster, string new Property() { Key = "Id", - Value=Guid.NewGuid().ToString(), + Value = Guid.NewGuid().ToString(), }, new Property() { @@ -222,11 +252,12 @@ public async Task GetAsyncByProperty(string environment, string cluster, string ConfigFormat = ConfigFormats.Properties, Content = brand.Serialize(_jsonSerializerOptions) }.Serialize(_jsonSerializerOptions)).Verifiable(); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); var ret = await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); Assert.IsNotNull(ret); - Assert.IsTrue(ret.Id.ToString() == brand.Where(b => b.Key == "Id").Select(t => t.Value).FirstOrDefault() && ret.Name == brand.Where(b => b.Key == "Name").Select(t => t.Value).FirstOrDefault()); + Assert.IsTrue(ret.Id.ToString() == brand.Where(b => b.Key == "Id").Select(t => t.Value).FirstOrDefault() && + ret.Name == brand.Where(b => b.Key == "Name").Select(t => t.Value).FirstOrDefault()); } [TestMethod] @@ -245,7 +276,7 @@ public async Task GetDynamicAsyncByJson(string environment, string cluster, stri _trigger.Content = newBrand.Serialize(_jsonSerializerOptions); _trigger.Action = action; }).Verifiable(); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); var ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, (dynamic obj) => { Assert.IsTrue((obj.Id + "") == newBrand.Id.ToString()); @@ -274,7 +305,7 @@ public async Task GetDynamicAsyncByJson(string environment, string cluster, stri _trigger.Content = newBrand.Serialize(_jsonSerializerOptions); _trigger.Action = action; }).Verifiable(); - client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny()); Assert.IsNotNull(ret); Assert.IsTrue(ret.Id == brand.Id.ToString()); @@ -290,12 +321,25 @@ public async Task GetDynamicAsyncByJson(string environment, string cluster, stri ConfigFormat = ConfigFormats.Json, Content = brand.Serialize(_jsonSerializerOptions) }.Serialize(_jsonSerializerOptions)); - client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); Assert.IsNotNull(ret); Assert.IsTrue(ret.Id == brand.Id.ToString() && ret.Name == brand.Name); } + [TestMethod] + [DataRow("DccOptions.ManageServiceAddress", "http://localhost:6379")] + [DataRow("DccOptions.RedisOptions.DefaultDatabase", "0")] + [DataRow("DccOptions.RedisOptions.Password", "")] + public async Task GetDynamicAsync(string key, string value) + { + var configuration = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build(); + _services.AddSingleton(configuration); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var res = (await client.GetDynamicAsync(key)); + Assert.IsTrue(res + "" == value); + } + [TestMethod] [DataRow("Test", "Default", "DccTest", "Brand")] public async Task GetDynamicAsyncByText(string environment, string cluster, string appId, string configObject) @@ -306,8 +350,11 @@ public async Task GetDynamicAsyncByText(string environment, string cluster, stri ConfigFormat = ConfigFormats.Text, Content = result }.Serialize(_jsonSerializerOptions)).Verifiable(); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); - await Assert.ThrowsExceptionAsync(async () => { await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); }); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + await Assert.ThrowsExceptionAsync(async () => + { + await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); + }); } [TestMethod] @@ -319,7 +366,7 @@ public async Task GetDynamicAsyncByProperty(string environment, string cluster, new Property() { Key = "Id", - Value=Guid.NewGuid().ToString(), + Value = Guid.NewGuid().ToString(), }, new Property() { @@ -332,7 +379,7 @@ public async Task GetDynamicAsyncByProperty(string environment, string cluster, ConfigFormat = ConfigFormats.Properties, Content = brand.Serialize(_jsonSerializerOptions) }.Serialize(_jsonSerializerOptions)).Verifiable(); - var client = new ConfigurationAPIClient(_client.Object, _jsonSerializerOptions, _dccSectionOptions, null); + var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); var ret = await client.GetDynamicAsync(environment, cluster, appId, configObject, It.IsAny>()); Assert.IsNotNull(ret); diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/appsettings.json b/test/MASA.Contrib.BasicAbility.Dcc.Tests/appsettings.json index 042a485d1..144652eea 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/appsettings.json +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/appsettings.json @@ -1,15 +1,17 @@ { "DccOptions": { - "Servers": [ - { - "Host": "localhost", - "Port": 8888 - } - ], - "DefaultDatabase": 0, - "Password": "", - "DccServiceAddress": "http://localhost:6379", - "SubscribeKeyPrefix": "masa.dcc:" + "ManageServiceAddress": "http://localhost:6379", + "SubscribeKeyPrefix": "masa.dcc:", + "RedisOptions": { + "Servers": [ + { + "Host": "localhost", + "Port": 8888 + } + ], + "DefaultDatabase": 0, + "Password": "" + } }, "AppId": "WebApplication1", "Environment": "Development", diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/expandSections.json b/test/MASA.Contrib.BasicAbility.Dcc.Tests/expandSections.json index b16a77dfb..28e953152 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/expandSections.json +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/expandSections.json @@ -1,14 +1,16 @@ { "DccOptions": { - "Servers": [ - { - "Host": "localhost", - "Port": 8888 - } - ], - "DefaultDatabase": 0, - "Password": "", - "DccServiceAddress": "http://localhost:6379" + "ManageServiceAddress": "http://localhost:6379", + "RedisOptions": { + "Servers": [ + { + "Host": "localhost", + "Port": 8888 + } + ], + "DefaultDatabase": 0, + "Password": "" + } }, "AppId": "DccTest", "Environment": "Test", diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Repositories/OrderRepository.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Repositories/OrderRepository.cs index 176bef55e..717b8527f 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Repositories/OrderRepository.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Infrastructure/Repositories/OrderRepository.cs @@ -15,7 +15,7 @@ public async Task AddAsync(Orders order) await base.SaveChangesAsync(); await base.CommitAsync(); } - catch (Exception ex) + catch (Exception) { await base.RollbackAsync(); } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs index 42dec62e5..cdc56df5a 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/RepositoryTest.cs @@ -17,6 +17,7 @@ public void Initialize() typeof(BaseRepositoryTest).Assembly }; _uoW = new(); + _uoW.Setup(uoW => uoW.UseTransaction).Returns(true); _dispatcherOptions = new(); _dispatcherOptions.Setup(options => options.Services).Returns(() => _services); @@ -85,11 +86,12 @@ await repository.AddAsync(new Orders(4) await repository.RemoveAsync(order => order.Description == "Apple", default); await repository.UnitOfWork.SaveChangesAsync(default); - var list = await repository.GetPaginatedListAsync(0, 10, "desc", default); + var list = await repository.GetPaginatedListAsync(0, 10, null, default); Assert.IsTrue(list.Count == 3); - Assert.IsTrue(list[0].Description == "Microsoft"); + Assert.IsTrue(list[0].Description == "HuaWei"); Assert.IsTrue(list[1].Description == "Google"); + Assert.IsTrue(list[2].Description == "Microsoft"); list = await repository.GetPaginatedListAsync(1, 10, null, default); Assert.IsTrue(list.Count == 2); @@ -103,7 +105,7 @@ await repository.AddAsync(new Orders(4) var count = await repository.GetCountAsync(default); Assert.IsTrue(count == 3); - var huaWei = await repository.FindAsync(huaweiOrder.Id); + var huaWei = await repository.FindAsync(huaweiOrder.Id, huaweiOrder.OrderNumber); await repository.RemoveAsync(huaWei!, default); await repository.UnitOfWork.SaveChangesAsync(default); @@ -262,14 +264,10 @@ public void TestErrorCompositeKeys() } [TestMethod] - public void TestErrorEntity() + public void TestPrivateEntity() { _services.AddScoped(typeof(IUnitOfWork), serviceProvider => _uoW.Object); _services.AddDbContext(options => options.UseSqlite(_connection)); - - Assert.ThrowsException(() => - { - _dispatcherOptions.Object.UseRepository(typeof(BaseRepositoryTest).Assembly, typeof(Hobbies).Assembly); - }); + _dispatcherOptions.Object.UseRepository(typeof(BaseRepositoryTest).Assembly, typeof(Hobbies).Assembly); } } diff --git a/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs b/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs index 9f0a8a30a..c82972410 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs +++ b/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs @@ -312,10 +312,7 @@ public void TestDomainQueryUnitOfWork() { domainQuery.UnitOfWork = _uoW.Object; }); - Assert.ThrowsException(() => - { - var unitOfWork = domainQuery.UnitOfWork; - }); + Assert.IsNull(domainQuery.UnitOfWork); } [TestMethod] diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj index ee2e76853..c8d7af8c5 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj @@ -18,7 +18,7 @@ - + diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs b/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs index bfa843978..53a7c7e05 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs @@ -51,7 +51,7 @@ public void TestUseSoftDelete() }); dbContext.SaveChanges(); Assert.IsTrue(dbContext.Students.Count() == 1); - uoW.Verify(u => u.Transaction, Times.Once); + uoW.Verify(u => u.Transaction, Times.Never); var student = dbContext.Students.Where(s => s.Name == "Tom").FirstOrDefault(); Assert.IsNotNull(student); @@ -66,6 +66,7 @@ public void TestUseSoftDelete() uoW = new(); uoW.Setup(u => u.Transaction).Verifiable(); + uoW.Setup(u => u.UseTransaction).Returns(() => true); services = new ServiceCollection(); services.AddScoped(serviceProvider => uoW.Object); services.AddMasaDbContext(option => diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/Events/DeductionMoneyEvent.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/Events/DeductionMoneyEvent.cs index d36975649..9623b3fc3 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/Events/DeductionMoneyEvent.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/Events/DeductionMoneyEvent.cs @@ -2,7 +2,7 @@ namespace MASA.Contrib.Dispatcher.Events.Tests.Events; public record DeductionMoneyEvent : Event, ITransaction { - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork? UnitOfWork { get; set; } public string Account { get; set; } diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/Events/IncreaseMoneyEvent.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/Events/IncreaseMoneyEvent.cs index 62ed400e9..ecbe79664 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/Events/IncreaseMoneyEvent.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/Events/IncreaseMoneyEvent.cs @@ -2,7 +2,7 @@ namespace MASA.Contrib.Dispatcher.Events.Tests.Events; public record IncreaseMoneyEvent : Event, ITransaction { - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork? UnitOfWork { get; set; } public string Account { get; set; } diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/Events/OrderPaymentFailedIntegrationEvent.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/Events/OrderPaymentFailedIntegrationEvent.cs index 814545634..c715ad3ce 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/Events/OrderPaymentFailedIntegrationEvent.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/Events/OrderPaymentFailedIntegrationEvent.cs @@ -8,7 +8,7 @@ public class OrderPaymentFailedIntegrationEvent : IIntegrationEvent public string Topic { get; set; } = nameof(OrderPaymentFailedIntegrationEvent); - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork? UnitOfWork { get; set; } public string OrderId { get; set; } diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj b/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj index 8f816f4b7..3470232d9 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/MASA.Contrib.Dispatcher.Events.Tests.csproj @@ -3,6 +3,7 @@ net6.0 false + enable Full enable diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/Events/IntegrationEvent.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/Events/IntegrationEvent.cs index 32fc849e8..445a38cec 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/Events/IntegrationEvent.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/Events/IntegrationEvent.cs @@ -7,7 +7,7 @@ public abstract record IntegrationEvent : IIntegrationEvent public DateTime CreationTime { get; init; } [JsonIgnore] - public IUnitOfWork UnitOfWork { get; set; } + public IUnitOfWork? UnitOfWork { get; set; } public abstract string Topic { get; set; } From ff4e9ac4e73174e3ddfda8c0cdce1316fe10ee5b Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Tue, 23 Nov 2021 15:42:48 +0800 Subject: [PATCH 08/39] chore: add package CI --- .github/workflows/packge.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/packge.yml diff --git a/.github/workflows/packge.yml b/.github/workflows/packge.yml new file mode 100644 index 000000000..e83542f72 --- /dev/null +++ b/.github/workflows/packge.yml @@ -0,0 +1,34 @@ + +name: Packege CI +on: + push: + branches: [ develop ] + pull_request: + branches: [ develop ] + +jobs: + packeg-build: + name: packeg build and push + runs-on: ${{matrix.os}} + strategy: + matrix: +# os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest] + steps: + - name: git pull + uses: actions/checkout@v2 + - name: run a one-line script + run: env + - name: setting dotnet version + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '6.0.x' + include-prerelease: true + - name: package push + run: | + env + echo "------------------------------------------------------" + ls + dotnet pack --include-symbols -p:PackageVersion=0.0.$GITHUB_RUN_ID + dotnet nuget push "**/*.symbols.nupkg" -k ${{secrets.NUGET_TOKEN}} -s https://api.nuget.org/v3/index.json + \ No newline at end of file From dc33a5da4484186413e76c6381a383524b7a89ed Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Tue, 23 Nov 2021 17:33:54 +0800 Subject: [PATCH 09/39] chore: update library package --- nuget.config | 17 +++++------------ .../MASA.Contrib.BasicAbility.Dcc.csproj | 10 +++++----- .../MASA.Contrib.Configuration.csproj | 2 +- ...MASA.Contrib.DDD.Domain.Repository.EF.csproj | 2 +- .../MASA.Contrib.DDD.Domain.csproj | 2 +- .../MASA.Contrib.Data.Contracts.EF.csproj | 6 +++--- .../MASA.Contrib.Data.UoW.EF.csproj | 6 +++--- .../MASA.Contrib.Dispatcher.Events.csproj | 10 +++++----- ...rib.Dispatcher.IntegrationEvents.Dapr.csproj | 4 ++-- ...atcher.IntegrationEvents.EventLogs.EF.csproj | 4 ++-- .../MASA.Contrib.ReadWriteSpliting.CQRS.csproj | 4 ++-- .../MASA.Contrib.Service.MinimalAPIs.csproj | 6 +++--- .../MASA.Contrib.Data.Contracts.EF.Test.csproj | 4 ++-- 13 files changed, 35 insertions(+), 42 deletions(-) diff --git a/nuget.config b/nuget.config index b3dcc28ac..3f0e00340 100644 --- a/nuget.config +++ b/nuget.config @@ -1,13 +1,6 @@ - + - - - - - - - - - - - + + + + \ No newline at end of file diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj index cdac58bc6..bc9812c5c 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj @@ -7,11 +7,11 @@ - - - - - + + + + + diff --git a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj index 2265db45e..e95bf4806 100644 --- a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj +++ b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj index 4c704c871..2a97adf92 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj index 08faf8c1b..5763c4ccc 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj index 83d7a6f43..7ff5a4f00 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj index 20753b006..4ec7c7033 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj +++ b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj index 135d58413..000208500 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj @@ -7,11 +7,11 @@ - - - - - + + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj index e60c5db20..cef8f0c46 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj index f845563ae..38ee74aab 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj index cfddea1de..a8c8967cc 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj index 7fbd788b8..89d0fdd9b 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj index c8d7af8c5..90a5be082 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj +++ b/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj @@ -18,8 +18,8 @@ - - + + From e8b9bebaafbf40cba3b15724e331cca05f96c12c Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Tue, 23 Nov 2021 18:15:39 +0800 Subject: [PATCH 10/39] chore: add Codecov --- appveyor.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..4cfd30948 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,8 @@ +- name: Restore dependencies + run: dotnet restore +- name: Build + run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true +- name: Test + run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover +- name: Codecov + uses: codecov/codecov-action@v1 \ No newline at end of file From 1f247e749c2d944446bd12891de2f5cc2c48df2f Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Tue, 23 Nov 2021 18:31:07 +0800 Subject: [PATCH 11/39] chore: update codecov --- .github/workflows/packge.yml | 6 ++++++ appveyor.yml | 8 -------- 2 files changed, 6 insertions(+), 8 deletions(-) delete mode 100644 appveyor.yml diff --git a/.github/workflows/packge.yml b/.github/workflows/packge.yml index e83542f72..0a746ef7c 100644 --- a/.github/workflows/packge.yml +++ b/.github/workflows/packge.yml @@ -24,6 +24,12 @@ jobs: with: dotnet-version: '6.0.x' include-prerelease: true + - name: build + run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true + - name: test + run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + - name: codecov + uses: codecov/codecov-action@v1 - name: package push run: | env diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 4cfd30948..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,8 +0,0 @@ -- name: Restore dependencies - run: dotnet restore -- name: Build - run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true -- name: Test - run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover -- name: Codecov - uses: codecov/codecov-action@v1 \ No newline at end of file From 73a7493f2f846c45aeaf5355a85d30476bb5bf78 Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Tue, 23 Nov 2021 18:34:19 +0800 Subject: [PATCH 12/39] chore: update codecov --- .github/workflows/packge.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/packge.yml b/.github/workflows/packge.yml index 0a746ef7c..1ec7b2106 100644 --- a/.github/workflows/packge.yml +++ b/.github/workflows/packge.yml @@ -24,6 +24,8 @@ jobs: with: dotnet-version: '6.0.x' include-prerelease: true + - name: restore + run: dotnet restore - name: build run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true - name: test From ee81ac4332f098101d7d99d3ae26767bcff7f5fe Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Tue, 23 Nov 2021 18:39:53 +0800 Subject: [PATCH 13/39] docs: add codecov badge --- README.md | 2 ++ README.zh-CN.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2dff7b60c..dd21b39e8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ [中](README.zh-CN.md) | EN +[![codecov](https://codecov.io/gh/masastack/MASA.Contrib/branch/develop/graph/badge.svg?token=87TPNHUHW2)](https://codecov.io/gh/masastack/MASA.Contrib) + # MASA.Contrib The purpose of MASA.Contrib is based on [MASA.BuildingBlocks](https://github.com/masastack/MASA.BuildingBlocks) to provide open, community driven reusable components for building mesh applications. These components will be used by the [MASA Stack](https://github.com/masastack) and [MASA Labs](https://github.com/masalabs) projects. diff --git a/README.zh-CN.md b/README.zh-CN.md index 3ba8b29be..8093fddf3 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,4 +1,6 @@ -中 | [EN](README.md) +中 | [EN](README.md) + +[![codecov](https://codecov.io/gh/masastack/MASA.Contrib/branch/develop/graph/badge.svg?token=87TPNHUHW2)](https://codecov.io/gh/masastack/MASA.Contrib) # MASA.Contrib From e8292392919efbdf1b7891b6d2f2cbf3c04ddc36 Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Tue, 23 Nov 2021 18:52:26 +0800 Subject: [PATCH 14/39] chore: codecov ignore tests --- .github/workflows/packge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/packge.yml b/.github/workflows/packge.yml index 1ec7b2106..976db7734 100644 --- a/.github/workflows/packge.yml +++ b/.github/workflows/packge.yml @@ -29,7 +29,7 @@ jobs: - name: build run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true - name: test - run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + run: dotnet test --filter FullyQualifiedName!~.Tests --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: codecov uses: codecov/codecov-action@v1 - name: package push From 9020481d9ee0b1cb03cd18c8969a69c2aefdc43d Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Tue, 23 Nov 2021 19:08:40 +0800 Subject: [PATCH 15/39] chore: update codecov --- .github/workflows/packge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/packge.yml b/.github/workflows/packge.yml index 976db7734..075bcf684 100644 --- a/.github/workflows/packge.yml +++ b/.github/workflows/packge.yml @@ -29,7 +29,7 @@ jobs: - name: build run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true - name: test - run: dotnet test --filter FullyQualifiedName!~.Tests --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + run: dotnet test --filter "Name!~.Tests" --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover - name: codecov uses: codecov/codecov-action@v1 - name: package push From c52e535a486ab1b61e53eefad85c0c2a6eb431a1 Mon Sep 17 00:00:00 2001 From: dodd <358683537@qq.com> Date: Tue, 23 Nov 2021 19:13:38 +0800 Subject: [PATCH 16/39] chore: update codecov --- .github/workflows/packge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/packge.yml b/.github/workflows/packge.yml index 075bcf684..9d96fe176 100644 --- a/.github/workflows/packge.yml +++ b/.github/workflows/packge.yml @@ -29,7 +29,7 @@ jobs: - name: build run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true - name: test - run: dotnet test --filter "Name!~.Tests" --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover + run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover --filter "Name!~.Tests" - name: codecov uses: codecov/codecov-action@v1 - name: package push From a5ebb5e1e63e4555a8d1e945285d71a80254c1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E5=B5=98?= Date: Wed, 24 Nov 2021 03:05:37 +0000 Subject: [PATCH 17/39] Update packge.yml --- .github/workflows/packge.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/packge.yml b/.github/workflows/packge.yml index 9d96fe176..05cd6d9e6 100644 --- a/.github/workflows/packge.yml +++ b/.github/workflows/packge.yml @@ -1,4 +1,3 @@ - name: Packege CI on: push: @@ -29,7 +28,7 @@ jobs: - name: build run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true - name: test - run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover --filter "Name!~.Tests" + run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[*.Tests]*" - name: codecov uses: codecov/codecov-action@v1 - name: package push @@ -39,4 +38,4 @@ jobs: ls dotnet pack --include-symbols -p:PackageVersion=0.0.$GITHUB_RUN_ID dotnet nuget push "**/*.symbols.nupkg" -k ${{secrets.NUGET_TOKEN}} -s https://api.nuget.org/v3/index.json - \ No newline at end of file + From f291f21b9aa451ef1dcb7aa9c4ad085d1cdbc6c6 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Wed, 24 Nov 2021 03:41:33 +0000 Subject: [PATCH 18/39] Feature/ci --- MASA.Contrib.sln | 194 +++++++++--------- .../Parser/JsonConfigurationParser.cs | 2 +- .../ServiceCollectionRepositoryExtensions.cs | 2 +- .../Repository.cs | 2 +- .../DccClientTest.cs | 15 +- .../DccManageTest.cs | 13 +- .../DccTest.cs | 32 +-- .../ErrorKafkaOptions.cs | 2 +- .../KafkaOptions.cs | 2 +- ...guration.ErrorSectionAutoMap.Tests.csproj} | 0 .../_Imports.cs | 0 ...ion.MountErrorSectionAutoMap.Tests.csproj} | 0 .../MountSectionRedisOptions.cs | 2 +- .../_Imports.cs | 0 .../ConfigurationTest.cs | 5 +- .../MASA.Contrib.Configuration.Tests.csproj | 4 +- .../_Imports.cs | 2 + ...n.Repository.EF.CombinedKeys.Tests.csproj} | 0 .../Students.cs | 2 +- .../_Imports.cs | 0 .../Courses.cs | 2 +- ...sitory.EF.CombinedKeysNoFind.Tests.csproj} | 0 .../Entities/User.cs | 2 +- ...pository.EF.CustomRepository.Tests.csproj} | 0 .../Repositories/IUserRepository.cs | 4 +- .../_Imports.cs | 1 - .../Hobbies.cs | 6 +- ....Domain.Repository.EF.Entity.Tests.csproj} | 0 .../_Imports.cs | 0 .../BaseRepositoryTest.cs | 4 +- .../Domain/Entities/Address.cs | 31 ++- ...trib.DDD.Domain.Repository.EF.Tests.csproj | 8 +- .../_Imports.cs | 8 +- .../DomainEventBusTest.cs | 6 +- .../MASA.Contrib.DDD.Domain.Tests.csproj | 2 +- .../MASA.Contrib.DDD.Domain.Tests/_Imports.cs | 4 +- .../Domain/Entities/Courses.cs | 4 +- .../Domain/Entities/Students.cs | 6 +- .../Infrastructure/CustomDbContext.cs | 4 +- ...SA.Contrib.Data.Contracts.EF.Tests.csproj} | 0 .../SoftDeleteTest.cs | 5 +- .../_Imports.cs | 3 +- .../TestUnitOfWork.cs | 2 +- .../Benchmarks.cs | 2 +- .../Extensions/EventHandlers/CouponHandler.cs | 4 +- .../Extensions/EventHandlers/NoticeHandler.cs | 4 +- .../Extensions/Events/ForgetPasswordEvent.cs | 2 +- .../Extensions/Events/RegisterUserEvent.cs | 2 +- .../Middleware/LoggingMiddleware.cs | 2 +- ...tcher.Events.BenchmarkDotnet.Tests.csproj} | 0 .../Program.cs | 2 +- .../_Imports.cs | 5 +- .../AssemblyResolutionTests.cs | 6 +- .../ChoreTest.cs | 6 +- .../FeaturesTest.cs | 8 +- .../SagaTest.cs | 12 +- .../TestBase.cs | 4 +- .../IntegrationEventBusTest.cs | 8 +- .../IntegrationEventLogServiceTest.cs | 6 +- ...Contribs.DDD.Domain.Entities.Tests.csproj} | 0 .../Users.cs | 2 +- .../_Imports.cs | 0 ...MASA.Contribs.DDD.Domain.Repository.csproj | 10 - .../_Imports.cs | 0 64 files changed, 231 insertions(+), 235 deletions(-) rename test/{MASA.Contrib.Configuration.ErrorSectionAutoMapTests => MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests}/ErrorKafkaOptions.cs (77%) rename test/{MASA.Contrib.Configuration.ErrorSectionAutoMapTests => MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests}/KafkaOptions.cs (82%) rename test/{MASA.Contrib.Configuration.ErrorSectionAutoMapTests/MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj => MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests.csproj} (100%) rename test/{MASA.Contrib.Configuration.ErrorSectionAutoMapTests => MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests}/_Imports.cs (100%) rename test/{MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj => MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests.csproj} (100%) rename test/{MASA.Contrib.Configuration.MountErrorSectionAutoMapTests => MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests}/MountSectionRedisOptions.cs (98%) rename test/{MASA.Contrib.Configuration.MountErrorSectionAutoMapTests => MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests}/_Imports.cs (100%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj => MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests.csproj} (100%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests => MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests}/Students.cs (90%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests => MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests}/_Imports.cs (100%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj => MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFind.Tests.csproj} (100%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository => MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests}/Entities/User.cs (91%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj => MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests.csproj} (100%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository => MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests}/Repositories/IUserRepository.cs (55%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository => MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests}/_Imports.cs (58%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.EntityTests => MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests}/Hobbies.cs (58%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj => MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests.csproj} (100%) rename test/{MASA.Contrib.DDD.Domain.Repository.EF.EntityTests => MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests}/_Imports.cs (100%) rename test/{MASA.Contrib.Data.Contracts.EF.Test => MASA.Contrib.Data.Contracts.EF.Tests}/Domain/Entities/Courses.cs (68%) rename test/{MASA.Contrib.Data.Contracts.EF.Test => MASA.Contrib.Data.Contracts.EF.Tests}/Domain/Entities/Students.cs (60%) rename test/{MASA.Contrib.Data.Contracts.EF.Test => MASA.Contrib.Data.Contracts.EF.Tests}/Infrastructure/CustomDbContext.cs (66%) rename test/{MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj => MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj} (100%) rename test/{MASA.Contrib.Data.Contracts.EF.Test => MASA.Contrib.Data.Contracts.EF.Tests}/SoftDeleteTest.cs (95%) rename test/{MASA.Contrib.Data.Contracts.EF.Test => MASA.Contrib.Data.Contracts.EF.Tests}/_Imports.cs (75%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests}/Benchmarks.cs (96%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests}/Extensions/EventHandlers/CouponHandler.cs (89%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests}/Extensions/EventHandlers/NoticeHandler.cs (91%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests}/Extensions/Events/ForgetPasswordEvent.cs (60%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests}/Extensions/Events/RegisterUserEvent.cs (59%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests}/Extensions/Middleware/LoggingMiddleware.cs (85%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.csproj} (100%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests}/Program.cs (83%) rename test/{MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest => MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests}/_Imports.cs (73%) rename test/{MASA.Contribs.DDD.Domain.Entities/MASA.Contribs.DDD.Domain.Entities.csproj => MASA.Contribs.DDD.Domain.Entities.Tests/MASA.Contribs.DDD.Domain.Entities.Tests.csproj} (100%) rename test/{MASA.Contribs.DDD.Domain.Entities => MASA.Contribs.DDD.Domain.Entities.Tests}/Users.cs (62%) rename test/{MASA.Contribs.DDD.Domain.Entities => MASA.Contribs.DDD.Domain.Entities.Tests}/_Imports.cs (100%) delete mode 100644 test/MASA.Contribs.DDD.Domain.Repository/MASA.Contribs.DDD.Domain.Repository.csproj delete mode 100644 test/MASA.Contribs.DDD.Domain.Repository/_Imports.cs diff --git a/MASA.Contrib.sln b/MASA.Contrib.sln index dce90e45e..7ce1804cd 100644 --- a/MASA.Contrib.sln +++ b/MASA.Contrib.sln @@ -42,8 +42,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Data", "Data", "{E33ADF54-4 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Dispatcher.Events", "src\Dispatcher\MASA.Contrib.Dispatcher.Events\MASA.Contrib.Dispatcher.Events.csproj", "{1B44F2E7-28F5-4E88-B8A8-3F336800FD5C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest", "test\MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest\MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj", "{0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests", "test\MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests\MASA.Contrib.Dispatcher.Events.CheckMethodsParameter.Tests.csproj", "{D55A7D3B-9C24-4029-BC03-41B28AD11DB6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Dispatcher.Events.CheckMethodsParameterNotNull.Tests", "test\MASA.Contrib.Dispatcher.Events.CheckMethodsParameterNotNull.Tests\MASA.Contrib.Dispatcher.Events.CheckMethodsParameterNotNull.Tests.csproj", "{89B2A693-CD8A-4EA2-9991-2CEE44C4D04B}" @@ -84,12 +82,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Dispatcher.Int EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MASA.Contrib.DDD.Domain", "MASA.Contrib.DDD.Domain", "{13EDB361-AF88-4F89-B4AB-46622BCCBC37}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contribs.DDD.Domain.Entities", "test\MASA.Contribs.DDD.Domain.Entities\MASA.Contribs.DDD.Domain.Entities.csproj", "{647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MASA.Contrib.DDD.Domain.Repository.EF", "MASA.Contrib.DDD.Domain.Repository.EF", "{880E8263-AECC-4793-BD28-7CD03650D124}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository", "test\MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository\MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj", "{7A1493EC-196F-4389-A966-02E526453578}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.UoW.EF", "src\Data\MASA.Contrib.Data.UoW.EF\MASA.Contrib.Data.UoW.EF.csproj", "{1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.UoW.EF.Tests", "test\MASA.Contrib.Data.UoW.EF.Tests\MASA.Contrib.Data.UoW.EF.Tests.csproj", "{1B16DD58-0847-45A7-AF93-53EBFBEDAAE7}" @@ -98,12 +92,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.BasicAbility.D EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration", "src\Configuration\MASA.Contrib.Configuration\MASA.Contrib.Configuration.csproj", "{C056C688-8FFC-42BC-B4EA-EF3808A8A12C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.EntityTests", "test\MASA.Contrib.DDD.Domain.Repository.EF.EntityTests\MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj", "{9CC40E07-C24B-4EC8-B05B-56CF986E0477}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests", "test\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj", "{313E60D8-23E3-419C-9EC7-7C625DFDC1A7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests", "test\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj", "{A2667784-9BA0-47AC-A327-C0C8F95B26D3}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.ReadWriteSpliting.CQRS.Tests", "test\MASA.Contrib.ReadWriteSpliting.CQRS.Tests\MASA.Contrib.ReadWriteSpliting.CQRS.Tests.csproj", "{428CDAF3-957A-4017-82EA-70737F205546}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration.Tests", "test\MASA.Contrib.Configuration.Tests\MASA.Contrib.Configuration.Tests.csproj", "{DB93B639-899D-4B2C-AF8A-47B4BC6B3776}" @@ -112,13 +100,25 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.BasicAbility.D EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MASA.Contrib.Configuration", "MASA.Contrib.Configuration", "{9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration.ErrorSectionAutoMapTests", "test\MASA.Contrib.Configuration.ErrorSectionAutoMapTests\MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj", "{2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Service.MinimalAPIs.Tests", "test\MASA.Contrib.Service.MinimalAPIs.Tests\MASA.Contrib.Service.MinimalAPIs.Tests.csproj", "{A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contribs.DDD.Domain.Entities.Tests", "test\MASA.Contribs.DDD.Domain.Entities.Tests\MASA.Contribs.DDD.Domain.Entities.Tests.csproj", "{B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration.MountErrorSectionAutoMapTests", "test\MASA.Contrib.Configuration.MountErrorSectionAutoMapTests\MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj", "{17CD5E42-C589-47CA-8FF2-7B6D3B70131A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.Contracts.EF.Tests", "test\MASA.Contrib.Data.Contracts.EF.Tests\MASA.Contrib.Data.Contracts.EF.Tests.csproj", "{5A163042-B03A-4063-85FF-22D4C5BB5B90}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Service.MinimalAPIs.Tests", "test\MASA.Contrib.Service.MinimalAPIs.Tests\MASA.Contrib.Service.MinimalAPIs.Tests.csproj", "{A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests", "test\MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests\MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests.csproj", "{84EFF9E1-6852-458F-8D57-62E3F084EA0F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests", "test\MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests\MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests.csproj", "{427822F2-7A20-4E3A-B45C-43CE855003C1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFind.Tests", "test\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFind.Tests.csproj", "{99067BDF-2C6A-47F8-913D-3FF9F2A69F98}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests", "test\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests\MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests.csproj", "{A4DE46BD-1FA4-494B-80DA-6EB370686F17}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests", "test\MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests\MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests.csproj", "{7909A736-6C1E-4622-9BE7-37EF0839FA05}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests", "test\MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests\MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests.csproj", "{71E02AFA-06A0-4527-923C-6666B3D66542}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Data.Contracts.EF.Test", "test\MASA.Contrib.Data.Contracts.EF.Test\MASA.Contrib.Data.Contracts.EF.Test.csproj", "{0843A857-87A3-4603-9659-160B2DCE36AC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests", "test\MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests\MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.csproj", "{1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -144,14 +144,6 @@ Global {1B44F2E7-28F5-4E88-B8A8-3F336800FD5C}.Release|Any CPU.Build.0 = Release|Any CPU {1B44F2E7-28F5-4E88-B8A8-3F336800FD5C}.Release|x64.ActiveCfg = Release|Any CPU {1B44F2E7-28F5-4E88-B8A8-3F336800FD5C}.Release|x64.Build.0 = Release|Any CPU - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}.Debug|x64.ActiveCfg = Debug|Any CPU - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}.Debug|x64.Build.0 = Debug|Any CPU - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}.Release|Any CPU.Build.0 = Release|Any CPU - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}.Release|x64.ActiveCfg = Release|Any CPU - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6}.Release|x64.Build.0 = Release|Any CPU {D55A7D3B-9C24-4029-BC03-41B28AD11DB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D55A7D3B-9C24-4029-BC03-41B28AD11DB6}.Debug|Any CPU.Build.0 = Debug|Any CPU {D55A7D3B-9C24-4029-BC03-41B28AD11DB6}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -304,22 +296,6 @@ Global {761C3313-A669-465F-A384-9E118FCE4F89}.Release|Any CPU.Build.0 = Release|Any CPU {761C3313-A669-465F-A384-9E118FCE4F89}.Release|x64.ActiveCfg = Release|Any CPU {761C3313-A669-465F-A384-9E118FCE4F89}.Release|x64.Build.0 = Release|Any CPU - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}.Debug|Any CPU.Build.0 = Debug|Any CPU - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}.Debug|x64.ActiveCfg = Debug|Any CPU - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}.Debug|x64.Build.0 = Debug|Any CPU - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}.Release|Any CPU.ActiveCfg = Release|Any CPU - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}.Release|Any CPU.Build.0 = Release|Any CPU - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}.Release|x64.ActiveCfg = Release|Any CPU - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32}.Release|x64.Build.0 = Release|Any CPU - {7A1493EC-196F-4389-A966-02E526453578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7A1493EC-196F-4389-A966-02E526453578}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7A1493EC-196F-4389-A966-02E526453578}.Debug|x64.ActiveCfg = Debug|Any CPU - {7A1493EC-196F-4389-A966-02E526453578}.Debug|x64.Build.0 = Debug|Any CPU - {7A1493EC-196F-4389-A966-02E526453578}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7A1493EC-196F-4389-A966-02E526453578}.Release|Any CPU.Build.0 = Release|Any CPU - {7A1493EC-196F-4389-A966-02E526453578}.Release|x64.ActiveCfg = Release|Any CPU - {7A1493EC-196F-4389-A966-02E526453578}.Release|x64.Build.0 = Release|Any CPU {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Debug|Any CPU.Build.0 = Debug|Any CPU {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -352,30 +328,6 @@ Global {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Release|Any CPU.Build.0 = Release|Any CPU {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Release|x64.ActiveCfg = Release|Any CPU {C056C688-8FFC-42BC-B4EA-EF3808A8A12C}.Release|x64.Build.0 = Release|Any CPU - {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Debug|x64.ActiveCfg = Debug|Any CPU - {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Debug|x64.Build.0 = Debug|Any CPU - {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Release|Any CPU.Build.0 = Release|Any CPU - {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Release|x64.ActiveCfg = Release|Any CPU - {9CC40E07-C24B-4EC8-B05B-56CF986E0477}.Release|x64.Build.0 = Release|Any CPU - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Debug|x64.ActiveCfg = Debug|Any CPU - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Debug|x64.Build.0 = Debug|Any CPU - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Release|Any CPU.Build.0 = Release|Any CPU - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Release|x64.ActiveCfg = Release|Any CPU - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7}.Release|x64.Build.0 = Release|Any CPU - {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Debug|x64.ActiveCfg = Debug|Any CPU - {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Debug|x64.Build.0 = Debug|Any CPU - {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Release|Any CPU.Build.0 = Release|Any CPU - {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Release|x64.ActiveCfg = Release|Any CPU - {A2667784-9BA0-47AC-A327-C0C8F95B26D3}.Release|x64.Build.0 = Release|Any CPU {428CDAF3-957A-4017-82EA-70737F205546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {428CDAF3-957A-4017-82EA-70737F205546}.Debug|Any CPU.Build.0 = Debug|Any CPU {428CDAF3-957A-4017-82EA-70737F205546}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -400,22 +352,6 @@ Global {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Release|Any CPU.Build.0 = Release|Any CPU {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Release|x64.ActiveCfg = Release|Any CPU {85BCA106-4A6F-4BEE-A748-E61A24D12DBD}.Release|x64.Build.0 = Release|Any CPU - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Debug|x64.ActiveCfg = Debug|Any CPU - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Debug|x64.Build.0 = Debug|Any CPU - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Release|Any CPU.Build.0 = Release|Any CPU - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Release|x64.ActiveCfg = Release|Any CPU - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1}.Release|x64.Build.0 = Release|Any CPU - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Debug|x64.ActiveCfg = Debug|Any CPU - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Debug|x64.Build.0 = Debug|Any CPU - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Release|Any CPU.Build.0 = Release|Any CPU - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Release|x64.ActiveCfg = Release|Any CPU - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A}.Release|x64.Build.0 = Release|Any CPU {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Debug|Any CPU.Build.0 = Debug|Any CPU {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -424,14 +360,78 @@ Global {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Release|Any CPU.Build.0 = Release|Any CPU {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Release|x64.ActiveCfg = Release|Any CPU {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD}.Release|x64.Build.0 = Release|Any CPU - {0843A857-87A3-4603-9659-160B2DCE36AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0843A857-87A3-4603-9659-160B2DCE36AC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0843A857-87A3-4603-9659-160B2DCE36AC}.Debug|x64.ActiveCfg = Debug|Any CPU - {0843A857-87A3-4603-9659-160B2DCE36AC}.Debug|x64.Build.0 = Debug|Any CPU - {0843A857-87A3-4603-9659-160B2DCE36AC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0843A857-87A3-4603-9659-160B2DCE36AC}.Release|Any CPU.Build.0 = Release|Any CPU - {0843A857-87A3-4603-9659-160B2DCE36AC}.Release|x64.ActiveCfg = Release|Any CPU - {0843A857-87A3-4603-9659-160B2DCE36AC}.Release|x64.Build.0 = Release|Any CPU + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}.Debug|x64.ActiveCfg = Debug|Any CPU + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}.Debug|x64.Build.0 = Debug|Any CPU + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}.Release|Any CPU.Build.0 = Release|Any CPU + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}.Release|x64.ActiveCfg = Release|Any CPU + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826}.Release|x64.Build.0 = Release|Any CPU + {5A163042-B03A-4063-85FF-22D4C5BB5B90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A163042-B03A-4063-85FF-22D4C5BB5B90}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A163042-B03A-4063-85FF-22D4C5BB5B90}.Debug|x64.ActiveCfg = Debug|Any CPU + {5A163042-B03A-4063-85FF-22D4C5BB5B90}.Debug|x64.Build.0 = Debug|Any CPU + {5A163042-B03A-4063-85FF-22D4C5BB5B90}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A163042-B03A-4063-85FF-22D4C5BB5B90}.Release|Any CPU.Build.0 = Release|Any CPU + {5A163042-B03A-4063-85FF-22D4C5BB5B90}.Release|x64.ActiveCfg = Release|Any CPU + {5A163042-B03A-4063-85FF-22D4C5BB5B90}.Release|x64.Build.0 = Release|Any CPU + {84EFF9E1-6852-458F-8D57-62E3F084EA0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84EFF9E1-6852-458F-8D57-62E3F084EA0F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84EFF9E1-6852-458F-8D57-62E3F084EA0F}.Debug|x64.ActiveCfg = Debug|Any CPU + {84EFF9E1-6852-458F-8D57-62E3F084EA0F}.Debug|x64.Build.0 = Debug|Any CPU + {84EFF9E1-6852-458F-8D57-62E3F084EA0F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84EFF9E1-6852-458F-8D57-62E3F084EA0F}.Release|Any CPU.Build.0 = Release|Any CPU + {84EFF9E1-6852-458F-8D57-62E3F084EA0F}.Release|x64.ActiveCfg = Release|Any CPU + {84EFF9E1-6852-458F-8D57-62E3F084EA0F}.Release|x64.Build.0 = Release|Any CPU + {427822F2-7A20-4E3A-B45C-43CE855003C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {427822F2-7A20-4E3A-B45C-43CE855003C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {427822F2-7A20-4E3A-B45C-43CE855003C1}.Debug|x64.ActiveCfg = Debug|Any CPU + {427822F2-7A20-4E3A-B45C-43CE855003C1}.Debug|x64.Build.0 = Debug|Any CPU + {427822F2-7A20-4E3A-B45C-43CE855003C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {427822F2-7A20-4E3A-B45C-43CE855003C1}.Release|Any CPU.Build.0 = Release|Any CPU + {427822F2-7A20-4E3A-B45C-43CE855003C1}.Release|x64.ActiveCfg = Release|Any CPU + {427822F2-7A20-4E3A-B45C-43CE855003C1}.Release|x64.Build.0 = Release|Any CPU + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98}.Debug|x64.ActiveCfg = Debug|Any CPU + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98}.Debug|x64.Build.0 = Debug|Any CPU + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98}.Release|Any CPU.Build.0 = Release|Any CPU + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98}.Release|x64.ActiveCfg = Release|Any CPU + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98}.Release|x64.Build.0 = Release|Any CPU + {A4DE46BD-1FA4-494B-80DA-6EB370686F17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4DE46BD-1FA4-494B-80DA-6EB370686F17}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4DE46BD-1FA4-494B-80DA-6EB370686F17}.Debug|x64.ActiveCfg = Debug|Any CPU + {A4DE46BD-1FA4-494B-80DA-6EB370686F17}.Debug|x64.Build.0 = Debug|Any CPU + {A4DE46BD-1FA4-494B-80DA-6EB370686F17}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A4DE46BD-1FA4-494B-80DA-6EB370686F17}.Release|Any CPU.Build.0 = Release|Any CPU + {A4DE46BD-1FA4-494B-80DA-6EB370686F17}.Release|x64.ActiveCfg = Release|Any CPU + {A4DE46BD-1FA4-494B-80DA-6EB370686F17}.Release|x64.Build.0 = Release|Any CPU + {7909A736-6C1E-4622-9BE7-37EF0839FA05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7909A736-6C1E-4622-9BE7-37EF0839FA05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7909A736-6C1E-4622-9BE7-37EF0839FA05}.Debug|x64.ActiveCfg = Debug|Any CPU + {7909A736-6C1E-4622-9BE7-37EF0839FA05}.Debug|x64.Build.0 = Debug|Any CPU + {7909A736-6C1E-4622-9BE7-37EF0839FA05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7909A736-6C1E-4622-9BE7-37EF0839FA05}.Release|Any CPU.Build.0 = Release|Any CPU + {7909A736-6C1E-4622-9BE7-37EF0839FA05}.Release|x64.ActiveCfg = Release|Any CPU + {7909A736-6C1E-4622-9BE7-37EF0839FA05}.Release|x64.Build.0 = Release|Any CPU + {71E02AFA-06A0-4527-923C-6666B3D66542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71E02AFA-06A0-4527-923C-6666B3D66542}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71E02AFA-06A0-4527-923C-6666B3D66542}.Debug|x64.ActiveCfg = Debug|Any CPU + {71E02AFA-06A0-4527-923C-6666B3D66542}.Debug|x64.Build.0 = Debug|Any CPU + {71E02AFA-06A0-4527-923C-6666B3D66542}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71E02AFA-06A0-4527-923C-6666B3D66542}.Release|Any CPU.Build.0 = Release|Any CPU + {71E02AFA-06A0-4527-923C-6666B3D66542}.Release|x64.ActiveCfg = Release|Any CPU + {71E02AFA-06A0-4527-923C-6666B3D66542}.Release|x64.Build.0 = Release|Any CPU + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}.Debug|x64.ActiveCfg = Debug|Any CPU + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}.Debug|x64.Build.0 = Debug|Any CPU + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}.Release|Any CPU.Build.0 = Release|Any CPU + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}.Release|x64.ActiveCfg = Release|Any CPU + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -452,7 +452,6 @@ Global {21180442-A6A5-4239-A2AD-33FF5BB80E72} = {42DF7AAC-362C-48F4-B76A-BDEEEFF17CC9} {E33ADF54-4D35-49B7-BDA6-412587CA39FF} = {42DF7AAC-362C-48F4-B76A-BDEEEFF17CC9} {1B44F2E7-28F5-4E88-B8A8-3F336800FD5C} = {FBD326D3-E59C-433E-A88E-14E179E3093D} - {0FF80D58-98D2-43E9-8EAF-7F47C31CB0B6} = {2BE750A5-8AC7-457C-9BB2-6E3D5E2D23B8} {D55A7D3B-9C24-4029-BC03-41B28AD11DB6} = {2BE750A5-8AC7-457C-9BB2-6E3D5E2D23B8} {89B2A693-CD8A-4EA2-9991-2CEE44C4D04B} = {2BE750A5-8AC7-457C-9BB2-6E3D5E2D23B8} {2E172027-1B85-474E-A238-21B2DBDB895F} = {2BE750A5-8AC7-457C-9BB2-6E3D5E2D23B8} @@ -473,24 +472,25 @@ Global {E893C913-98A0-4BB3-A32B-3871BE3C5C53} = {880E8263-AECC-4793-BD28-7CD03650D124} {761C3313-A669-465F-A384-9E118FCE4F89} = {38E6C400-90C0-493E-9266-C1602E229F1B} {13EDB361-AF88-4F89-B4AB-46622BCCBC37} = {38E6C400-90C0-493E-9266-C1602E229F1B} - {647A9FC3-4C21-4CD1-AD6A-FADFEB976E32} = {13EDB361-AF88-4F89-B4AB-46622BCCBC37} {880E8263-AECC-4793-BD28-7CD03650D124} = {38E6C400-90C0-493E-9266-C1602E229F1B} - {7A1493EC-196F-4389-A966-02E526453578} = {880E8263-AECC-4793-BD28-7CD03650D124} {1265AE3C-B5FD-4339-8A7D-BC598E6E1C9F} = {E33ADF54-4D35-49B7-BDA6-412587CA39FF} {1B16DD58-0847-45A7-AF93-53EBFBEDAAE7} = {38E6C400-90C0-493E-9266-C1602E229F1B} {FDF1C618-4C68-485E-A881-4FFF04EDF6E8} = {5DFAF4A2-ECB5-46E4-904D-1EA5F48B2D48} {C056C688-8FFC-42BC-B4EA-EF3808A8A12C} = {59DA3D5F-9E39-4173-8C31-126967CC189F} - {9CC40E07-C24B-4EC8-B05B-56CF986E0477} = {880E8263-AECC-4793-BD28-7CD03650D124} - {313E60D8-23E3-419C-9EC7-7C625DFDC1A7} = {880E8263-AECC-4793-BD28-7CD03650D124} - {A2667784-9BA0-47AC-A327-C0C8F95B26D3} = {880E8263-AECC-4793-BD28-7CD03650D124} {428CDAF3-957A-4017-82EA-70737F205546} = {38E6C400-90C0-493E-9266-C1602E229F1B} {DB93B639-899D-4B2C-AF8A-47B4BC6B3776} = {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} {85BCA106-4A6F-4BEE-A748-E61A24D12DBD} = {38E6C400-90C0-493E-9266-C1602E229F1B} {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} = {38E6C400-90C0-493E-9266-C1602E229F1B} - {2A7F4ACC-E30D-4124-BE1F-B3B5C9DF7BE1} = {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} - {17CD5E42-C589-47CA-8FF2-7B6D3B70131A} = {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} {A5C1EF6B-A3B5-4D0C-8373-F854EE7EF4AD} = {38E6C400-90C0-493E-9266-C1602E229F1B} - {0843A857-87A3-4603-9659-160B2DCE36AC} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {B29ABF5D-AFA8-4480-B74E-3ACB6FAAA826} = {13EDB361-AF88-4F89-B4AB-46622BCCBC37} + {5A163042-B03A-4063-85FF-22D4C5BB5B90} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {84EFF9E1-6852-458F-8D57-62E3F084EA0F} = {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} + {427822F2-7A20-4E3A-B45C-43CE855003C1} = {9EEE31DA-3165-4CB3-AAE9-27CC3A4DE669} + {99067BDF-2C6A-47F8-913D-3FF9F2A69F98} = {880E8263-AECC-4793-BD28-7CD03650D124} + {A4DE46BD-1FA4-494B-80DA-6EB370686F17} = {880E8263-AECC-4793-BD28-7CD03650D124} + {7909A736-6C1E-4622-9BE7-37EF0839FA05} = {880E8263-AECC-4793-BD28-7CD03650D124} + {71E02AFA-06A0-4527-923C-6666B3D66542} = {880E8263-AECC-4793-BD28-7CD03650D124} + {1A86AE9B-A57D-43D2-9E8C-5ED0C1E6041C} = {2BE750A5-8AC7-457C-9BB2-6E3D5E2D23B8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03} diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/JsonConfigurationParser.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/JsonConfigurationParser.cs index e3d2f7295..b23f71761 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/JsonConfigurationParser.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/Internal/Parser/JsonConfigurationParser.cs @@ -49,7 +49,7 @@ private void VisitElement(JsonElement element) if (isEmpty && _paths.Count > 0) { - _data[_paths.Peek()] = null; + _data[_paths.Peek()] = ""; } } diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs index 52997fba0..f009c3c8f 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Internal/ServiceCollectionRepositoryExtensions.cs @@ -49,7 +49,7 @@ private static string[] GetKeys(Type entityType) aggregateRoot = (IAggregateRoot)Activator.CreateInstance(entityType, constructorInfo.IsPrivate)!; } - catch (Exception ex) + catch (Exception) { throw new ArgumentNullException("The entity needs to have an empty constructor"); } diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs index 11096f1cf..8b5de93a6 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs @@ -51,7 +51,7 @@ public override Task CommitAsync(CancellationToken cancellationToken = default) public override Task FindAsync(object?[]? keyValues, CancellationToken cancellationToken) { if (keyValues == null) - return null; + return Task.FromResult(default(TEntity?)); var keys = GetKeys(typeof(TEntity)); Dictionary fields = new(); diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs index 72191684a..811652440 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccClientTest.cs @@ -37,9 +37,8 @@ public void Initialize() [DataRow("Test", "Default", "DccTest", "Brand")] public async Task TestGetRawAsync(string environment, string cluster, string appId, string configObject) { - - Action valueChanged = delegate (string val) { }; - _client.Setup(client => client.GetAsync(It.IsAny(), valueChanged).Result).Returns(() => null).Verifiable(); + Action valueChanged = delegate (string? val) { }; + _client.Setup(client => client.GetAsync(It.IsAny(), valueChanged).Result).Returns(() => null).Verifiable(); var client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); await Assert.ThrowsExceptionAsync(async () => await client.GetRawAsync(environment, cluster, appId, configObject, valueChanged), "configObject invalid" @@ -175,14 +174,14 @@ public async Task GetAsyncByJson(string environment, string cluster, string appI _trigger.Action = action; }); client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); - ret = await client.GetAsync(environment, cluster, appId, configObject, null); + ret = await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); Assert.IsNotNull(ret); Assert.IsTrue(ret.Id == brand.Id && ret.Name == brand.Name); _trigger.Execute(); - ret = await client.GetAsync(environment, cluster, appId, configObject, null); + ret = await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); Assert.IsTrue(ret.Id == newBrand.Id && ret.Name == "Masa"); - _client.Setup(client => client.GetAsync(It.IsAny(), null).Result).Returns(() => new PublishRelease() + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() { ConfigFormat = ConfigFormats.Json, Content = brand.Serialize(_jsonSerializerOptions) @@ -201,7 +200,7 @@ public async Task GetAsyncByJson(string environment, string cluster, string appI client = new ConfigurationAPIClient(_serviceProvider, _client.Object, _jsonSerializerOptions, _dccSectionOptions, null); await Assert.ThrowsExceptionAsync(async () => { - await client.GetAsync(environment, cluster, appId, configObject, null); + await client.GetAsync(environment, cluster, appId, configObject, It.IsAny>()); }); } @@ -316,7 +315,7 @@ public async Task GetDynamicAsyncByJson(string environment, string cluster, stri Assert.IsNotNull(ret); Assert.IsTrue(ret.Id == newBrand.Id.ToString() && ret.Name == newBrand.Name); - _client.Setup(client => client.GetAsync(It.IsAny(), null).Result).Returns(() => new PublishRelease() + _client.Setup(client => client.GetAsync(It.IsAny(), It.IsAny>()).Result).Returns(() => new PublishRelease() { ConfigFormat = ConfigFormats.Json, Content = brand.Serialize(_jsonSerializerOptions) diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs index 5c2530483..75f9073c7 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccManageTest.cs @@ -10,7 +10,6 @@ public class DccManageTest private DccSectionOptions _dccSectionOptions; private JsonSerializerOptions _jsonSerializerOptions; private Mock _callerProvider; - private Mock _httpMessageHandler; [TestInitialize] public void Initialize() @@ -129,7 +128,7 @@ public void GetCluster(string cluster, string outCluster) public void GetAppid(string appId, string outAppid) { var api = new CustomConfigurationAPI(_dccSectionOptions, null); - Assert.IsTrue(api.GetAppid(appId) == outAppid); + Assert.IsTrue(api.GetAppId(appId) == outAppid); } [DataTestMethod] @@ -151,13 +150,13 @@ public CustomConfigurationAPI(DccSectionOptions defaultSectionOption, List base.GetSecret(appId); + public new string GetSecret(string appId) => base.GetSecret(appId); - public string GetEnvironment(string environment) => base.GetEnvironment(environment); + public new string GetEnvironment(string environment) => base.GetEnvironment(environment); - public string GetCluster(string cluster) => base.GetCluster(cluster); + public new string GetCluster(string cluster) => base.GetCluster(cluster); - public string GetAppid(string appId) => base.GetAppId(appId); + public new string GetAppId(string appId) => base.GetAppId(appId); - public string GetConfigObject(string configObject) => base.GetConfigObject(configObject); + public new string GetConfigObject(string configObject) => base.GetConfigObject(configObject); } diff --git a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs index d787ac0c2..27164dd0c 100644 --- a/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs +++ b/test/MASA.Contrib.BasicAbility.Dcc.Tests/DccTest.cs @@ -46,9 +46,9 @@ public void TestErrorDccSection() [TestMethod] public void TestTryAddConfigurationAPIClient() { - _memoryCacheClientFactory.Setup(factory => factory.CreateClient(DEFAULT_CLIENT_NAME)).Returns(() => null).Verifiable(); + _memoryCacheClientFactory.Setup(factory => factory.CreateClient(DEFAULT_CLIENT_NAME)).Returns(() => null!).Verifiable(); _services.AddSingleton(serviceProvider => _memoryCacheClientFactory.Object); - MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), new List(), null); + MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), new List(), null!); Assert.IsTrue(_services.Count(service => service.ServiceType == typeof(IConfigurationAPIClient) && service.Lifetime == ServiceLifetime.Singleton) == 1); Assert.ThrowsException(() => { @@ -58,7 +58,7 @@ public void TestTryAddConfigurationAPIClient() _services = new ServiceCollection(); _memoryCacheClientFactory .Setup(factory => factory.CreateClient(DEFAULT_CLIENT_NAME)) - .Returns(() => new MemoryCacheClient(_memoryCache.Object, _distributedCacheClient.Object, Utils.Caching.Core.Models.SubscribeKeyTypes.ValueTypeFullNameAndKey)) + .Returns(() => new MemoryCacheClient(_memoryCache.Object, _distributedCacheClient.Object, SubscribeKeyTypes.ValueTypeFullNameAndKey)) .Verifiable(); _services.AddSingleton(serviceProvider => _memoryCacheClientFactory.Object); MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), new List(), new JsonSerializerOptions() @@ -75,8 +75,8 @@ public void TestTryAddConfigurationAPIClient() .Returns(() => new MemoryCacheClient(_memoryCache.Object, _distributedCacheClient.Object, Utils.Caching.Core.Models.SubscribeKeyTypes.ValueTypeFullNameAndKey)) .Verifiable(); _services.AddSingleton(serviceProvider => _memoryCacheClientFactory.Object); - MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), null, null); - MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), null, null); + MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), new List(), _jsonSerializerOptions); + MasaConfigurationExtensions.TryAddConfigurationAPIClient(_services, new DccSectionOptions(), new List(), _jsonSerializerOptions); clienties = _services.BuildServiceProvider().GetServices(); Assert.IsTrue(clienties.Count() == 1); } @@ -106,7 +106,7 @@ public void TestUseDCCAndErrorSection() [TestMethod] public void TestUseDCCAndNullDccConfigurationOption() { - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => null, option => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => null!, option => { option.AppId = "Test"; option.Environment = "Test"; @@ -115,7 +115,7 @@ public void TestUseDCCAndNullDccConfigurationOption() Initialize(); - Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, null, option => + Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, null!, option => { option.AppId = "Test"; option.Environment = "Test"; @@ -127,7 +127,7 @@ public void TestUseDCCAndNullDccConfigurationOption() public void TestCustomCaller() { Mock configurationAPIClient = new(); - configurationAPIClient.Setup(client => client.GetRawAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), null).Result).Returns(() => ("", ConfigurationTypes.Text)); + configurationAPIClient.Setup(client => client.GetRawAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()).Result).Returns(() => ("", ConfigurationTypes.Text)); _services.AddSingleton(configurationAPIClient.Object); _masaConfigurationBuilder.Object.UseDcc(_services, () => new DccConfigurationOptions() { @@ -175,7 +175,7 @@ public void TestUseDCCAndEmptyDccServiceAddress() { ManageServiceAddress = "", }; - }, null, null), "DccServiceAddress"); + }, null!, null), "DccServiceAddress"); } [TestMethod] @@ -188,10 +188,10 @@ public void TestUseDCCAndErrorDccService() ManageServiceAddress = "https://github.com", RedisOptions = new Utils.Caching.Redis.Models.RedisConfigurationOptions() { - Servers = null + Servers = null! } }; - }, null, null), "Servers"); + }, null!, null), "Servers"); _services = new ServiceCollection(); Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => @@ -204,7 +204,7 @@ public void TestUseDCCAndErrorDccService() Servers = new List() } }; - }, null, null), "Servers"); + }, null!, null), "Servers"); _services = new ServiceCollection(); Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => @@ -224,7 +224,7 @@ public void TestUseDCCAndErrorDccService() } } }; - }, null, null), "Servers"); + }, null!, null), "Servers"); _services = new ServiceCollection(); Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => @@ -244,7 +244,7 @@ public void TestUseDCCAndErrorDccService() } } }; - }, null, null), "Servers"); + }, null!, null), "Servers"); } [TestMethod] @@ -267,7 +267,7 @@ public void TestUseDCCAndErrorDefaultSectionOption() } } }; - }, null, null), "defaultSectionOptions"); + }, null!, null), "defaultSectionOptions"); _services = new ServiceCollection(); Assert.ThrowsException(() => _masaConfigurationBuilder.Object.UseDcc(_services, () => @@ -313,7 +313,7 @@ public void TestUseDCCAndErrorDefaultSectionOption() }, option => { option.AppId = "Test"; - option.ConfigObjects = null; + option.ConfigObjects = null!; }, null), "ConfigObjects cannot be empty"); _services = new ServiceCollection(); diff --git a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/ErrorKafkaOptions.cs b/test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/ErrorKafkaOptions.cs similarity index 77% rename from test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/ErrorKafkaOptions.cs rename to test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/ErrorKafkaOptions.cs index 52750046a..1ab0da584 100644 --- a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/ErrorKafkaOptions.cs +++ b/test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/ErrorKafkaOptions.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Configuration.ErrorSectionAutoMapTests; +namespace MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests; public class ErrorKafkaOptions : KafkaOptions { diff --git a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/KafkaOptions.cs b/test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/KafkaOptions.cs similarity index 82% rename from test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/KafkaOptions.cs rename to test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/KafkaOptions.cs index 3cf9ec2a2..a2f1f13ee 100644 --- a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/KafkaOptions.cs +++ b/test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/KafkaOptions.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Configuration.ErrorSectionAutoMapTests; +namespace MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests; public class KafkaOptions : MasaConfigurationOptions { diff --git a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj b/test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests.csproj similarity index 100% rename from test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/MASA.Contrib.Configuration.ErrorSectionAutoMapTests.csproj rename to test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests.csproj diff --git a/test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/_Imports.cs b/test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/_Imports.cs similarity index 100% rename from test/MASA.Contrib.Configuration.ErrorSectionAutoMapTests/_Imports.cs rename to test/MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests/_Imports.cs diff --git a/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests.csproj similarity index 100% rename from test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests.csproj rename to test/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests.csproj diff --git a/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MountSectionRedisOptions.cs b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests/MountSectionRedisOptions.cs similarity index 98% rename from test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MountSectionRedisOptions.cs rename to test/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests/MountSectionRedisOptions.cs index 3fc6f8f89..22de5854b 100644 --- a/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/MountSectionRedisOptions.cs +++ b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests/MountSectionRedisOptions.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Configuration.MountErrorSectionAutoMapTests; +namespace MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests; public class MountSectionRedisOptions : MasaConfigurationOptions { diff --git a/test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/_Imports.cs b/test/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests/_Imports.cs similarity index 100% rename from test/MASA.Contrib.Configuration.MountErrorSectionAutoMapTests/_Imports.cs rename to test/MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests/_Imports.cs diff --git a/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs b/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs index 4c9f73154..fe62c475c 100644 --- a/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs +++ b/test/MASA.Contrib.Configuration.Tests/ConfigurationTest.cs @@ -1,6 +1,3 @@ -using MASA.Contrib.Configuration.ErrorSectionAutoMapTests; -using MASA.Contrib.Configuration.MountErrorSectionAutoMapTests; - namespace MASA.Contrib.Configuration.Tests; [TestClass] @@ -18,7 +15,7 @@ public void Initialize() public void TestAddSection() { var masaConfigurationBuilder = new MasaConfigurationBuilder(_configurationBuilder); - Assert.ThrowsException(() => masaConfigurationBuilder.AddSection(null)); + Assert.ThrowsException(() => masaConfigurationBuilder.AddSection(null!)); Assert.ThrowsException(() => masaConfigurationBuilder.AddSection(new ConfigurationBuilder())); diff --git a/test/MASA.Contrib.Configuration.Tests/MASA.Contrib.Configuration.Tests.csproj b/test/MASA.Contrib.Configuration.Tests/MASA.Contrib.Configuration.Tests.csproj index b45547eb3..318fc49f0 100644 --- a/test/MASA.Contrib.Configuration.Tests/MASA.Contrib.Configuration.Tests.csproj +++ b/test/MASA.Contrib.Configuration.Tests/MASA.Contrib.Configuration.Tests.csproj @@ -21,8 +21,8 @@ - - + + diff --git a/test/MASA.Contrib.Configuration.Tests/_Imports.cs b/test/MASA.Contrib.Configuration.Tests/_Imports.cs index 96c264dae..12d9cc8ba 100644 --- a/test/MASA.Contrib.Configuration.Tests/_Imports.cs +++ b/test/MASA.Contrib.Configuration.Tests/_Imports.cs @@ -1,4 +1,6 @@ global using MASA.BuildingBlocks.Configuration; +global using MASA.Contrib.Configuration.ErrorSectionAutoMap.Tests; +global using MASA.Contrib.Configuration.MountErrorSectionAutoMap.Tests; global using MASA.Contrib.Configuration.Tests.Config; global using Microsoft.AspNetCore.Builder; global using Microsoft.Extensions.Configuration; diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests.csproj similarity index 100% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests.csproj rename to test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests.csproj diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/Students.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests/Students.cs similarity index 90% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/Students.cs rename to test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests/Students.cs index 490334645..d9363e62d 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/Students.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests/Students.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests; +namespace MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests; public class Students : AggregateRoot { diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests/_Imports.cs similarity index 100% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/_Imports.cs rename to test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests/_Imports.cs diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/Courses.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/Courses.cs index cca8d48e7..45965f525 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/Courses.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/Courses.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests; +namespace MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFind.Tests; public class Courses : AggregateRoot { diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFind.Tests.csproj similarity index 100% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests.csproj rename to test/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests/MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFind.Tests.csproj diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/Entities/User.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/Entities/User.cs similarity index 91% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/Entities/User.cs rename to test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/Entities/User.cs index d4f5399ee..915381728 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/Entities/User.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/Entities/User.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Entities; +namespace MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests.Entities; public class User : AggregateRoot { diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests.csproj similarity index 100% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.csproj rename to test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests.csproj diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/Repositories/IUserRepository.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/Repositories/IUserRepository.cs similarity index 55% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/Repositories/IUserRepository.cs rename to test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/Repositories/IUserRepository.cs index ecdd10afe..83e3677da 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/Repositories/IUserRepository.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/Repositories/IUserRepository.cs @@ -1,4 +1,6 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Repositories; +using MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests.Entities; + +namespace MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests.Repositories; public interface IUserRepository : IRepository { diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/_Imports.cs similarity index 58% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/_Imports.cs rename to test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/_Imports.cs index 2348cb021..5db641dcf 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository/_Imports.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests/_Imports.cs @@ -1,3 +1,2 @@ global using MASA.BuildingBlocks.DDD.Domain.Entities; global using MASA.BuildingBlocks.DDD.Domain.Repositories; -global using MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Entities; diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/Hobbies.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests/Hobbies.cs similarity index 58% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/Hobbies.cs rename to test/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests/Hobbies.cs index 27a0c0427..f95e10bc4 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/Hobbies.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests/Hobbies.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Entities; +namespace MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests; public class Hobbies : AggregateRoot { @@ -6,11 +6,11 @@ public class Hobbies : AggregateRoot private Hobbies() { - this.Id = Guid.NewGuid(); + Id = Guid.NewGuid(); } public Hobbies(string name) : this() { - this.Name = name; + Name = name; } } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests.csproj similarity index 100% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests.csproj rename to test/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests.csproj diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests/_Imports.cs similarity index 100% rename from test/MASA.Contrib.DDD.Domain.Repository.EF.EntityTests/_Imports.cs rename to test/MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests/_Imports.cs diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/BaseRepositoryTest.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/BaseRepositoryTest.cs index b09128716..1778f8154 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/BaseRepositoryTest.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/BaseRepositoryTest.cs @@ -26,7 +26,7 @@ public void TestNullServices() { Assert.ThrowsException(() => { - _dispatcherOptions.Setup(options => options.Services).Returns(() => null); + _dispatcherOptions.Setup(options => options.Services).Returns(() => null!); var options = _dispatcherOptions.Object.UseRepository(); }); } @@ -60,7 +60,7 @@ public void TestNullAssembly() Assert.ThrowsException(() => { - _dispatcherOptions.Object.UseRepository(null); + _dispatcherOptions.Object.UseRepository(null!); }); } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Entities/Address.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Entities/Address.cs index b40622c72..27f677f52 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Entities/Address.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/Domain/Entities/Address.cs @@ -1,24 +1,23 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Entities +namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Entities; + +public class Address : ValueObject { - public class Address : ValueObject - { - public string Street { get; set; } + public string Street { get; set; } - public string City { get; set; } + public string City { get; set; } - public string State { get; set; } + public string State { get; set; } - public string Country { get; set; } + public string Country { get; set; } - public string ZipCode { get; set; } + public string ZipCode { get; set; } - protected override IEnumerable GetEqualityValues() - { - yield return Street; - yield return City; - yield return State; - yield return Country; - yield return ZipCode; - } + protected override IEnumerable GetEqualityValues() + { + yield return Street; + yield return City; + yield return State; + yield return Country; + yield return ZipCode; } } diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj index 83b835a62..9f271c9aa 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/MASA.Contrib.DDD.Domain.Repository.EF.Tests.csproj @@ -22,10 +22,10 @@ - - - - + + + + diff --git a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs index 0fb87a53e..0d939826d 100644 --- a/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs +++ b/test/MASA.Contrib.DDD.Domain.Repository.EF.Tests/_Imports.cs @@ -4,9 +4,10 @@ global using MASA.BuildingBlocks.DDD.Domain.Repositories; global using MASA.BuildingBlocks.DDD.Domain.Values; global using MASA.BuildingBlocks.Dispatcher.Events; -global using MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFindTests; -global using MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysTests; -global using MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Repositories; +global using MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeys.Tests; +global using MASA.Contrib.DDD.Domain.Repository.EF.CombinedKeysNoFind.Tests; +global using MASA.Contrib.DDD.Domain.Repository.EF.CustomRepository.Tests.Repositories; +global using MASA.Contrib.DDD.Domain.Repository.EF.Entity.Tests; global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Entities; global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Domain.Repositories; global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure; @@ -19,3 +20,4 @@ global using System.Collections.Generic; global using System.Linq; global using System.Reflection; + diff --git a/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs b/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs index c82972410..cad4e8dd1 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs +++ b/test/MASA.Contrib.DDD.Domain.Tests/DomainEventBusTest.cs @@ -48,7 +48,7 @@ public async Task TestPublishDomainEventAsync() _eventBus.Verify(eventBus => eventBus.PublishAsync(domainEvent), Times.Once, "PublishAsync is executed multiple times"); _integrationEventBus.Verify(integrationEventBus => integrationEventBus.PublishAsync(domainEvent), Times.Never, "integrationEventBus should not be executed"); - Assert.IsTrue(domainEvent.UnitOfWork.Equals(_uoW.Object)); + Assert.IsTrue(domainEvent.UnitOfWork!.Equals(_uoW.Object)); } [TestMethod] @@ -80,7 +80,7 @@ public async Task TestPublishDomainCommandAsync() Name = "Jim" }; userRepository.Setup(repository => repository.AddAsync(It.IsAny(), CancellationToken.None)).Verifiable(); - domainEvent.UnitOfWork.CommitAsync(); + domainEvent.UnitOfWork!.CommitAsync(); }); var @command = new CreateProductDomainCommand() @@ -147,7 +147,7 @@ public void TestNotUseIntegrationEventBus() [TestMethod] public void TestNullAssembly() { - Assert.ThrowsException(() => _dispatcherOptions.Value.Assemblies = null); + Assert.ThrowsException(() => _dispatcherOptions.Value.Assemblies = null!); } [TestMethod] diff --git a/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj b/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj index e4486a855..811911766 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj +++ b/test/MASA.Contrib.DDD.Domain.Tests/MASA.Contrib.DDD.Domain.Tests.csproj @@ -22,7 +22,7 @@ - + diff --git a/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs b/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs index 3e24c3e5e..6d9c61865 100644 --- a/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs +++ b/test/MASA.Contrib.DDD.Domain.Tests/_Imports.cs @@ -6,10 +6,10 @@ global using MASA.Contrib.DDD.Domain.Events; global using MASA.Contrib.DDD.Domain.Tests.Events; global using MASA.Contrib.DDD.Domain.Tests.Services; -global using MASA.Contribs.DDD.Domain.Entities; +global using MASA.Contribs.DDD.Domain.Entities.Tests; global using Microsoft.Extensions.DependencyInjection; -global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Options; global using Microsoft.VisualStudio.TestTools.UnitTesting; global using Moq; global using System.Reflection; + diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Courses.cs b/test/MASA.Contrib.Data.Contracts.EF.Tests/Domain/Entities/Courses.cs similarity index 68% rename from test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Courses.cs rename to test/MASA.Contrib.Data.Contracts.EF.Tests/Domain/Entities/Courses.cs index 158e8ceb3..2b6039096 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Courses.cs +++ b/test/MASA.Contrib.Data.Contracts.EF.Tests/Domain/Entities/Courses.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Data.Contracts.EF.Test.Domain.Entities; +namespace MASA.Contrib.Data.Contracts.EF.Tests.Domain.Entities; public class Courses : AggregateRoot { @@ -8,8 +8,6 @@ public Courses() IsDeleted = false; } - public Guid Id { get; init; } - public string Name { get; set; } public bool IsDeleted { get; set; } diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Students.cs b/test/MASA.Contrib.Data.Contracts.EF.Tests/Domain/Entities/Students.cs similarity index 60% rename from test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Students.cs rename to test/MASA.Contrib.Data.Contracts.EF.Tests/Domain/Entities/Students.cs index c99587da6..968c5de7c 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/Domain/Entities/Students.cs +++ b/test/MASA.Contrib.Data.Contracts.EF.Tests/Domain/Entities/Students.cs @@ -1,11 +1,11 @@ -namespace MASA.Contrib.Data.Contracts.EF.Test.Domain.Entities; +namespace MASA.Contrib.Data.Contracts.EF.Tests.Domain.Entities; public class Students : AuditAggregateRoot { public Students() { - this.Id = Guid.NewGuid(); - this.RegisterTime = DateTime.UtcNow; + Id = Guid.NewGuid(); + RegisterTime = DateTime.UtcNow; } public string Name { get; set; } diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/Infrastructure/CustomDbContext.cs b/test/MASA.Contrib.Data.Contracts.EF.Tests/Infrastructure/CustomDbContext.cs similarity index 66% rename from test/MASA.Contrib.Data.Contracts.EF.Test/Infrastructure/CustomDbContext.cs rename to test/MASA.Contrib.Data.Contracts.EF.Tests/Infrastructure/CustomDbContext.cs index cff5509cc..46299964b 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/Infrastructure/CustomDbContext.cs +++ b/test/MASA.Contrib.Data.Contracts.EF.Tests/Infrastructure/CustomDbContext.cs @@ -1,4 +1,6 @@ -namespace MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure; +using MASA.Contrib.Data.Contracts.EF.Tests.Domain.Entities; + +namespace MASA.Contrib.Data.Contracts.EF.Tests.Infrastructure; public class CustomDbContext : MasaDbContext { diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj b/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj similarity index 100% rename from test/MASA.Contrib.Data.Contracts.EF.Test/MASA.Contrib.Data.Contracts.EF.Test.csproj rename to test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs b/test/MASA.Contrib.Data.Contracts.EF.Tests/SoftDeleteTest.cs similarity index 95% rename from test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs rename to test/MASA.Contrib.Data.Contracts.EF.Tests/SoftDeleteTest.cs index 53a7c7e05..39f797c4d 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/SoftDeleteTest.cs +++ b/test/MASA.Contrib.Data.Contracts.EF.Tests/SoftDeleteTest.cs @@ -1,4 +1,7 @@ -namespace MASA.Contrib.Data.Contracts.EF.Test; +using MASA.Contrib.Data.Contracts.EF.Tests.Domain.Entities; +using MASA.Contrib.Data.Contracts.EF.Tests.Infrastructure; + +namespace MASA.Contrib.Data.Contracts.EF.Tests; [TestClass] public class SoftDeleteTest : IDisposable diff --git a/test/MASA.Contrib.Data.Contracts.EF.Test/_Imports.cs b/test/MASA.Contrib.Data.Contracts.EF.Tests/_Imports.cs similarity index 75% rename from test/MASA.Contrib.Data.Contracts.EF.Test/_Imports.cs rename to test/MASA.Contrib.Data.Contracts.EF.Tests/_Imports.cs index d269e5e5b..13d3abe9d 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Test/_Imports.cs +++ b/test/MASA.Contrib.Data.Contracts.EF.Tests/_Imports.cs @@ -1,8 +1,7 @@ global using MASA.BuildingBlocks.Data.UoW; global using MASA.BuildingBlocks.DDD.Domain.Entities; global using MASA.BuildingBlocks.DDD.Domain.Entities.Auditing; -global using MASA.Contrib.Data.Contracts.EF.Test.Domain.Entities; -global using MASA.Contrib.DDD.Domain.Repository.EF.Tests.Infrastructure; +global using MASA.Contrib.Data.Contracts.EF.Tests.Domain.Entities; global using MASA.Utils.Data.EntityFrameworkCore; global using Microsoft.Data.Sqlite; global using Microsoft.EntityFrameworkCore; diff --git a/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs b/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs index 4c38d2649..cf5fe487b 100644 --- a/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs +++ b/test/MASA.Contrib.Data.UoW.EF.Tests/TestUnitOfWork.cs @@ -52,7 +52,7 @@ public void TestAddMultUoW() public void TestTransaction() { Mock uoW = new(); - Assert.IsTrue(new Transaction(uoW.Object).UnitOfWork.Equals(uoW.Object)); + Assert.IsTrue(new Transaction(uoW.Object).UnitOfWork!.Equals(uoW.Object)); } [TestMethod] diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Benchmarks.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Benchmarks.cs similarity index 96% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Benchmarks.cs rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Benchmarks.cs index b65e87930..633736ad6 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Benchmarks.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Benchmarks.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest; +namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests; [SimpleJob(RunStrategy.ColdStart, RuntimeMoniker.Net60, targetCount: 100)] [MinColumn, MaxColumn, MeanColumn, MedianColumn] diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/EventHandlers/CouponHandler.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/EventHandlers/CouponHandler.cs similarity index 89% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/EventHandlers/CouponHandler.cs rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/EventHandlers/CouponHandler.cs index 691667eec..f02d16684 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/EventHandlers/CouponHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/EventHandlers/CouponHandler.cs @@ -1,4 +1,6 @@ -namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.Extensions.EventHandlers; +using MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.Events; + +namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.EventHandlers; public class CouponHandler { diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/EventHandlers/NoticeHandler.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/EventHandlers/NoticeHandler.cs similarity index 91% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/EventHandlers/NoticeHandler.cs rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/EventHandlers/NoticeHandler.cs index ea115ab65..056ac0809 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/EventHandlers/NoticeHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/EventHandlers/NoticeHandler.cs @@ -1,4 +1,6 @@ -namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.Extensions.EventHandlers; +using MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.Events; + +namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.EventHandlers; public class SendCouponHandler : ISagaEventHandler { diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Events/ForgetPasswordEvent.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/ForgetPasswordEvent.cs similarity index 60% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Events/ForgetPasswordEvent.cs rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/ForgetPasswordEvent.cs index d14180190..abe93678a 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Events/ForgetPasswordEvent.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/ForgetPasswordEvent.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.Extensions.Events; +namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.Events; public record ForgetPasswordEvent : Event { diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Events/RegisterUserEvent.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/RegisterUserEvent.cs similarity index 59% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Events/RegisterUserEvent.cs rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/RegisterUserEvent.cs index 10adbe699..49353fbaf 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Events/RegisterUserEvent.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/RegisterUserEvent.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.Extensions.Events; +namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.Events; public record RegisterUserEvent : Event { diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Middleware/LoggingMiddleware.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Middleware/LoggingMiddleware.cs similarity index 85% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Middleware/LoggingMiddleware.cs rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Middleware/LoggingMiddleware.cs index 35b8394f6..f2e28eac5 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Extensions/Middleware/LoggingMiddleware.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Middleware/LoggingMiddleware.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.Extensions.Middleware; +namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.Middleware; public class LoggingMiddleware : IMiddleware where TEvent : notnull, IEvent { diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.csproj similarity index 100% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.csproj rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.csproj diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Program.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Program.cs similarity index 83% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Program.cs rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Program.cs index 0ec3ffd4c..0ec5f1cb3 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/Program.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Program.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest; +namespace MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests; class Program { diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/_Imports.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/_Imports.cs similarity index 73% rename from test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/_Imports.cs rename to test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/_Imports.cs index 4e7ce08eb..5276b15ee 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest/_Imports.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/_Imports.cs @@ -5,10 +5,11 @@ global using BenchmarkDotNet.Running; global using BenchmarkDotNet.Validators; global using MASA.BuildingBlocks.Dispatcher.Events; -global using MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.Extensions.EventHandlers; -global using MASA.Contrib.Dispatcher.Events.BenchmarkDotnetTest.Extensions.Events; +global using MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.EventHandlers; +global using MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests.Extensions.Events; global using MASA.Contrib.Dispatcher.Events.Enums; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.Logging; global using System; global using System.Threading.Tasks; + diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/AssemblyResolutionTests.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/AssemblyResolutionTests.cs index d0a8c6f1a..c9b51ff42 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/AssemblyResolutionTests.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/AssemblyResolutionTests.cs @@ -33,7 +33,7 @@ public void TestAddNullAssembly() services.AddTransient(typeof(IMiddleware<>), typeof(LoggingMiddleware<>)); Assert.ThrowsException(() => { - services.AddEventBus(options => options.Assemblies = null); + services.AddEventBus(options => options.Assemblies = null!); }); } @@ -57,7 +57,7 @@ public void TestEventBusByAddNullAssembly() services.AddTransient(typeof(IMiddleware<>), typeof(LoggingMiddleware<>)); Assert.ThrowsException(() => { - services.AddTestEventBus(ServiceLifetime.Scoped, options => options.Assemblies = null); + services.AddTestEventBus(ServiceLifetime.Scoped, options => options.Assemblies = null!); }); } @@ -116,7 +116,7 @@ public void TestAddMultEventBus() [TestMethod] public void TestUseEventBusAndNullServices() { - var options = new DispatcherOptions(null); + var options = new DispatcherOptions(null!); Assert.ThrowsException(() => options.UseEventBus()); } } diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/ChoreTest.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/ChoreTest.cs index 6ed94ada0..6a28ce658 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/ChoreTest.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/ChoreTest.cs @@ -1,4 +1,4 @@ -namespace MASA.Contrib.Dispatcher.Events.Tests; +namespace MASA.Contrib.Dispatcher.Events.Tests; [TestClass] public class ChoreTest : TestBase @@ -6,7 +6,7 @@ public class ChoreTest : TestBase private readonly IEventBus _eventBus; public ChoreTest() { - _eventBus = _serviceProvider.GetService(); + _eventBus = _serviceProvider.GetRequiredService(); } [DataTestMethod] @@ -99,4 +99,4 @@ public void TestDispatchHandlerConstructor() Assert.IsTrue(dispatchHandler.RetryTimes.Equals(5)); Assert.IsTrue(dispatchHandler.IsCancel.Equals(true)); } -} \ No newline at end of file +} diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs index b6f500a11..52714f63a 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs @@ -6,7 +6,7 @@ public class FeaturesTest : TestBase private readonly IEventBus _eventBus; public FeaturesTest() : base() { - _eventBus = _serviceProvider.GetService(); + _eventBus = _serviceProvider.GetRequiredService(); } [TestMethod] @@ -77,8 +77,8 @@ public async Task TestCorrectEventBus() [TestMethod] public async Task TestNullEvent() { - AddShoppingCartEvent @event = null; - await Assert.ThrowsExceptionAsync(async () => await _eventBus.PublishAsync(@event)); + AddShoppingCartEvent? @event = null; + await Assert.ThrowsExceptionAsync(async () => await _eventBus.PublishAsync(@event!)); } [DataTestMethod] @@ -146,7 +146,7 @@ public Task TestOrderLessThenZero() { ResetMemoryEventBus(typeof(FeaturesTest).Assembly); } - catch (Exception ex) + catch (Exception) { } diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/SagaTest.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/SagaTest.cs index 1880990d3..ce8fee8b2 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/SagaTest.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/SagaTest.cs @@ -6,7 +6,7 @@ public class SagaTest : TestBase private readonly IEventBus _eventBus; public SagaTest() : base() { - _eventBus = _serviceProvider.GetService(); + _eventBus = _serviceProvider.GetRequiredService(); } [DataTestMethod] @@ -30,7 +30,7 @@ public async Task TestExecuteAbnormalExit(string orderId, string orderState, str [DataRow("jordan", "change password notcices @", 0)] public async Task TestLastCancelError(string account, string content, int isError) { - ResetMemoryEventBus(false, null); + ResetMemoryEventBus(false, null!); ChangePasswordEvent @event = new ChangePasswordEvent() { Account = account, @@ -89,7 +89,7 @@ await Assert.ThrowsExceptionAsync(async () => [TestMethod] public async Task TestMultiOrderBySaga() { - IEventBus eventBus = null; + IEventBus? eventBus = null; Assert.ThrowsException(() => { ResetMemoryEventBus(false, typeof(SagaTest).Assembly, typeof(EditCategoryEvent).Assembly); @@ -104,13 +104,13 @@ public async Task TestMultiOrderBySaga() { await eventBus.PublishAsync(@event); } - ResetMemoryEventBus(false, null); + ResetMemoryEventBus(false, null!); } [TestMethod] public async Task TestLessThenZeroBySaga() { - IEventBus eventBus = null; + IEventBus? eventBus = null; Assert.ThrowsException(() => { ResetMemoryEventBus(false, typeof(EditGoodsEvent).Assembly); @@ -126,6 +126,6 @@ public async Task TestLessThenZeroBySaga() { await eventBus.PublishAsync(@event); } - ResetMemoryEventBus(false, null); + ResetMemoryEventBus(false, null!); } } diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/TestBase.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/TestBase.cs index 4d013922c..551056db7 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/TestBase.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/TestBase.cs @@ -12,9 +12,9 @@ public TestBase() : this(null) } - public TestBase(Func func = null) => ResetMemoryEventBus(func, false, null); + public TestBase(Func? func = null) => ResetMemoryEventBus(func, false, null); - protected void ResetMemoryEventBus(Func func = null, bool isAddLog = true, params Assembly[] assemblies) + protected void ResetMemoryEventBus(Func? func = null, bool isAddLog = true, params Assembly[]? assemblies) { _services = new ServiceCollection(); if (isAddLog) diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/IntegrationEventBusTest.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/IntegrationEventBusTest.cs index 3a75473bd..d8d2fd127 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/IntegrationEventBusTest.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.Tests/IntegrationEventBusTest.cs @@ -22,7 +22,7 @@ public void Initialize() _daprClient = new(); _logger = new(); _eventLog = new(); - _eventLog.Setup(eventLog => eventLog.SaveEventAsync(It.IsAny(), null)).Verifiable(); + _eventLog.Setup(eventLog => eventLog.SaveEventAsync(It.IsAny(), null!)).Verifiable(); _eventLog.Setup(eventLog => eventLog.MarkEventAsInProgressAsync(It.IsAny())).Verifiable(); _eventLog.Setup(eventLog => eventLog.MarkEventAsPublishedAsync(It.IsAny())).Verifiable(); _eventLog.Setup(eventLog => eventLog.MarkEventAsFailedAsync(It.IsAny())).Verifiable(); @@ -34,7 +34,7 @@ public void Initialize() _eventBus = new(); _uoW = new(); _uoW.Setup(uoW => uoW.CommitAsync(default)).Verifiable(); - _uoW.Setup(uoW => uoW.Transaction).Returns(() => null); + _uoW.Setup(uoW => uoW.Transaction).Returns(() => null!); } [TestMethod] @@ -47,7 +47,7 @@ public void TestDispatcherOption() { options = new DispatcherOptions(services) { - Assemblies = null + Assemblies = null! }; }); Assert.ThrowsException(() => @@ -119,7 +119,7 @@ public void TestAddDaprEventBusAndChangeAssemblies() [TestMethod] public void TestAddDaprEventBusAndNullServicesAsync() { - _options.Setup(option => option.Services).Returns(() => null); + _options.Setup(option => option.Services).Returns(() => null!); var ex = Assert.ThrowsException(() => _options.Object.UseDaprEventBus()); Assert.IsTrue(ex.Message == $"Value cannot be null. (Parameter '{nameof(_options.Object.Services)}')"); } diff --git a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/IntegrationEventLogServiceTest.cs b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/IntegrationEventLogServiceTest.cs index 93555862f..fd80f19b6 100644 --- a/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/IntegrationEventLogServiceTest.cs +++ b/test/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.Tests/IntegrationEventLogServiceTest.cs @@ -88,7 +88,7 @@ public void TestMultUseEventLogService() [TestMethod] public void TestNullServices() { - var options = new DispatcherOptions(null); + var options = new DispatcherOptions(null!); Assert.ThrowsException(() => { options.UseEventLog(options => @@ -104,14 +104,14 @@ public void TestNullDbContextOptionsBuilder() var options = new DispatcherOptions(new ServiceCollection()); Assert.ThrowsException(() => { - options.UseEventLog(null); + options.UseEventLog(null!); }); } [TestMethod] public void TestUseCustomDbContextByNullServices() { - var options = new DispatcherOptions(null); + var options = new DispatcherOptions(null!); Assert.IsNull(options.Services); Assert.ThrowsException(() => options.UseEventLog()); } diff --git a/test/MASA.Contribs.DDD.Domain.Entities/MASA.Contribs.DDD.Domain.Entities.csproj b/test/MASA.Contribs.DDD.Domain.Entities.Tests/MASA.Contribs.DDD.Domain.Entities.Tests.csproj similarity index 100% rename from test/MASA.Contribs.DDD.Domain.Entities/MASA.Contribs.DDD.Domain.Entities.csproj rename to test/MASA.Contribs.DDD.Domain.Entities.Tests/MASA.Contribs.DDD.Domain.Entities.Tests.csproj diff --git a/test/MASA.Contribs.DDD.Domain.Entities/Users.cs b/test/MASA.Contribs.DDD.Domain.Entities.Tests/Users.cs similarity index 62% rename from test/MASA.Contribs.DDD.Domain.Entities/Users.cs rename to test/MASA.Contribs.DDD.Domain.Entities.Tests/Users.cs index 5d0a693ba..342e042f8 100644 --- a/test/MASA.Contribs.DDD.Domain.Entities/Users.cs +++ b/test/MASA.Contribs.DDD.Domain.Entities.Tests/Users.cs @@ -1,4 +1,4 @@ -namespace MASA.Contribs.DDD.Domain.Entities; +namespace MASA.Contribs.DDD.Domain.Entities.Tests; public class Users : AggregateRoot { diff --git a/test/MASA.Contribs.DDD.Domain.Entities/_Imports.cs b/test/MASA.Contribs.DDD.Domain.Entities.Tests/_Imports.cs similarity index 100% rename from test/MASA.Contribs.DDD.Domain.Entities/_Imports.cs rename to test/MASA.Contribs.DDD.Domain.Entities.Tests/_Imports.cs diff --git a/test/MASA.Contribs.DDD.Domain.Repository/MASA.Contribs.DDD.Domain.Repository.csproj b/test/MASA.Contribs.DDD.Domain.Repository/MASA.Contribs.DDD.Domain.Repository.csproj deleted file mode 100644 index 268cbace4..000000000 --- a/test/MASA.Contribs.DDD.Domain.Repository/MASA.Contribs.DDD.Domain.Repository.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - net6.0 - enable - enable - false - - - diff --git a/test/MASA.Contribs.DDD.Domain.Repository/_Imports.cs b/test/MASA.Contribs.DDD.Domain.Repository/_Imports.cs deleted file mode 100644 index e69de29bb..000000000 From 7244962c23d3eedff37864884e9ab396360ebd9e Mon Sep 17 00:00:00 2001 From: capdiem Date: Thu, 9 Dec 2021 17:40:03 +0800 Subject: [PATCH 19/39] =?UTF-8?q?=F0=9F=86=95=20feat(minimal-apis):=20Impr?= =?UTF-8?q?ove=20MapGet,=20MapPost,=20MapPut=20and=20MapDelete=20with=20Ba?= =?UTF-8?q?seUri=20prop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ServiceBase.cs | 83 ++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs b/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs index 6d0bee5d0..4792ea4aa 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs @@ -1,11 +1,15 @@ +using Microsoft.AspNetCore.Routing; + namespace MASA.Contrib.Service.MinimalAPIs; -public class ServiceBase : IService +public abstract class ServiceBase : IService { private ServiceProvider _serviceProvider = default!; public WebApplication App => _serviceProvider.GetRequiredService(); + public string BaseUri { get; } + public IServiceCollection Services { get; protected set; } public ServiceBase(IServiceCollection services) @@ -14,9 +18,84 @@ public ServiceBase(IServiceCollection services) _serviceProvider = services.BuildServiceProvider(); } + public ServiceBase(IServiceCollection services, string baseUri) + { + BaseUri = baseUri; + Services = services; + _serviceProvider = services.BuildServiceProvider(); + } + public TService? GetService() => _serviceProvider.GetService(); public TService GetRequiredService() where TService : notnull => Services.BuildServiceProvider().GetRequiredService(); -} + + #region Map GET,POST,PUT,DELETE + + /// + /// Adds a to the that matches HTTP GET requests + /// for the specified pattern, a combination of and or name. + /// + /// The delegate executed when the endpoint is matched. It's name is a part of pattern if is null. + /// The custom uri. It is a part of pattern if it is not null. + /// A that can be used to further customize the endpoint. + protected RouteHandlerBuilder MapGet(Delegate handler, string? customUri = null) + { + customUri ??= FormatAction(handler.Method.Name); + + return App.MapGet($"{BaseUri}/{customUri}", handler); + } + + /// + /// Adds a to the that matches HTTP POST requests + /// for the specified pattern, a combination of and or name. + /// + /// The delegate executed when the endpoint is matched. It's name is a part of pattern if is null. + /// The custom uri. It is a part of pattern if it is not null. + /// A that can be used to further customize the endpoint. + protected RouteHandlerBuilder MapPost(Delegate handler, string? customUri = null) + { + customUri ??= FormatAction(handler.Method.Name); + + return App.MapPost($"{BaseUri}/{customUri}", handler); + } + + /// + /// Adds a to the that matches HTTP PUT requests + /// for the specified pattern, a combination of and or name. + /// + /// The delegate executed when the endpoint is matched. It's name is a part of pattern if is null. + /// The custom uri. It is a part of pattern if it is not null. + /// A that can be used to further customize the endpoint. + protected RouteHandlerBuilder MapPut(Delegate handler, string? customUri = null) + { + customUri ??= FormatAction(handler.Method.Name); + + return App.MapPut($"{BaseUri}/{customUri}", handler); + } + + /// + /// Adds a to the that matches HTTP DELETE requests + /// for the specified pattern, a combination of and or name. + /// + /// The delegate executed when the endpoint is matched. It's name is a part of pattern if is null. + /// The custom uri. It is a part of pattern if it is not null. + /// A that can be used to further customize the endpoint. + protected RouteHandlerBuilder MapDelete(Delegate handler, string? customUri = null) + { + customUri ??= FormatAction(handler.Method.Name); + + return App.MapDelete($"{BaseUri}/{customUri}", handler); + } + + private static string FormatAction(string action) + { + if (!action.EndsWith("Async")) return action; + + var i = action.LastIndexOf("Async", StringComparison.Ordinal); + return action[..i]; + } + + #endregion +} \ No newline at end of file From 4a3660f30a644d6bc4aa7d12fca82de7cb49d828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=B9=E5=B0=A4=E5=85=88?= Date: Fri, 10 Dec 2021 08:06:14 +0000 Subject: [PATCH 20/39] =?UTF-8?q?=F0=9F=90=9B=20fix:=20Combine=20baseUri?= =?UTF-8?q?=20and=20customUri?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ServiceBase.cs | 54 ++++++++++++------- .../_Imports.cs | 1 + 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs b/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs index 4792ea4aa..2ef353c06 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/ServiceBase.cs @@ -1,5 +1,3 @@ -using Microsoft.AspNetCore.Routing; - namespace MASA.Contrib.Service.MinimalAPIs; public abstract class ServiceBase : IService @@ -39,12 +37,15 @@ public TService GetRequiredService() /// /// The delegate executed when the endpoint is matched. It's name is a part of pattern if is null. /// The custom uri. It is a part of pattern if it is not null. + /// Determines whether to remove the string 'Async' at the end. /// A that can be used to further customize the endpoint. - protected RouteHandlerBuilder MapGet(Delegate handler, string? customUri = null) + protected RouteHandlerBuilder MapGet(Delegate handler, string? customUri = null, bool trimEndAsync = true) { - customUri ??= FormatAction(handler.Method.Name); + customUri ??= FormatAction(handler.Method.Name, trimEndAsync); + + var pattern = CombineUris(BaseUri, customUri); - return App.MapGet($"{BaseUri}/{customUri}", handler); + return App.MapGet(pattern, handler); } /// @@ -53,12 +54,15 @@ protected RouteHandlerBuilder MapGet(Delegate handler, string? customUri = null) /// /// The delegate executed when the endpoint is matched. It's name is a part of pattern if is null. /// The custom uri. It is a part of pattern if it is not null. + /// Determines whether to remove the string 'Async' at the end. /// A that can be used to further customize the endpoint. - protected RouteHandlerBuilder MapPost(Delegate handler, string? customUri = null) + protected RouteHandlerBuilder MapPost(Delegate handler, string? customUri = null, bool trimEndAsync = true) { - customUri ??= FormatAction(handler.Method.Name); + customUri ??= FormatAction(handler.Method.Name, trimEndAsync); - return App.MapPost($"{BaseUri}/{customUri}", handler); + var pattern = CombineUris(BaseUri, customUri); + + return App.MapPost(pattern, handler); } /// @@ -67,12 +71,15 @@ protected RouteHandlerBuilder MapPost(Delegate handler, string? customUri = null /// /// The delegate executed when the endpoint is matched. It's name is a part of pattern if is null. /// The custom uri. It is a part of pattern if it is not null. + /// Determines whether to remove the string 'Async' at the end. /// A that can be used to further customize the endpoint. - protected RouteHandlerBuilder MapPut(Delegate handler, string? customUri = null) + protected RouteHandlerBuilder MapPut(Delegate handler, string? customUri = null, bool trimEndAsync = true) { - customUri ??= FormatAction(handler.Method.Name); + customUri ??= FormatAction(handler.Method.Name, trimEndAsync); + + var pattern = CombineUris(BaseUri, customUri); - return App.MapPut($"{BaseUri}/{customUri}", handler); + return App.MapPut(pattern, handler); } /// @@ -81,20 +88,31 @@ protected RouteHandlerBuilder MapPut(Delegate handler, string? customUri = null) /// /// The delegate executed when the endpoint is matched. It's name is a part of pattern if is null. /// The custom uri. It is a part of pattern if it is not null. + /// Determines whether to remove the string 'Async' at the end. /// A that can be used to further customize the endpoint. - protected RouteHandlerBuilder MapDelete(Delegate handler, string? customUri = null) + protected RouteHandlerBuilder MapDelete(Delegate handler, string? customUri = null, bool trimEndAsync = true) { - customUri ??= FormatAction(handler.Method.Name); + customUri ??= FormatAction(handler.Method.Name, trimEndAsync); - return App.MapDelete($"{BaseUri}/{customUri}", handler); + var pattern = CombineUris(BaseUri, customUri); + + return App.MapDelete(pattern, handler); } - private static string FormatAction(string action) + private static string FormatAction(string action, bool trimEndAsync) { - if (!action.EndsWith("Async")) return action; + if (trimEndAsync && action.EndsWith("Async")) + { + var i = action.LastIndexOf("Async", StringComparison.Ordinal); + action = action[..i]; + } + + return action; + } - var i = action.LastIndexOf("Async", StringComparison.Ordinal); - return action[..i]; + private static string CombineUris(params string[] uris) + { + return string.Join("/", uris.Select(u => u.Trim('/'))); } #endregion diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/_Imports.cs b/src/Service/MASA.Contrib.Service.MinimalAPIs/_Imports.cs index 9015d4d4a..a6b33566f 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/_Imports.cs +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/_Imports.cs @@ -1,5 +1,6 @@ global using MASA.BuildingBlocks.Service.MinimalAPIs; global using Microsoft.AspNetCore.Builder; +global using Microsoft.AspNetCore.Routing; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection.Extensions; global using System; From 00a93420c6fa822d7f788924f745edb8642c7c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E5=B5=98?= Date: Fri, 10 Dec 2021 08:23:46 +0000 Subject: [PATCH 21/39] Update .gitlab-ci.yml --- .gitlab-ci.yml | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4e8ff5524..edf4e831e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,32 +1,10 @@ -image: mcr.microsoft.com/dotnet/sdk:6.0.100-preview.7 - stages: - build - - tests - - nuget build: stage: build + image: mcr.microsoft.com/dotnet/sdk:6.0 only: - branches script: - dotnet build - retry: 2 - -# tests: -# stage: tests -# only: -# - branches -# script: -# - dotnet test --collect:"XPlat Code Coverage" -# retry: 2 - -nuget: - stage: nuget - only: - - branches - script: - - dotnet build - - dotnet pack --include-symbols -p:PackageVersion=0.0.$CI_PIPELINE_ID - - dotnet nuget push "**/*.symbols.nupkg" --source gitlab - retry: 2 From 34298df2ed075dd75d1988a9e79c41c0784ed376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E5=B5=98?= Date: Fri, 10 Dec 2021 08:26:06 +0000 Subject: [PATCH 22/39] =?UTF-8?q?=E6=9B=B4=E6=96=B0.gitlab-ci.yml=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index edf4e831e..50b61d584 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,10 +1,20 @@ +image: mcr.microsoft.com/dotnet/sdk:6.0 + stages: - build + - test build: stage: build - image: mcr.microsoft.com/dotnet/sdk:6.0 only: - branches script: - dotnet build + + +test: + stage: test + only: + - branches + script: + - dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[*.Tests]*" \ No newline at end of file From 96439280852dd31d6f1ec19630358b9062cd5150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E5=B5=98?= Date: Fri, 10 Dec 2021 08:30:21 +0000 Subject: [PATCH 23/39] Delete .gitlab-ci.yml --- .gitlab-ci.yml | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 50b61d584..000000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,20 +0,0 @@ -image: mcr.microsoft.com/dotnet/sdk:6.0 - -stages: - - build - - test - -build: - stage: build - only: - - branches - script: - - dotnet build - - -test: - stage: test - only: - - branches - script: - - dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[*.Tests]*" \ No newline at end of file From 3f872d433844edb0c6c276b33fbffc0fc67da152 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Mon, 13 Dec 2021 07:46:32 +0000 Subject: [PATCH 24/39] chore: change fileName --- .../Repository.cs | 14 +++++++------- .../{RREADME.zh-CN.md => README.zh-CN.md} | 0 .../{RREADME.zh-CN.md => README.zh-CN.md} | 0 3 files changed, 7 insertions(+), 7 deletions(-) rename src/Data/MASA.Contrib.Data.Contracts.EF/{RREADME.zh-CN.md => README.zh-CN.md} (100%) rename src/Data/MASA.Contrib.Data.UoW.EF/{RREADME.zh-CN.md => README.zh-CN.md} (100%) diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs index 8b5de93a6..a56c6be61 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/Repository.cs @@ -48,7 +48,7 @@ public override Task CommitAsync(CancellationToken cancellationToken = default) public override async ValueTask DisposeAsync() => await ValueTask.CompletedTask; - public override Task FindAsync(object?[]? keyValues, CancellationToken cancellationToken) + public override Task FindAsync(object?[]? keyValues, CancellationToken cancellationToken = default) { if (keyValues == null) return Task.FromResult(default(TEntity?)); @@ -69,20 +69,20 @@ public override Task CommitAsync(CancellationToken cancellationToken = default) CancellationToken cancellationToken = default) => _context.Set().Where(predicate).FirstOrDefaultAsync(cancellationToken); - public override async Task GetCountAsync(CancellationToken cancellationToken) + public override async Task GetCountAsync(CancellationToken cancellationToken = default) => await _context.Set().LongCountAsync(cancellationToken); public override Task GetCountAsync( Expression> predicate, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) => _context.Set().LongCountAsync(predicate, cancellationToken); - public override async Task> GetListAsync(CancellationToken cancellationToken) + public override async Task> GetListAsync(CancellationToken cancellationToken = default) => await _context.Set().ToListAsync(cancellationToken); public override async Task> GetListAsync( Expression> predicate, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) => await _context.Set().Where(predicate).ToListAsync(cancellationToken); /// @@ -93,7 +93,7 @@ public override async Task> GetListAsync( /// asc or desc, default asc /// /// - public override Task> GetPaginatedListAsync(int skip, int take, Dictionary? sorting, CancellationToken cancellationToken) + public override Task> GetPaginatedListAsync(int skip, int take, Dictionary? sorting, CancellationToken cancellationToken = default) { if (sorting == null) sorting = new Dictionary(GetKeys(typeof(TEntity)).Select(x => new KeyValuePair(x, false))); @@ -110,7 +110,7 @@ public override Task> GetPaginatedListAsync(int skip, int take, Di /// asc or desc, default asc /// /// - public override Task> GetPaginatedListAsync(Expression> predicate, int skip, int take, Dictionary? sorting, CancellationToken cancellationToken) + public override Task> GetPaginatedListAsync(Expression> predicate, int skip, int take, Dictionary? sorting, CancellationToken cancellationToken = default) { if (sorting == null) { diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md b/src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-CN.md similarity index 100% rename from src/Data/MASA.Contrib.Data.Contracts.EF/RREADME.zh-CN.md rename to src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-CN.md diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/RREADME.zh-CN.md b/src/Data/MASA.Contrib.Data.UoW.EF/README.zh-CN.md similarity index 100% rename from src/Data/MASA.Contrib.Data.UoW.EF/RREADME.zh-CN.md rename to src/Data/MASA.Contrib.Data.UoW.EF/README.zh-CN.md From ad52b8a650f280d88563098322853cefb0ef6f3e Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Thu, 23 Dec 2021 18:07:15 +0800 Subject: [PATCH 25/39] chore: update dapr library package --- .../MASA.Contrib.BasicAbility.Dcc.csproj | 8 ++++---- .../MASA.Contrib.Data.Contracts.EF.csproj | 2 +- .../MASA.Contrib.Data.UoW.EF.csproj | 2 +- .../MASA.Contrib.Dispatcher.Events.csproj | 2 +- .../MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj | 5 ++--- ...ntrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj | 2 +- .../MASA.Contrib.Service.MinimalAPIs.csproj | 4 ++-- .../MASA.Contrib.Data.Contracts.EF.Tests.csproj | 2 +- 8 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj index bc9812c5c..b3a1e3b8b 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj @@ -8,10 +8,10 @@ - - - - + + + + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj index 7ff5a4f00..831385ce2 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj index 4ec7c7033..1bc35f8c4 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj +++ b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj index 000208500..e3df38944 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj index cef8f0c46..41d888fde 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj @@ -7,10 +7,9 @@ - - + - + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj index 38ee74aab..c869e1da0 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj index 89d0fdd9b..a2edc25ee 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj b/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj index 90a5be082..12ddeb750 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj +++ b/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj @@ -19,7 +19,7 @@ - + From 3a2907b0b2ac2a70672af0c5ce8e0c322507f446 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Thu, 30 Dec 2021 03:47:52 +0000 Subject: [PATCH 26/39] chore: change readme --- README.md | 2 +- README.zh-CN.md | 8 ++++---- src/DDD/MASA.Contrib.DDD.Domain/README.md | 4 ++-- src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md | 4 ++-- .../Benchmarks.cs | 4 ++-- .../Extensions/Events/ForgetPasswordEvent.cs | 2 +- .../Extensions/Events/RegisterUserEvent.cs | 2 +- .../EventHandlers/UserEventHandler.cs | 2 +- .../{BindMobileEvent.cs => BindPhoneNumberEvent.cs} | 4 ++-- test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs | 2 +- 10 files changed, 17 insertions(+), 17 deletions(-) rename test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/Events/{BindMobileEvent.cs => BindPhoneNumberEvent.cs} (58%) diff --git a/README.md b/README.md index dd21b39e8..770fcf46e 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ Realize cross-process events based on Dapr。[Usage introduction](/src/Dispatche > Advantage: > > 1. CQRS -> 2. Field Service +> 2. Domain Service > 3. Support domain events (in-process), integrated domain events (cross-process) > 4. Support the unified sending of field events after being pushed onto the stack diff --git a/README.zh-CN.md b/README.zh-CN.md index 8093fddf3..9a0265a83 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,4 +1,4 @@ -中 | [EN](README.md) +中 | [EN](README.md) [![codecov](https://codecov.io/gh/masastack/MASA.Contrib/branch/develop/graph/badge.svg?token=87TPNHUHW2)](https://codecov.io/gh/masastack/MASA.Contrib) @@ -93,9 +93,9 @@ MASA.Contrib > 优势: > -> 2. CQRS -> 3. 领域服务 -> 4. 支持领域事件(进程内)、集成领域事件(跨进程) +> 1. CQRS +> 2. 领域服务 +> 3. 支持领域事件(进程内)、集成领域事件(跨进程) > 4. 支持对领域事件先压栈后统一发送 ### 6. DDD diff --git a/src/DDD/MASA.Contrib.DDD.Domain/README.md b/src/DDD/MASA.Contrib.DDD.Domain/README.md index d0b37c510..842995a1e 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/README.md +++ b/src/DDD/MASA.Contrib.DDD.Domain/README.md @@ -24,7 +24,7 @@ builder.Services options.UseEventBus()//Use in-process events .UseUoW(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=idientity")) .UseDaprEventBus()///Use cross-process events - .UseEventLog() + .UseEventLog() .UseRepository();//Use the EF version of Repository to achieve }) ``` @@ -38,7 +38,7 @@ public class RegisterUserDomainCommand : DomainCommand public string Password { get; set; } = default!; - public string Mobile { get; set; } = default!; + public string PhoneNumber { get; set; } = default!; } ``` > DomainQuery refers to Query in CQRS diff --git a/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md b/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md index 95c16a4cb..a6402cc4d 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md +++ b/src/DDD/MASA.Contrib.DDD.Domain/README.zh-CN.md @@ -24,7 +24,7 @@ builder.Services options.UseEventBus()//使用进程内事件 .UseUoW(dbOptions => dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=idientity")) .UseDaprEventBus()///使用跨进程事件 - .UseEventLog() + .UseEventLog() .UseRepository();//使用Repository的EF版实现 }) ``` @@ -38,7 +38,7 @@ public class RegisterUserDomainCommand : DomainCommand public string Password { get; set; } = default!; - public string Mobile { get; set; } = default!; + public string PhoneNumber { get; set; } = default!; } ``` > DomainQuery参考CQRS中的Query diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Benchmarks.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Benchmarks.cs index 633736ad6..92194fcaa 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Benchmarks.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Benchmarks.cs @@ -20,12 +20,12 @@ public void GlobalSetup() _userEvent = new RegisterUserEvent() { Name = "tom", - Mobile = "18888888888" + PhoneNumber = "18888888888" }; _forgetPasswordEvent = new ForgetPasswordEvent() { Name = "lisa", - Mobile = "19999999999" + PhoneNumber = "19999999999" }; } diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/ForgetPasswordEvent.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/ForgetPasswordEvent.cs index abe93678a..dc9e2fbb7 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/ForgetPasswordEvent.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/ForgetPasswordEvent.cs @@ -4,5 +4,5 @@ public record ForgetPasswordEvent : Event { public string Name { get; set; } - public string Mobile { get; set; } + public string PhoneNumber { get; set; } } diff --git a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/RegisterUserEvent.cs b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/RegisterUserEvent.cs index 49353fbaf..30ba9d578 100644 --- a/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/RegisterUserEvent.cs +++ b/test/MASA.Contrib.Dispatcher.Events.BenchmarkDotnet.Tests/Extensions/Events/RegisterUserEvent.cs @@ -4,5 +4,5 @@ public record RegisterUserEvent : Event { public string Name { get; set; } - public string Mobile { get; set; } + public string PhoneNumber { get; set; } } diff --git a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/EventHandlers/UserEventHandler.cs b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/EventHandlers/UserEventHandler.cs index 66356ba86..02ae7f52a 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/EventHandlers/UserEventHandler.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/EventHandlers/UserEventHandler.cs @@ -3,7 +3,7 @@ namespace MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.EventHandlers; public class UserEventHandler { [EventHandler(IsCancel = true)] - public void BindMobile(BindMobileEvent @event) + public void BindPhoneNumber(BindPhoneNumberEvent @event) { } diff --git a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/Events/BindMobileEvent.cs b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/Events/BindPhoneNumberEvent.cs similarity index 58% rename from test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/Events/BindMobileEvent.cs rename to test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/Events/BindPhoneNumberEvent.cs index e339a5215..a28c44bb8 100644 --- a/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/Events/BindMobileEvent.cs +++ b/test/MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests/Events/BindPhoneNumberEvent.cs @@ -1,8 +1,8 @@ namespace MASA.Contrib.Dispatcher.Events.OnlyCancelHandler.Tests.Events; -public record BindMobileEvent : Event +public record BindPhoneNumberEvent : Event { public string AccountId { get; set; } - public string Mobile { get; set; } + public string PhoneNumber { get; set; } } diff --git a/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs b/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs index 52714f63a..4a5cc269c 100644 --- a/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs +++ b/test/MASA.Contrib.Dispatcher.Events.Tests/FeaturesTest.cs @@ -163,7 +163,7 @@ public Task TestOnlyCancelHandler() { try { - ResetMemoryEventBus(typeof(OnlyCancelHandler.Tests.Events.BindMobileEvent).Assembly); + ResetMemoryEventBus(typeof(OnlyCancelHandler.Tests.Events.BindPhoneNumberEvent).Assembly); } catch (NotSupportedException) { From ac7ecba77b9ec4f5c055882c172040cd516cf04b Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Tue, 11 Jan 2022 11:59:06 +0800 Subject: [PATCH 27/39] chore: Added a solution to the failure to obtain the Event relationship chain --- docs/LoadEvent.md | 10 ++++++++++ .../EventBus.cs | 19 ++++++++++++------- .../Options/DispatcherOptions.cs | 4 ++-- 3 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 docs/LoadEvent.md diff --git a/docs/LoadEvent.md b/docs/LoadEvent.md new file mode 100644 index 000000000..65d1db9e3 --- /dev/null +++ b/docs/LoadEvent.md @@ -0,0 +1,10 @@ +# LoadEvent + +## Getting "Event" relationship chain failed + +When Event, EventHandler, and the main project are not in the same assembly, there will be a failure to obtain the "Event" relationship chain when publishing Events through EventBus. When we use AddEventBus without a special specified assembly, the assembly under the current domain is used by default. Due to the delayed loading feature of dotnet, the acquisition of the event relationship chain is incomplete. There are the following two solutions : + +1. When using AddEventBus, specify the complete set of application assemblies used by the current project by specifying Assemblies + +2. Before using AddEventBus, by calling Event directly +Any method or class of the assembly where the EventHandler is located, make sure that the application assembly where it is located has been loaded into the current assembly ( AppDomain.CurrentDomain.GetAssemblies() ) diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs index 0abb86540..1f7cd0cd8 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/EventBus.cs @@ -10,6 +10,8 @@ public class EventBus : IEventBus private IUnitOfWork? _unitOfWork; + private readonly string LoadEventHelpLink = "https://github.com/masastack/MASA.Contrib/tree/develop/docs/LoadEvent.md"; + public EventBus(IServiceProvider serviceProvider, IOptions options) { _serviceProvider = serviceProvider; @@ -19,15 +21,21 @@ public EventBus(IServiceProvider serviceProvider, IOptions op public async Task PublishAsync(TEvent @event) where TEvent : IEvent { + var eventType = typeof(TEvent); if (@event is null) { - throw new ArgumentNullException(typeof(TEvent).Name); + throw new ArgumentNullException(eventType.Name); } var middlewares = _serviceProvider.GetRequiredService>>(); - if (_options.UnitOfWorkRelation[typeof(TEvent)]) + if (!_options.UnitOfWorkRelation.ContainsKey(eventType)) { - ITransaction transactionEvent = (ITransaction)@event; + throw new NotSupportedException($"Getting \"{eventType.Name}\" relationship chain failed, see {LoadEventHelpLink} for details. "); + } + + if (_options.UnitOfWorkRelation[eventType]) + { + ITransaction transactionEvent = (ITransaction) @event; var unitOfWork = _serviceProvider.GetService(); if (unitOfWork != null) { @@ -43,10 +51,7 @@ public async Task PublishAsync(TEvent @event) where TEvent : IEvent } } - EventHandlerDelegate publishEvent = async () => - { - await _dispatcher.PublishEventAsync(_serviceProvider, @event); - }; + EventHandlerDelegate publishEvent = async () => { await _dispatcher.PublishEventAsync(_serviceProvider, @event); }; await middlewares.Reverse().Aggregate(publishEvent, (next, middleware) => () => middleware.HandleAsync(@event, next))(); } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs index ad57330d0..3db90c640 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Options/DispatcherOptions.cs @@ -2,7 +2,7 @@ namespace MASA.Contrib.Dispatcher.Events.Options; public class DispatcherOptions : IDispatcherOptions { - private Assembly[] _assemblies = new Assembly[0]; + private Assembly[] _assemblies = Array.Empty(); public Assembly[] Assemblies { @@ -19,7 +19,7 @@ public Assembly[] Assemblies .Where(type => type.IsClass && typeof(IEvent).IsAssignableFrom(type)) .ToList(); - UnitOfWorkRelation = AllEventTypes.ToDictionary(type => type, type => IsSupportUnitOfWork(type)); + UnitOfWorkRelation = AllEventTypes.ToDictionary(type => type, IsSupportUnitOfWork); } } From 9414348f55b04120c7ac57366f2a666e0ffed364 Mon Sep 17 00:00:00 2001 From: zhenlei520 Date: Wed, 12 Jan 2022 03:09:32 +0000 Subject: [PATCH 28/39] Fix/event --- .../MASA.Contrib.BasicAbility.Dcc.csproj | 10 +++++----- .../MasaConfigurationExtensions.cs | 6 +++--- .../MASA.Contrib.Configuration.csproj | 2 +- .../MASA.Contrib.DDD.Domain.Repository.EF.csproj | 2 +- .../MASA.Contrib.DDD.Domain/Events/DomainCommand.cs | 2 ++ src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs | 2 ++ src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs | 2 ++ .../Events/IntegrationDomainEvent.cs | 1 + .../MASA.Contrib.DDD.Domain.csproj | 2 +- .../MASA.Contrib.Data.Contracts.EF.csproj | 6 +++--- .../MASA.Contrib.Data.UoW.EF.csproj | 6 +++--- src/Dispatcher/MASA.Contrib.Dispatcher.Events/Event.cs | 2 ++ .../MASA.Contrib.Dispatcher.Events.csproj | 10 +++++----- .../MASA.Contrib.Dispatcher.Events/_Imports.cs | 1 + .../IntegrationEvent.cs | 3 +++ ...SA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj | 4 ++-- ...ib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj | 4 ++-- .../Commands/Command.cs | 2 ++ .../MASA.Contrib.ReadWriteSpliting.CQRS.csproj | 4 ++-- .../Queries/Query.cs | 2 ++ .../MASA.Contrib.ReadWriteSpliting.CQRS/_Imports.cs | 1 + .../MASA.Contrib.Service.MinimalAPIs.csproj | 6 +++--- .../MASA.Contrib.Data.Contracts.EF.Tests.csproj | 4 ++-- 23 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj index b3a1e3b8b..20f81b453 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MASA.Contrib.BasicAbility.Dcc.csproj @@ -7,11 +7,11 @@ - - - - - + + + + + diff --git a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs index 747d4b061..f83f41adc 100644 --- a/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs +++ b/src/BasicAbility/MASA.Contrib.BasicAbility.Dcc/MasaConfigurationExtensions.cs @@ -60,17 +60,17 @@ public static IMasaConfigurationBuilder UseDcc( PropertyNameCaseInsensitive = true }; jsonSerializerOptions?.Invoke(jsonSerializerOption); - services.AddCaller(Options => + services.AddCaller(options => { if (callerOptions == null) { - Options.UseHttpClient(() + options.UseHttpClient(() => new MasaHttpClientBuilder(DEFAULT_CLIENT_NAME, string.Empty, opt => opt.BaseAddress = new Uri(config.DccConfigurationOption.ManageServiceAddress), jsonSerializerOption) ); } else { - callerOptions.Invoke(Options); + callerOptions.Invoke(options); } }); diff --git a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj index e95bf4806..c922b16ec 100644 --- a/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj +++ b/src/Configuration/MASA.Contrib.Configuration/MASA.Contrib.Configuration.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj index 2a97adf92..0a5db0ecb 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain.Repository.EF/MASA.Contrib.DDD.Domain.Repository.EF.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainCommand.cs b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainCommand.cs index bd05fed21..54e6999e5 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainCommand.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainCommand.cs @@ -2,8 +2,10 @@ namespace MASA.Contrib.DDD.Domain.Events; public record DomainCommand : IDomainCommand { + [JsonIgnore] public Guid Id { get; init; } + [JsonIgnore] public DateTime CreationTime { get; init; } [JsonIgnore] diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs index fc8a28c63..f87cdedd7 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainEvent.cs @@ -2,8 +2,10 @@ namespace MASA.Contrib.DDD.Domain.Events; public record DomainEvent : IDomainEvent { + [JsonIgnore] public Guid Id { get; init; } + [JsonIgnore] public DateTime CreationTime { get; init; } [JsonIgnore] diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs index 8be4b1563..2e96e40a2 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Events/DomainQuery.cs @@ -3,8 +3,10 @@ namespace MASA.Contrib.DDD.Domain.Events; public abstract record DomainQuery : IDomainQuery where TResult : notnull { + [JsonIgnore] public Guid Id { get; init; } + [JsonIgnore] public DateTime CreationTime { get; init; } [JsonIgnore] diff --git a/src/DDD/MASA.Contrib.DDD.Domain/Events/IntegrationDomainEvent.cs b/src/DDD/MASA.Contrib.DDD.Domain/Events/IntegrationDomainEvent.cs index a0f916a10..eff19f144 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/Events/IntegrationDomainEvent.cs +++ b/src/DDD/MASA.Contrib.DDD.Domain/Events/IntegrationDomainEvent.cs @@ -2,6 +2,7 @@ namespace MASA.Contrib.DDD.Domain.Events; public abstract record IntegrationDomainEvent : DomainEvent, IIntegrationDomainEvent { + [JsonIgnore] public abstract string Topic { get; set; } public IntegrationDomainEvent() : this(Guid.NewGuid(), DateTime.UtcNow) { } diff --git a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj index 5763c4ccc..3c7e81c5c 100644 --- a/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj +++ b/src/DDD/MASA.Contrib.DDD.Domain/MASA.Contrib.DDD.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj index 831385ce2..b6b9909a2 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/MASA.Contrib.Data.Contracts.EF.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj index 1bc35f8c4..7924a7213 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj +++ b/src/Data/MASA.Contrib.Data.UoW.EF/MASA.Contrib.Data.UoW.EF.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Event.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Event.cs index bcab2ea47..c4d6b516d 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Event.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/Event.cs @@ -2,8 +2,10 @@ namespace MASA.Contrib.Dispatcher.Events; public record Event : IEvent { + [JsonIgnore] public Guid Id { get; init; } + [JsonIgnore] public DateTime CreationTime { get; init; } public Event() : this(Guid.NewGuid(), DateTime.UtcNow) { } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj index e3df38944..44194dbaf 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/MASA.Contrib.Dispatcher.Events.csproj @@ -7,11 +7,11 @@ - - - - - + + + + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs index 708ca8761..b3e839e01 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.Events/_Imports.cs @@ -15,3 +15,4 @@ global using Microsoft.Extensions.Options; global using System.Linq.Expressions; global using System.Reflection; +global using System.Text.Json.Serialization; diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEvent.cs b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEvent.cs index 5af45246d..5a50db571 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEvent.cs +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/IntegrationEvent.cs @@ -2,13 +2,16 @@ namespace MASA.Contrib.Dispatcher.IntegrationEvents.Dapr; public abstract record IntegrationEvent : IIntegrationEvent { + [JsonIgnore] public Guid Id { get; init; } + [JsonIgnore] public DateTime CreationTime { get; init; } [JsonIgnore] public IUnitOfWork? UnitOfWork { get; set; } + [JsonIgnore] public abstract string Topic { get; set; } public IntegrationEvent() : this(Guid.NewGuid(), DateTime.UtcNow) { } diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj index 41d888fde..87a18256f 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr/MASA.Contrib.Dispatcher.IntegrationEvents.Dapr.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj index c869e1da0..0d2b310a2 100644 --- a/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj +++ b/src/Dispatcher/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF/MASA.Contrib.Dispatcher.IntegrationEvents.EventLogs.EF.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Commands/Command.cs b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Commands/Command.cs index 2253a8817..30e214bd3 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Commands/Command.cs +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Commands/Command.cs @@ -2,8 +2,10 @@ namespace MASA.Contrib.ReadWriteSpliting.CQRS.Commands; public record Command : ICommand { + [JsonIgnore] public Guid Id { get; init; } + [JsonIgnore] public DateTime CreationTime { get; init; } public Command() : this(Guid.NewGuid(), DateTime.UtcNow) { } diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj index a8c8967cc..946e6e406 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/MASA.Contrib.ReadWriteSpliting.CQRS.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Queries/Query.cs b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Queries/Query.cs index d7e3c2455..270217d44 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Queries/Query.cs +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/Queries/Query.cs @@ -3,8 +3,10 @@ namespace MASA.Contrib.ReadWriteSpliting.CQRS.Queries; public abstract record Query : IQuery where TResult : notnull { + [JsonIgnore] public Guid Id { get; init; } + [JsonIgnore] public DateTime CreationTime { get; init; } public abstract TResult Result { get; set; } diff --git a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/_Imports.cs b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/_Imports.cs index c934201ef..978c98f77 100644 --- a/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/_Imports.cs +++ b/src/ReadWriteSpliting/CQRS/MASA.Contrib.ReadWriteSpliting.CQRS/_Imports.cs @@ -1,3 +1,4 @@ global using MASA.BuildingBlocks.Dispatcher.Events; global using MASA.BuildingBlocks.ReadWriteSpliting.CQRS.Commands; global using MASA.BuildingBlocks.ReadWriteSpliting.CQRS.Queries; +global using System.Text.Json.Serialization; diff --git a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj index a2edc25ee..a0a1a7b4b 100644 --- a/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj +++ b/src/Service/MASA.Contrib.Service.MinimalAPIs/MASA.Contrib.Service.MinimalAPIs.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj b/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj index 12ddeb750..d3376dffd 100644 --- a/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj +++ b/test/MASA.Contrib.Data.Contracts.EF.Tests/MASA.Contrib.Data.Contracts.EF.Tests.csproj @@ -18,8 +18,8 @@ - - + + From e2faf28a53a0ef67acf8f1e371be780b502ab3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=BE=BE?= Date: Thu, 13 Jan 2022 07:30:04 +0000 Subject: [PATCH 29/39] add ghpackageconfig --- .github/workflows/package_push_github.yml | 39 ++++++++++++++++++ ...{packge.yml => package_push_nuget.org.yml} | 0 Directory.Build.props | 24 +++++++++++ nuget.config | 5 +++ packageIcon.png | Bin 0 -> 9523 bytes 5 files changed, 68 insertions(+) create mode 100644 .github/workflows/package_push_github.yml rename .github/workflows/{packge.yml => package_push_nuget.org.yml} (100%) create mode 100644 Directory.Build.props create mode 100644 packageIcon.png diff --git a/.github/workflows/package_push_github.yml b/.github/workflows/package_push_github.yml new file mode 100644 index 000000000..d49406e95 --- /dev/null +++ b/.github/workflows/package_push_github.yml @@ -0,0 +1,39 @@ +name: Packege CI +on: + push: + branches: [ develop ] + pull_request: + branches: [ develop ] + +jobs: + package-push: + name: package build and push + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: setting dotnet version + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '6.0.x' + include-prerelease: true + + - name: restore + run: dotnet restore + + - name: build + run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true + + - name: test + run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[*.Tests]*" + + - name: codecov + uses: codecov/codecov-action@v1 + + - name: pack + run: dotnet pack --include-symbols -p:PackageVersion=0.0.$GITHUB_RUN_ID + + - name: package push + run: | + dotnet nuget push "**/*.symbols.nupkg" --api-key ${{secrets.PACKAGE_NUGET_GITHUB}} --source "github" diff --git a/.github/workflows/packge.yml b/.github/workflows/package_push_nuget.org.yml similarity index 100% rename from .github/workflows/packge.yml rename to .github/workflows/package_push_nuget.org.yml diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..a0865029c --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,24 @@ + + + $(AssemblyName) + packageIcon.png + masastack + © masastack Corporation. All rights reserved. + packageIcon.png + https://github.com/masastack/MASA.Contrib + git + true + $(MSBuildThisFileDirectory) + LICENSE.txt + + + + True + + + + True + + + + diff --git a/nuget.config b/nuget.config index 3f0e00340..eaf63190b 100644 --- a/nuget.config +++ b/nuget.config @@ -2,5 +2,10 @@ + + + + + \ No newline at end of file diff --git a/packageIcon.png b/packageIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..2128805c1995656deba83316df54cb048b9264ee GIT binary patch literal 9523 zcmb_?RZtvV)GbMH4=#bh6C4s;1_`dg-8DgjI|&-xAvl9OgA6V~Cpf_dcXt_dkjq#1 z`99qG|A+3bK7046>Z-NRS!`}+MOv^g^lRHswFY3f}@9~klao-i!G2gNH zySuv|;>rBYZCF1_vuMm{8D3#v(PGHyqRWf-NXoq?Adw`92jeIH2nmfxW?&0p_#dT+ zx3(b>BY*zv^D#9$mfVeOJXjK=^U3gPq1}+S$|x44N}p@!BN?7}B8`SKi&IYN5ngBF zs);oV2_(1OIm^#Edrfz-YXcdX-|Vw*Z4GXT-R$P@ziO3WMj(?$PW=2=WRtBPGE|_} ze4Z&^GxPDbL5_#XJFr3vL59^DT;k%E`r;a;t~BRpvXFi85a&LHHhQuG?jeYqXg(N% zX1Vj}zu1OO4347=%wZ&6bN{&Who+=izhS@5s5S#Mg~<;aeG6!4x_4XdYEG1t5@`~n zZtJ3Gp#$1jaQ}pik~VM>C0|64s*TfClT0Di?6!8Bb@B?>GObvJ9`O`xwKi>R6`*pr$jH3Mt+~0m+Z`~xxr$xz zs`F8tHnbc`yd-Qp_XD<&aG*JP^I4oErdGPla&?v_IGPAnO(SBg`!=(b(uUz(OjO6` z2LV}Q_)XmDm;FJ4h0#%lYT3owLuRi=@MKc$vY6r%T=lr5S|&myNjpZgowjAU52|^f zAunQ%vNqqNe^X>=KufzZ2FYI^rYzaEdiT#c5e+8lJ~tg4dbLLqu&s%rEWg~Qv?8Lj zCsH?c-q43xmzkna{NA^4>cZ4a`lMnaVoWUXgBx{39Lw~{V+HkogNUx~Zk)C)%4&-g z&^PGSpZZ%&NM^cZ`6W2AL6^g;9K3O|PCiI%;6?3dMC0=5dvZ&iMVl1sm%qj>n~|NDVW5TB@rL>gdHdndI!Q(w~Xq z(7D_3{PKC062HjdgZh9OiVRI38Gmc#$fNI^a4C9it3tS6C`rnI^ZOO2KcCq8xWM6x-y1QQF1 zqQTh{gC(Rb4HP|0yd3l%t3vRvhye2vGqz8&d-rna2V!bAHU(5r$C43xL`2I@PVH0O zW_Qo)A50E3;Mg`ST5=)wrE4Y6?emv0@QS$4fs)U6F6^ua#a~OJL~*34fjE2IbIYOe zKMrkZX5I(~Tfe{r=}Qf>+tL1sWHRebwU0BsZGK_{or5uIP)HQCd+>P7*z&|MDC+%^ z(XWph@*yZl>?W^MNV6Ud_VRr{$ho$E^y~$Qb5)t?8|~|lc-C`^4k<;-QumuF!qq#1_qE`M4Yz- zYqS-uAhmh5#D;|@sq||W5O`#|l>Nc&7;S$rJ_YrzC2tDJf=%N`E}20w-9MQLJBe&o zuQIqLmyf-GE?tVAE|VPQw^_n~p-|Yy8rc?XVec2RN6SnJr+4q8mq6|uw zxy3Z6=}8<9yP2EzDwUV%X1=w8f+~=~RVE(6%c$%k;}+frK{E#s@^>|RkjqyR_SsDD z7~d@Df;ue$df1rGsWE%Ydff3+PzpW>e4cl10EN%(nv$((67o zuyhhC#-_u=@wnf*waXzFz4f6eNDgg#7|d;r00D#Ae{gTEzXwbQqJv*Pu10Y#s4C*S}TYq^1lFsx_<0XZ8wd{Ifb6xo_r>iYGhkI5f^~Zh>qmgxQD>0PRly zY}r>c9ZXrBZPLWe@0E29c^myc7A%}kfH|zB%|h*&rVv>WiT8u+T{+B}q9HFhXxPS< zWrreQkN;rAERx;hB%Fq}kafz5XL+A@Jkx?BVTg^55F2NH-^-W;G}wzR6m7+oLz@4g zB}nJqxl^m9oL83__^J}t)0^pKh@EgxG(7kRt{-g?`k`C_$)tdfbSc?xA@=H=HL#5n zJ;g*9y=m=k8Ltluk0hRW zI=kiquV(CAa16dH)YKWON_J+l#kJYB+~m?jw%x5@Ay?3E^Ygu-CDV2T94lq4+)*Fj zzd;g{5(JJtfO*-+N#%W6XgZrtbp(Hb|)nix1{$eVDRgST0({ z;&)HVj?G-XyC{O!pR1k_BKXyuR5)k>$KwD?Yb|2D&%L0kd@FvN=VGSOPek<@;x(aX z5s{0eN2}5buRDFSk0!L|A4V6L9H@jqQ)tqzT^S-r7xHybQ`oGRk)SkNHfZ|m(L)4Z z&(+k{)s*GUPk4hg>Lpz5$Vh~xNBv@lY7V@@nRTI{oIc&UYvb)=_+4JEiDOOHQ$W}% zkTH>~sh$a2U*MswcM9_DHzIa2p?qX-`fQXzT0im8g#yRQ7x9aaJ%)DH~0(n3cTbll}O++Dl7% zKEaW<0_`zAUQ=brDOuPLyEVt-pK=#u7fQ*+ow)?}IV_JIj2S#X2E+Go=aUf6gjB_K zos4m(_-FwIVbS&UxmCkk(uX5&Genx*mSSCp6nblNX^nmQW4*>BLqF*B{ACU+KGw_W zH9uW{AvDo8sVsh8NfUP6#ai0}0^s>rwbY;fU0*E3Tv^0!XHi6$RSHwIK}yd}=?9SJ zO3kAOwU6J#tnM6vcsd0UKBFx1d?wt)Dys>3EJ~NKM1# zo7h(!T?{;_lY`*9d!2A%p(Z{vdsx6ov;>QCPTtY0Q?gaWh#c{`UYygWD)rorw`}9E zjEd{GTH6ugf5fj3T`rsUB6hnDm(m>O5*Ojw?WU@49bKBcPdYS#LlV08L8#wXn1=5= zAKtC=kJWIRk_&+Q^CeGNL`?I>nBg9zacT$ef|~@~Bls2^?+6%H2&(jz0~RFx-H`8g zh*~?};F(b=t_vW~Y$oO+sIz5$W%*!p=pkqLCFoqAZ(`JHqje~nL@)@o_u!I!9^T3u z`zd-DD#vI`x%@|4QnfZrtk?E16#gW`=>^43MRbH$)3(EvO38vvnc;(;X;S?E5*o z^@BV0!8$19&VWtv0`kp%eB9$Y>sOniE*>*4j#+Rf`m7#__E@4U0Ket=$W0<`_nG#l za(BmRR&N#ZRnFOHurzJlGac?IIv5Jtc?|gblT;_;& zNnws}Fz%~+^wm>A)y5xPLu+bo)RRq~bA^*jdmeK}&f(dEqNP0)ZAs{ab_V^;7m#YU zKW&#>C*27$Qg%2egQ?NHTllAn0EadZwYAZD%Yphti@rvqzKu<@&&}ooG&85HWxws3 z3vyzTY-i49bc36}%RIQ=KUxBfqF9nz(> zTp0c83<0{(P>8z~fp#1%31?!`&zcN&n4Q@=QK&mT@oY)RE84KIOIdcj>aXYq71V&q zlqv$#vdtr&hXK7s)6!=$gQiN2&zi`P4Z{95(2B{k!S|;RYDyhX5Q)MkFc4c_!j^Lw zqv0)G0K1@){aoVVMDI0qF0jY5GGRPGk+(Vuw$oqN(5GIFz1S7e>JJLZaq`1HhxrV5 zJis9j1M>tF`Mx^8SQBtLDFg8k>#jwDiQUe>J7i$h6?Qdp=^?yZq89b|Q5_W}e`^L< zstmRr-|XvzB~P&AE-8MyV0*?n{G6$MeMQMGRJ%8)uIuD6qJ;33Jr^;IVj@-14!Gr< z`N^*N59jtpC*V~ZgWd?_>BfBr66S<^;tKg>E1wYlQ;#D_vT%+yjN)_t(ot z9_?0#%5TixwHUm8YpOYjEAim>>(%&aDZk#=-bYk^_jLcJC(?WKDFJXtGf{|lIu`oI z$Z421PFie|Xn4w+TLo+*?c|?>0qtU!{Jbw~@GNGs`9N1}-D63Nsjqm)7H=+h^(x=CShwVK0wuOB)Oc|Lr~9%Q$4_^QzZu2h&JAew#WY3_KLw5;obKJJR|I^#m8BEC4bR8oPX=wbKfwKT-{F&gWzkTaLz2@zOM zSMGuijR=uWK7PZ__9m*B1#&Q%WdOX?)~X2BlNWde7=sDdD?BcVNqJ=0p@6A>bM2WO zew>#L?g+S>^>F(P3QEwhPjOgi*wlNiZC)}MM!#s)ugV2o=@+BOzu$1s>iN8AT`g}= z-6o($Ck74B_`7g2-Ok)>7GNzIo za?8^2oamL`n?*Zcqt73@3v=7+6I}1&)oCD@HAa9=SuWRc_r=Fj94w!tH3?joEq?DY zGXfjg&k7dv_5SWq{pRF97>zKmupU-DYIHAxP`b<#UZORrj|%Jhuz$aCK4tOajz}%$ z(2?WcIXzA-kGR#Eb)Ye-DYL^dZ^6KVb{D;Bm}_fxuPdz)dtN|CeBYR-Pn{O@m!KP^ z1WdHSh|7oi#vpZj!CQYk_Xn!LU)g-i1YfT6k=neYCsnU`?ej zz?~!2?s@ZY%b|E|U9_ItQFH)|Kbg$MK;N2anX5J0O8>m^^n6+K$_o)e4eJ=TeDDX^ zKwX{p8Qv~LDU+7m^L!gk*GkF6NK;)XYx6Lg``ba{`tPk~J-)|8o6^tI?wOP%$ z0=coNoB~T2S_nFC<#kHl1|EuhJ<;5UfSv1HW@y>BBLU6^xbf~?*hu$X4)1uEJHdVx z7qhNdXn};1w-J}v>x9X(CdG2{fB3_Mk3z5C$sq2rTxxS#9SH~8Z%h!irs`~b4oF|A zO*-6Tm6ZD;I|Yy1>PHvqZ))_a2VL=rC8VY2@PmJfgVh8%a~bOF`~mNB7F_ukk2C+=B>7|g2Q zld49ewxJ$sxs?~0o`{t>Y%NDQ}5>j&Ry{_n;IT;0TB9L?$#x^ zT0g!%yXI{YwmSv!P`?=dLRbW*IOY1FKi&H`oVGto2dV@Q<6^#EAS<(FNr?geI@ zIy+h0EgNWb35p@mjJUr(tprH=>i89+AQ5(b{4MjW%*FHaA0N0CXQS3YmI$Q#XfNX6|8O-`$Y-*ri1*0<*lTu72_QQLLiKT)%T^E4 zj%H^Z*dDGXF?x~-&F=S?(s0q)#%$A`DkZH1b9UDwJHW+%=r3Gn4||)wF1njVd4w~k zI|mOxO-5%aEW)4dc-Ok-i|eV;_#}pqiD&Hw!rd&=j%RpIO)EfP;7GC)e0ID~$okuA zu#uEoAqvn&1AYI{tSOyp&!QwWQK{pb-=r+phTwRA1Uhn!|sA>sw9sB zvSUA~uTB6ii92hzSK3Fp%BX`-3c1_)u=lNWe^Pf&4P|-qd)(n*D`BNik<$G|8uJ{{ z7a-Li{GZS7iFvqXd~uXeH)<^iEh3cat4UT%jFa;s6G0m*gr!o!LLla;57{c^Bbtbg zZspZMnZ~QJVVCP~z5$6;_f>SA0$%p-A?K8W1SCjo>9l~=<;9}6Ws~a}U|ags++faZ zTF%yA@Et+(=bDefxL(E=lJp8Vy{3PHB{;pQQmhqrSBPJ{`nquglJB)__UN7-yj(po zBgO@=vTnuunwbE@0L&^a`*`i9;42xpMB|krf z|Gg!X-0$!DIPK92d?fd{M@qjZ(($VH^w%OOdR9n$wS8}@J^WR<)(1OLKw3hOG=N5fAY>!7bAZRrr02L0*slU$ znj$!7c`{7vw0|VY-<(PWPoWLI6y9+7DLkX}Px189a6+LFX@y$mA@^_YxO&+W#`>vR z(1zb28vhxVth_Q%yNc;%2!Fum%hQ7zoiLTJgMh0oYf8qia5t--dx4balLdjp2c zW9GMg-FN)9zdmYdJ=~o+2x;VOWpS66&$MhK8j1xUgh|g)2sM4!@e7?f!g?!HTB{$a zR%WWOZi8;LcC=m`71w}C_Yb-r56j_^SkS*a$Me5;>-!Zrb!$xs;UYNqgZ@XC|5%i% znUaG4(adGk%E4T9K~=*EQn$$4ilXVP38^>EM>b*Wr=(-!&TMR%Wnkl?xqGXfYZR9U z(y;Dven7K#>TfZLL9(C8KbfJ{3z8kn(HMj}bP-O#FD`8HM8DPRtT|xmFu|3UkU(CQ zeljc)or70i|7PfJ5?F1Rkyr&_=$OQ8%LUw{YGV{2Kewpc&0_s?zpTgcnd$2pmo=&)5ZRkCw&2m%sqxcH?kEZW63jcPpMo%b)e^c zxnH@<3l;KQ)~XRI#Hj48%BdPrX)h{Npm@gQJ#YZK&nQO@J_Q{1o_vvn0R*!f zzzNKq-RjtLtPjhoTA)h)1A7!TIzczcvte;`P<76SluVIdV!>@{S`w0hj z`MwscZ7B`2E_m*Cij_KSuUS<6L!b!8-u3Brkf`G0&t^KnQX)DOMSST9HWoj{TxGgq zrW{wZ^nV%hV>1c-eP87`=(e4NklO3otA2CT^rZxkAiQyifO?IMwPE$$dpK(q-k06( zG>eqMb1%e6v|z3jIt^xB`?D_N;-kiTld?n;Bu@>)P(0{!+hR?KkD-BaXInecce z;sk}O^}j=l?Mu$-+84f?wF-5dDJ2a^LWrQTZjv|pryR|C)A1ADTx=_aa@)jp2+lWq zRJ)8VmJ7u+$5+3waopZ18`V&(Fx4-=>!~1jJG=HR+4rL?&PHair=vlg^a{1Y0>c*9 zXM9C5bw1l}l?E_p6nUXONyO*`4do66fI%ftbf+;ftkFj z)?8C{HRi(qVkgf8Njk}@{8DMWlC`sSJ8*FyWvq%8?p+S0G%^*<$eg3`yE5a}`%fr2 zKg@y82T(Vbgk&?bGpfa0%0b$1{)JMA!JzqNk>UIiZwX_LTkA3m=bkG@gyi;s@yAQD z{wGd!EI~qNnQZ3u_A5+Aa{R&@T-zn>Vz4|Srx?AGgi=#Xm{^5zG4`Zt>fx2p$Wp+( z^EQ#0!XdZ2uD*wPpph->%cqP5~9!!Ol@(aCj4jV}ZqZ55IB^F)rWnZc+*=o)ZD*P4Os} zZgsYGmBDohUhR(zzZ(hr8;PUz-oC{Bp--~tZ9SNdBg<{rn4Fy!s%g0f=gD6cWcP7m zHBpetgQ|ioPB)5qY9X%2(f<5cW{4Q;a_wCk4%n{s`f5NP*VT_!xJA3)-DBpKO&mVk zn>#_t@slb36jZd;ic?^`TIpKN)y1VOMliKw4t+6PD}6CxgB$070XU!x`tFAv@U6?v zr0|GauJkFlGqFUZ-kvxYMyC?X~ zqNjXq?yjL&-G@w8mNj)lzE|3)a=CNt*rIJDm*@uY&E}!lQ2SZvfdbQrqF~rNJ@<9v z8{9c)8bF)wy|*gy?Sj_)do=5`D)RlvG2@IkSrZYD@UPTj&5^r#%! zUx9pGQO%=20Lp-GvOs} zo-g1CT#mg>FVod7KX!f5f*d(C@&uB;+)bPWFB|}PtH0{hP?}gR^Y)y(d5BWz%3Q&a z0b1wG9{H;)4xzpM(qh8bcJLl*p`(%@g2(wB1+t7!58{0huqheokw!p?t!?y~f1q%y z63B~hBJp0R&N+9C(9)Xag_!{sqH0%CR^WRF{F@3(?A@rzdpfveaC}Jakzg{n*dwpW z-?)>!&iNg1uE~Cxrh#}{)UVO$*`kZ#gpo`D#kRuBj`iYp&wTqcuT=k_`cp((Fb~!f z=Ip&?Jk Date: Mon, 17 Jan 2022 10:46:40 +0800 Subject: [PATCH 30/39] Update package_push_github.yml --- .github/workflows/package_push_github.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package_push_github.yml b/.github/workflows/package_push_github.yml index d49406e95..6772a8b8f 100644 --- a/.github/workflows/package_push_github.yml +++ b/.github/workflows/package_push_github.yml @@ -1,4 +1,4 @@ -name: Packege CI +name: Nuget Push Github on: push: branches: [ develop ] From e08b2f762164515f05ba751188fd2c94bad301af Mon Sep 17 00:00:00 2001 From: PollosD <55781685+PollosD@users.noreply.github.com> Date: Mon, 17 Jan 2022 10:47:57 +0800 Subject: [PATCH 31/39] Update package_push_nuget.org.yml --- .github/workflows/package_push_nuget.org.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package_push_nuget.org.yml b/.github/workflows/package_push_nuget.org.yml index 05cd6d9e6..787251510 100644 --- a/.github/workflows/package_push_nuget.org.yml +++ b/.github/workflows/package_push_nuget.org.yml @@ -1,4 +1,4 @@ -name: Packege CI +name: Package Push Nuget on: push: branches: [ develop ] From 37dc4015c937c2e69fb95d92530298e7c8cbcd35 Mon Sep 17 00:00:00 2001 From: PollosD <55781685+PollosD@users.noreply.github.com> Date: Mon, 17 Jan 2022 11:01:31 +0800 Subject: [PATCH 32/39] Update nuget.config --- nuget.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nuget.config b/nuget.config index eaf63190b..44c937594 100644 --- a/nuget.config +++ b/nuget.config @@ -6,6 +6,6 @@ - + - \ No newline at end of file + From e00c5ffd2b4f8c91ae91f443a426079f382f0b4e Mon Sep 17 00:00:00 2001 From: PollosD <55781685+PollosD@users.noreply.github.com> Date: Mon, 17 Jan 2022 11:06:36 +0800 Subject: [PATCH 33/39] Update nuget.config --- nuget.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nuget.config b/nuget.config index 44c937594..265b484f3 100644 --- a/nuget.config +++ b/nuget.config @@ -5,7 +5,7 @@ - - + + From 30957eb739ef917e88f5b34e0be9695d5e01e59f Mon Sep 17 00:00:00 2001 From: PollosD <55781685+PollosD@users.noreply.github.com> Date: Mon, 17 Jan 2022 11:13:45 +0800 Subject: [PATCH 34/39] Update package_push_nuget.org.yml --- .github/workflows/package_push_nuget.org.yml | 29 +++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/.github/workflows/package_push_nuget.org.yml b/.github/workflows/package_push_nuget.org.yml index 787251510..32f3e3493 100644 --- a/.github/workflows/package_push_nuget.org.yml +++ b/.github/workflows/package_push_nuget.org.yml @@ -1,9 +1,12 @@ name: Package Push Nuget on: - push: - branches: [ develop ] - pull_request: - branches: [ develop ] + create: + ref_type: [ tags ] + # push: + # branches: [ develop ] + # pull_request: + # branches: [ develop ] + workflow_dispatch: jobs: packeg-build: @@ -14,28 +17,34 @@ jobs: # os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest] steps: + - name: git pull uses: actions/checkout@v2 + - name: run a one-line script run: env + - name: setting dotnet version uses: actions/setup-dotnet@v1 with: dotnet-version: '6.0.x' include-prerelease: true + - name: restore run: dotnet restore + - name: build run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true + - name: test run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[*.Tests]*" + - name: codecov uses: codecov/codecov-action@v1 + + - name: pack + run: dotnet pack --include-symbols -p:PackageVersion=0.0.$GITHUB_RUN_ID + - name: package push - run: | - env - echo "------------------------------------------------------" - ls - dotnet pack --include-symbols -p:PackageVersion=0.0.$GITHUB_RUN_ID - dotnet nuget push "**/*.symbols.nupkg" -k ${{secrets.NUGET_TOKEN}} -s https://api.nuget.org/v3/index.json + run: dotnet nuget push "**/*.symbols.nupkg" -k ${{secrets.NUGET_TOKEN}} -s https://api.nuget.org/v3/index.json From b12cc2221eb73f926fcb8bf59a6e371dc2227c7c Mon Sep 17 00:00:00 2001 From: PollosD <55781685+PollosD@users.noreply.github.com> Date: Mon, 17 Jan 2022 11:14:16 +0800 Subject: [PATCH 35/39] Update package_push_github.yml --- .github/workflows/package_push_github.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package_push_github.yml b/.github/workflows/package_push_github.yml index 6772a8b8f..f60287d96 100644 --- a/.github/workflows/package_push_github.yml +++ b/.github/workflows/package_push_github.yml @@ -1,4 +1,4 @@ -name: Nuget Push Github +name: Package Push Github on: push: branches: [ develop ] From a1e3dc5cb7930c023ddc86e55e517422fe216a7c Mon Sep 17 00:00:00 2001 From: PollosD <55781685+PollosD@users.noreply.github.com> Date: Mon, 17 Jan 2022 11:19:22 +0800 Subject: [PATCH 36/39] Update nuget.config --- nuget.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nuget.config b/nuget.config index 265b484f3..3baa31717 100644 --- a/nuget.config +++ b/nuget.config @@ -5,7 +5,7 @@ - - + + From 4c4543c344e487cd09021f7c0200119261ea60e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=AC=E9=9B=A8=E5=A3=B0?= Date: Fri, 21 Jan 2022 09:16:08 +0800 Subject: [PATCH 37/39] chore: Modify the introduction of Uow usage documentation (#3) * chore: Modify the introduction of Uow usage documentation * chore: Remove invalid comments --- README.md | 10 ++++++---- README.zh-CN.md | 7 ++++--- src/Data/MASA.Contrib.Data.Contracts.EF/README.md | 7 ++++--- .../MASA.Contrib.Data.Contracts.EF/README.zh-CN.md | 7 ++++--- src/Data/MASA.Contrib.Data.UoW.EF/README.md | 7 ++++--- src/Data/MASA.Contrib.Data.UoW.EF/README.zh-CN.md | 7 ++++--- 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 770fcf46e..5ee9ed804 100644 --- a/README.md +++ b/README.md @@ -118,12 +118,14 @@ Install-Package MASA.Contrib.Data.Contracts.EF ``` ```C# -builder.Services - .AddUoW(dbOptions => +builder.Services.AddEventBus(options => { + options.UseUoW(dbOptions => { dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"); - dbOptions.UseSoftDelete(builder.Services);//Start soft delete - }) + dbOptions.UseSoftDelete(builder.Services); + }); +}); + ``` > When the entity inherits ISoftware and is deleted, change the delete state to the modified state, and cooperate with the custom Remove operation to achieve soft deletion diff --git a/README.zh-CN.md b/README.zh-CN.md index 9a0265a83..7021d5fc1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -118,12 +118,13 @@ Install-Package MASA.Contrib.Data.Contracts.EF ``` ```C# -builder.Services - .AddUoW(dbOptions => +builder.Services.AddEventBus(options => { + options.UseUoW(dbOptions => { dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"); dbOptions.UseSoftDelete(builder.Services);//启动软删除 - }) + }); +}); ``` > 当实体继承ISoftware,且被删除时,将删除状态改为修改状态,并配合自定义Remove操作,实现软删除 diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/README.md b/src/Data/MASA.Contrib.Data.Contracts.EF/README.md index 9d0a41218..350d71970 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/README.md +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/README.md @@ -10,12 +10,13 @@ Install-Package MASA.Contrib.Data.Contracts.EF ``` ```C# -builder.Services - .AddUoW(dbOptions => +builder.Services.AddEventBus(options => { + options.UseUoW(dbOptions => { dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"); dbOptions.UseSoftDelete(builder.Services); - }) + }); +}); ``` > When the entity inherits ISoftware and is deleted, change the delete state to the modified state, and cooperate with the custom Remove operation to achieve soft deletion diff --git a/src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-CN.md b/src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-CN.md index 8ec6e7b50..e31e3f3f0 100644 --- a/src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-CN.md +++ b/src/Data/MASA.Contrib.Data.Contracts.EF/README.zh-CN.md @@ -10,12 +10,13 @@ Install-Package MASA.Contrib.Data.Contracts.EF ``` ```C# -builder.Services - .AddUoW(dbOptions => +builder.Services.AddEventBus(options => { + options.UseUoW(dbOptions => { dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"); dbOptions.UseSoftDelete(builder.Services);//启动软删除 - }) + }); +}); ``` > 当实体继承ISoftware,且被删除时,将删除状态改为修改状态,并配合自定义Remove操作,实现软删除 diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/README.md b/src/Data/MASA.Contrib.Data.UoW.EF/README.md index b7f924b4e..efd89e947 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/README.md +++ b/src/Data/MASA.Contrib.Data.UoW.EF/README.md @@ -10,10 +10,11 @@ Install-Package MASA.Contrib.Data.Contracts.EF ``` ```C# -builder.Services - .AddUoW(dbOptions => +builder.Services.AddEventBus(options => { + options.UseUoW(dbOptions => { dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"); - }) + }); +}); ``` diff --git a/src/Data/MASA.Contrib.Data.UoW.EF/README.zh-CN.md b/src/Data/MASA.Contrib.Data.UoW.EF/README.zh-CN.md index c2f15f5b3..316b94e90 100644 --- a/src/Data/MASA.Contrib.Data.UoW.EF/README.zh-CN.md +++ b/src/Data/MASA.Contrib.Data.UoW.EF/README.zh-CN.md @@ -10,10 +10,11 @@ Install-Package MASA.Contrib.Data.Contracts.EF ``` ```C# -builder.Services - .AddUoW(dbOptions => +builder.Services.AddEventBus(options => { + options.UseUoW(dbOptions => { dbOptions.UseSqlServer("server=localhost;uid=sa;pwd=P@ssw0rd;database=identity"); - }) + }); +}); ``` From 52e4573150bee2f7dc674d55ecbb5bb153267f33 Mon Sep 17 00:00:00 2001 From: PollosD <55781685+PollosD@users.noreply.github.com> Date: Mon, 24 Jan 2022 10:17:56 +0800 Subject: [PATCH 38/39] Update package_push_github.yml --- .github/workflows/package_push_github.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package_push_github.yml b/.github/workflows/package_push_github.yml index f60287d96..a2b9c37a2 100644 --- a/.github/workflows/package_push_github.yml +++ b/.github/workflows/package_push_github.yml @@ -36,4 +36,4 @@ jobs: - name: package push run: | - dotnet nuget push "**/*.symbols.nupkg" --api-key ${{secrets.PACKAGE_NUGET_GITHUB}} --source "github" + dotnet nuget push "**/*.symbols.nupkg" --api-key ${{secrets.PACKAGE_NUGET_GITHUB}} --source https://nuget.pkg.github.com/masastack/index.json From 85b0378f2681a309c2f60edf9f388ce3950234b0 Mon Sep 17 00:00:00 2001 From: PollosD <55781685+PollosD@users.noreply.github.com> Date: Mon, 24 Jan 2022 10:19:06 +0800 Subject: [PATCH 39/39] Update nuget.config --- nuget.config | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/nuget.config b/nuget.config index 3baa31717..6873eb959 100644 --- a/nuget.config +++ b/nuget.config @@ -1,11 +1,6 @@ - + - - - - -