diff --git a/CHANGELOG.md b/CHANGELOG.md index dc7c336df..eabc84a3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,16 @@ Represents the **NuGet** versions. +## v5.12.4 +- *Fixed:* Fixes to the `Template` solution to improve the initial `dotnet new beef` experience, including sample Reference Data API tests. +- *Fixed:* Upgraded `CoreEx` (`v3.18.0`) to include all related fixes and improvements. +- *Fixed:* The `EntityManager_cs.hbs` template has been updated to account for the `CoreEx.Validation.ValueValidator` fixes. + ## v5.12.3 -- *Fixed:* Fixes to the Template solution to improve the initial `dotnet new beef` experience with respect to API health endpoint. +- *Fixed:* Fixes to the `Template` solution to improve the initial `dotnet new beef` experience with respect to API health endpoint. ## v5.12.2 -- *Fixed:* Fixes to the Template solution to improve the initial `dotnet new beef` experience. +- *Fixed:* Fixes to the `Template` solution to improve the initial `dotnet new beef` experience. ## v5.12.1 - *Fixed:* Upgraded `CoreEx` (`v3.15.0`) to include all related fixes and improvements. @@ -25,7 +30,7 @@ Represents the **NuGet** versions. ## v5.10.0 - *Enhancement:* Added [PostgreSQL](https://www.postgresql.org/) database support: - Leverages both `CoreEx.Database.Postgres` (runtime) and `DbEx.Postgres` (migration) packages; encapsulates the `Npgsql` package. - - The `Npgsql.EntityFrameworkCore.PostgreSQL` packages is used for the entity framework provider. + - The `Npgsql.EntityFrameworkCore.PostgreSQL` package is used for the entity framework provider. - The `dotnet new beef` template updated to support new `datasource` option of `postgres`. - *Enhancement:* Additional improvements for data migration and code-generation, including `SqlServer` and `MySql`, as a result of `DbEx` (`v2.5.0`) enhancements. diff --git a/Common.targets b/Common.targets index 59104f8ba..89989bbdf 100644 --- a/Common.targets +++ b/Common.targets @@ -1,6 +1,6 @@ - 5.12.3 + 5.12.4 preview Avanade Avanade diff --git a/samples/Cdr.Banking/Cdr.Banking.Api/Cdr.Banking.Api.csproj b/samples/Cdr.Banking/Cdr.Banking.Api/Cdr.Banking.Api.csproj index b9d9415c2..74f2a19ce 100644 --- a/samples/Cdr.Banking/Cdr.Banking.Api/Cdr.Banking.Api.csproj +++ b/samples/Cdr.Banking/Cdr.Banking.Api/Cdr.Banking.Api.csproj @@ -5,7 +5,7 @@ true - + diff --git a/samples/Cdr.Banking/Cdr.Banking.Business/Cdr.Banking.Business.csproj b/samples/Cdr.Banking/Cdr.Banking.Business/Cdr.Banking.Business.csproj index 06dc5cf6f..454b4cd0d 100644 --- a/samples/Cdr.Banking/Cdr.Banking.Business/Cdr.Banking.Business.csproj +++ b/samples/Cdr.Banking/Cdr.Banking.Business/Cdr.Banking.Business.csproj @@ -11,8 +11,8 @@ - - - + + + \ No newline at end of file diff --git a/samples/Cdr.Banking/Cdr.Banking.Business/Generated/AccountManager.cs b/samples/Cdr.Banking/Cdr.Banking.Business/Generated/AccountManager.cs index 5781a3323..332d6b26f 100644 --- a/samples/Cdr.Banking/Cdr.Banking.Business/Generated/AccountManager.cs +++ b/samples/Cdr.Banking/Cdr.Banking.Business/Generated/AccountManager.cs @@ -24,7 +24,7 @@ public AccountManager(IAccountDataSvc dataService) public Task> GetAccountsAsync(AccountArgs? args, PagingArgs? paging) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go() - .ValidatesAsync(args, v => v.Entity().With(), cancellationToken: ct) + .ValidatesAsync(args, vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(() => _dataService.GetAccountsAsync(args, paging)); }, InvokerArgs.Read); diff --git a/samples/Cdr.Banking/Cdr.Banking.Business/Generated/TransactionManager.cs b/samples/Cdr.Banking/Cdr.Banking.Business/Generated/TransactionManager.cs index 05c9e886a..20a54cd9c 100644 --- a/samples/Cdr.Banking/Cdr.Banking.Business/Generated/TransactionManager.cs +++ b/samples/Cdr.Banking/Cdr.Banking.Business/Generated/TransactionManager.cs @@ -25,8 +25,8 @@ public Task> GetTransactionsAsync(string? ac { return Result.Go().Requires(accountId) .ValidateAsync(() => MultiValidator.Create() - .Add(accountId.Validate().Common(Validators.AccountId)) - .Add(args.Validate().Entity().With())) + .Add(accountId.Validate().Configure(vc => vc.Common(Validators.AccountId))) + .Add(args.Validate().Configure(vc => vc.Entity().With())), cancellationToken: ct) .ThenAsAsync(() => _dataService.GetTransactionsAsync(accountId, args, paging)); }, InvokerArgs.Read); } \ No newline at end of file diff --git a/samples/Cdr.Banking/Cdr.Banking.Business/Validation/Validators.cs b/samples/Cdr.Banking/Cdr.Banking.Business/Validation/Validators.cs index b88e31906..5e58abb99 100644 --- a/samples/Cdr.Banking/Cdr.Banking.Business/Validation/Validators.cs +++ b/samples/Cdr.Banking/Cdr.Banking.Business/Validation/Validators.cs @@ -8,6 +8,6 @@ public static class Validators /// /// Validates an value to ensure that the executing user is authorized to access. /// - public static CommonValidator AccountId => CommonValidator.Create(v => v.Custom(ctx + public static CommonValidator AccountId => CommonValidator.Create(v => v.Custom(ctx => Result.Go().When(() => ctx.Value == null || !ExecutionContext.Current.Accounts.Contains(ctx.Value), () => Result.AuthorizationError()))); } \ No newline at end of file diff --git a/samples/Cdr.Banking/Cdr.Banking.Common/Cdr.Banking.Common.csproj b/samples/Cdr.Banking/Cdr.Banking.Common/Cdr.Banking.Common.csproj index 96c7fac1e..b170a6150 100644 --- a/samples/Cdr.Banking/Cdr.Banking.Common/Cdr.Banking.Common.csproj +++ b/samples/Cdr.Banking/Cdr.Banking.Common/Cdr.Banking.Common.csproj @@ -8,6 +8,6 @@ - + \ No newline at end of file diff --git a/samples/Cdr.Banking/Cdr.Banking.Test/Cdr.Banking.Test.csproj b/samples/Cdr.Banking/Cdr.Banking.Test/Cdr.Banking.Test.csproj index 7399f049a..13826eb86 100644 --- a/samples/Cdr.Banking/Cdr.Banking.Test/Cdr.Banking.Test.csproj +++ b/samples/Cdr.Banking/Cdr.Banking.Test/Cdr.Banking.Test.csproj @@ -39,7 +39,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/samples/Demo/Beef.Demo.Api/Beef.Demo.Api.csproj b/samples/Demo/Beef.Demo.Api/Beef.Demo.Api.csproj index 39294d440..9d32a54ec 100644 --- a/samples/Demo/Beef.Demo.Api/Beef.Demo.Api.csproj +++ b/samples/Demo/Beef.Demo.Api/Beef.Demo.Api.csproj @@ -12,7 +12,7 @@ - + diff --git a/samples/Demo/Beef.Demo.Business/Beef.Demo.Business.csproj b/samples/Demo/Beef.Demo.Business/Beef.Demo.Business.csproj index 6b856460b..266e8c327 100644 --- a/samples/Demo/Beef.Demo.Business/Beef.Demo.Business.csproj +++ b/samples/Demo/Beef.Demo.Business/Beef.Demo.Business.csproj @@ -16,14 +16,14 @@ - - - - - - - - + + + + + + + + diff --git a/samples/Demo/Beef.Demo.Business/Generated/ContactManager.cs b/samples/Demo/Beef.Demo.Business/Generated/ContactManager.cs index 0f5eecb2b..037f62b44 100644 --- a/samples/Demo/Beef.Demo.Business/Generated/ContactManager.cs +++ b/samples/Demo/Beef.Demo.Business/Generated/ContactManager.cs @@ -32,14 +32,14 @@ public Task GetAllAsync() => ManagerInvoker.Current.Inv /// public Task GetAsync(Guid id) => ManagerInvoker.Current.InvokeAsync(this, async (_, ct) => { - await id.Validate().Mandatory().ValidateAsync(true).ConfigureAwait(false); + await id.Validate().Configure(vc => vc.Mandatory()).ValidateAsync(true).ConfigureAwait(false); return await _dataService.GetAsync(id).ConfigureAwait(false); }, InvokerArgs.Read); /// public Task CreateAsync(Contact value) => ManagerInvoker.Current.InvokeAsync(this, async (_, ct) => { - await value.Validate().Mandatory().Entity().With().ValidateAsync(true).ConfigureAwait(false); + await value.Validate().Configure(vc => vc.Mandatory().Entity().With()).ValidateAsync(true).ConfigureAwait(false); return await _dataService.CreateAsync(value).ConfigureAwait(false); }, InvokerArgs.Create); @@ -48,8 +48,8 @@ public Task UpdateAsync(Contact value, Guid id) => ManagerInvoker.Curre { value.Required().Id = id; await MultiValidator.Create() - .Add(id.Validate().Mandatory()) - .Add(value.Validate().Mandatory().Entity().With()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) + .Add(value.Validate().Configure(vc => vc.Mandatory().Entity().With())) .ValidateAsync(true).ConfigureAwait(false); return await _dataService.UpdateAsync(value).ConfigureAwait(false); @@ -58,7 +58,7 @@ await MultiValidator.Create() /// public Task DeleteAsync(Guid id) => ManagerInvoker.Current.InvokeAsync(this, async (_, ct) => { - await id.Validate().Mandatory().ValidateAsync(true).ConfigureAwait(false); + await id.Validate().Configure(vc => vc.Mandatory()).ValidateAsync(true).ConfigureAwait(false); await _dataService.DeleteAsync(id).ConfigureAwait(false); }, InvokerArgs.Delete); diff --git a/samples/Demo/Beef.Demo.Business/Generated/PersonManager.cs b/samples/Demo/Beef.Demo.Business/Generated/PersonManager.cs index dde0d98b0..f68c89597 100644 --- a/samples/Demo/Beef.Demo.Business/Generated/PersonManager.cs +++ b/samples/Demo/Beef.Demo.Business/Generated/PersonManager.cs @@ -176,7 +176,7 @@ public Task CreateAsync(Person value) => ManagerInvoker.Current.InvokeAs Cleaner.CleanUp(value); await Invoker.InvokeAsync(_createOnPreValidateAsync?.Invoke(value)).ConfigureAwait(false); await MultiValidator.Create() - .Add(value.Validate().Mandatory().Entity().With()) + .Add(value.Validate().Configure(vc => vc.Mandatory().Entity().With())) .Additional(mv => _createOnValidate?.Invoke(mv, value)) .ValidateAsync(true).ConfigureAwait(false); @@ -192,7 +192,7 @@ public Task DeleteAsync(Guid id) => ManagerInvoker.Current.InvokeAsync(this, asy Cleaner.CleanUp(id); await Invoker.InvokeAsync(_deleteOnPreValidateAsync?.Invoke(id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) .Additional(mv => _deleteOnValidate?.Invoke(mv, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -206,7 +206,7 @@ await MultiValidator.Create() { Cleaner.CleanUp(id); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) .ValidateAsync(true).ConfigureAwait(false); return Cleaner.Clean(await _dataService.GetAsync(id).ConfigureAwait(false)); @@ -218,7 +218,7 @@ await MultiValidator.Create() Cleaner.CleanUp(id); await Invoker.InvokeAsync(_getExOnPreValidateAsync?.Invoke(id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) .Additional(mv => _getExOnValidate?.Invoke(mv, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -235,8 +235,8 @@ public Task UpdateAsync(Person value, Guid id) => ManagerInvoker.Current Cleaner.CleanUp(value); await Invoker.InvokeAsync(_updateOnPreValidateAsync?.Invoke(value, id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) - .Add(value.Validate().Mandatory().Entity().With()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) + .Add(value.Validate().Configure(vc => vc.Mandatory().Entity().With())) .Additional(mv => _updateOnValidate?.Invoke(mv, value, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -253,8 +253,8 @@ public Task UpdateWithRollbackAsync(Person value, Guid id) => ManagerInv Cleaner.CleanUp(value); await Invoker.InvokeAsync(_updateWithRollbackOnPreValidateAsync?.Invoke(value, id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) - .Add(value.Validate().Mandatory().Entity().With()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) + .Add(value.Validate().Configure(vc => vc.Mandatory().Entity().With())) .Additional(mv => _updateWithRollbackOnValidate?.Invoke(mv, value, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -298,7 +298,7 @@ public Task GetByArgsAsync(PersonArgs? args, PagingArgs? Cleaner.CleanUp(args); await Invoker.InvokeAsync(_getByArgsOnPreValidateAsync?.Invoke(args, paging)).ConfigureAwait(false); await MultiValidator.Create() - .Add(args.Validate().Entity().With()) + .Add(args.Validate().Configure(vc => vc.Entity().With())) .Additional(mv => _getByArgsOnValidate?.Invoke(mv, args, paging)) .ValidateAsync(true).ConfigureAwait(false); @@ -314,7 +314,7 @@ public Task GetDetailByArgsAsync(PersonArgs? args, Cleaner.CleanUp(args); await Invoker.InvokeAsync(_getDetailByArgsOnPreValidateAsync?.Invoke(args, paging)).ConfigureAwait(false); await MultiValidator.Create() - .Add(args.Validate().Entity().With()) + .Add(args.Validate().Configure(vc => vc.Entity().With())) .Additional(mv => _getDetailByArgsOnValidate?.Invoke(mv, args, paging)) .ValidateAsync(true).ConfigureAwait(false); @@ -330,8 +330,8 @@ public Task MergeAsync(Guid fromId, Guid toId) => ManagerInvoker.Current Cleaner.CleanUp(fromId, toId); await Invoker.InvokeAsync(_mergeOnPreValidateAsync?.Invoke(fromId, toId)).ConfigureAwait(false); await MultiValidator.Create() - .Add(fromId.Validate().Mandatory()) - .Add(toId.Validate().Mandatory().CompareValue(CompareOperator.NotEqual, fromId, nameof(fromId).ToSentenceCase()!)) + .Add(fromId.Validate().Configure(vc => vc.Mandatory())) + .Add(toId.Validate().Configure(vc => vc.Mandatory().CompareValue(CompareOperator.NotEqual, fromId, nameof(fromId).ToSentenceCase()!))) .Additional(mv => _mergeOnValidate?.Invoke(mv, fromId, toId)) .ValidateAsync(true).ConfigureAwait(false); @@ -389,7 +389,7 @@ await MultiValidator.Create() Cleaner.CleanUp(id); await Invoker.InvokeAsync(_getDetailOnPreValidateAsync?.Invoke(id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) .Additional(mv => _getDetailOnValidate?.Invoke(mv, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -406,8 +406,8 @@ public Task UpdateDetailAsync(PersonDetail value, Guid id) => Mana Cleaner.CleanUp(value); await Invoker.InvokeAsync(_updateDetailOnPreValidateAsync?.Invoke(value, id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) - .Add(value.Validate().Mandatory().Entity().With()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) + .Add(value.Validate().Configure(vc => vc.Mandatory().Entity().With())) .Additional(mv => _updateDetailOnValidate?.Invoke(mv, value, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -470,7 +470,7 @@ public Task EventPublishNoSendAsync(Person value) => ManagerInvoker.Curr Cleaner.CleanUp(value.Required()); await Invoker.InvokeAsync(_eventPublishNoSendOnPreValidateAsync?.Invoke(value)).ConfigureAwait(false); await MultiValidator.Create() - .Add(value.Validate().Mandatory().Entity().With()) + .Add(value.Validate().Configure(vc => vc.Mandatory().Entity().With())) .Additional(mv => _eventPublishNoSendOnValidate?.Invoke(mv, value)) .ValidateAsync(true).ConfigureAwait(false); @@ -486,7 +486,7 @@ public Task GetByArgsWithEfAsync(PersonArgs? args, Pagin Cleaner.CleanUp(args); await Invoker.InvokeAsync(_getByArgsWithEfOnPreValidateAsync?.Invoke(args, paging)).ConfigureAwait(false); await MultiValidator.Create() - .Add(args.Validate().Entity().With()) + .Add(args.Validate().Configure(vc => vc.Entity().With())) .Additional(mv => _getByArgsWithEfOnValidate?.Invoke(mv, args, paging)) .ValidateAsync(true).ConfigureAwait(false); @@ -515,7 +515,7 @@ public Task InvokeApiViaAgentAsync(Guid id) => ManagerInvoker.Current.In Cleaner.CleanUp(id); await Invoker.InvokeAsync(_invokeApiViaAgentOnPreValidateAsync?.Invoke(id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) .Additional(mv => _invokeApiViaAgentOnValidate?.Invoke(mv, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -531,7 +531,7 @@ public Task ParamCollAsync(AddressCollection? addresses) => ManagerInvoker.Curre Cleaner.CleanUp(addresses); await Invoker.InvokeAsync(_paramCollOnPreValidateAsync?.Invoke(addresses)).ConfigureAwait(false); await MultiValidator.Create() - .Add(addresses.Validate().Entity().With()) + .Add(addresses.Validate().Configure(vc => vc.Entity().With())) .Additional(mv => _paramCollOnValidate?.Invoke(mv, addresses)) .ValidateAsync(true).ConfigureAwait(false); @@ -546,7 +546,7 @@ await MultiValidator.Create() Cleaner.CleanUp(id); await Invoker.InvokeAsync(_getWithEfOnPreValidateAsync?.Invoke(id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) .Additional(mv => _getWithEfOnValidate?.Invoke(mv, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -563,7 +563,7 @@ public Task CreateWithEfAsync(Person value) => ManagerInvoker.Current.In Cleaner.CleanUp(value); await Invoker.InvokeAsync(_createWithEfOnPreValidateAsync?.Invoke(value)).ConfigureAwait(false); await MultiValidator.Create() - .Add(value.Validate().Mandatory().Entity().With()) + .Add(value.Validate().Configure(vc => vc.Mandatory().Entity().With())) .Additional(mv => _createWithEfOnValidate?.Invoke(mv, value)) .ValidateAsync(true).ConfigureAwait(false); @@ -580,8 +580,8 @@ public Task UpdateWithEfAsync(Person value, Guid id) => ManagerInvoker.C Cleaner.CleanUp(value); await Invoker.InvokeAsync(_updateWithEfOnPreValidateAsync?.Invoke(value, id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) - .Add(value.Validate().Mandatory().Entity().With()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) + .Add(value.Validate().Configure(vc => vc.Mandatory().Entity().With())) .Additional(mv => _updateWithEfOnValidate?.Invoke(mv, value, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -597,7 +597,7 @@ public Task DeleteWithEfAsync(Guid id) => ManagerInvoker.Current.InvokeAsync(thi Cleaner.CleanUp(id); await Invoker.InvokeAsync(_deleteWithEfOnPreValidateAsync?.Invoke(id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) .Additional(mv => _deleteWithEfOnValidate?.Invoke(mv, id)) .ValidateAsync(true).ConfigureAwait(false); @@ -612,7 +612,7 @@ public Task GetDocumentationAsync(Guid id) => ManagerInvoker. Cleaner.CleanUp(id); await Invoker.InvokeAsync(_getDocumentationOnPreValidateAsync?.Invoke(id)).ConfigureAwait(false); await MultiValidator.Create() - .Add(id.Validate().Mandatory()) + .Add(id.Validate().Configure(vc => vc.Mandatory())) .Additional(mv => _getDocumentationOnValidate?.Invoke(mv, id)) .ValidateAsync(true).ConfigureAwait(false); diff --git a/samples/Demo/Beef.Demo.Business/Generated/PostalInfoManager.cs b/samples/Demo/Beef.Demo.Business/Generated/PostalInfoManager.cs index d2ca3c9f8..6a96317d4 100644 --- a/samples/Demo/Beef.Demo.Business/Generated/PostalInfoManager.cs +++ b/samples/Demo/Beef.Demo.Business/Generated/PostalInfoManager.cs @@ -28,7 +28,7 @@ public PostalInfoManager(IPostalInfoDataSvc dataService) { return Result.Go().Requires(country).Requires(state).Requires(city) .Then(() => Cleaner.CleanUp(country, state, city)) - .ValidatesAsync(country, v => v.IsValid(), cancellationToken: ct) + .ValidatesAsync(country, vc => vc.IsValid(), cancellationToken: ct) .ThenAsAsync(() => _dataService.GetPostCodesAsync(country, state, city)); }, InvokerArgs.Read); @@ -37,7 +37,7 @@ public Task> CreatePostCodesAsync(PostalInfo value, RefDataNa { return Result.Go(value).Required().Requires(country).Requires(state).Requires(city) .Then(v => Cleaner.CleanUp(v, country, state, city)) - .ValidatesAsync(country, v => v.IsValid(), cancellationToken: ct) + .ValidatesAsync(country, vc => vc.IsValid(), cancellationToken: ct) .ThenAsAsync(v => _dataService.CreatePostCodesAsync(value, country, state, city)); }, InvokerArgs.Create); @@ -46,7 +46,7 @@ public Task> UpdatePostCodesAsync(PostalInfo value, RefDataNa { return Result.Go(value).Required().Requires(country).Requires(state).Requires(city) .Then(v => Cleaner.CleanUp(v, country, state, city)) - .ValidatesAsync(country, v => v.IsValid(), cancellationToken: ct) + .ValidatesAsync(country, vc => vc.IsValid(), cancellationToken: ct) .ThenAsAsync(v => _dataService.UpdatePostCodesAsync(value, country, state, city)); }, InvokerArgs.Update); @@ -55,7 +55,7 @@ public Task DeletePostCodesAsync(RefDataNamespace.Country? country, stri { return Result.Go().Requires(country).Requires(state).Requires(city) .Then(() => Cleaner.CleanUp(country, state, city)) - .ValidatesAsync(country, v => v.IsValid(), cancellationToken: ct) + .ValidatesAsync(country, vc => vc.IsValid(), cancellationToken: ct) .ThenAsync(() => _dataService.DeletePostCodesAsync(country, state, city)); }, InvokerArgs.Delete); } diff --git a/samples/Demo/Beef.Demo.Business/Generated/RobotManager.cs b/samples/Demo/Beef.Demo.Business/Generated/RobotManager.cs index 179c4d2fa..aba5e5b02 100644 --- a/samples/Demo/Beef.Demo.Business/Generated/RobotManager.cs +++ b/samples/Demo/Beef.Demo.Business/Generated/RobotManager.cs @@ -41,7 +41,7 @@ public Task> CreateAsync(Robot value) => ManagerInvoker.Current.In return Result.Go(value).Required() .ThenAsync(async v => v.Id = await _identifierGenerator.GenerateIdentifierAsync().ConfigureAwait(false)) .Then(v => Cleaner.CleanUp(v)) - .ValidateAsync(v => v.Interop(() => FluentValidator.Create().Wrap()), cancellationToken: ct) + .ValidateAsync(vc => vc.Interop(() => FluentValidator.Create().Wrap()), cancellationToken: ct) .ThenAsAsync(v => _dataService.CreateAsync(value)); }, InvokerArgs.Create); @@ -50,7 +50,7 @@ public Task> UpdateAsync(Robot value, Guid id) => ManagerInvoker.C { return Result.Go(value).Required().Requires(id).Then(v => v.Id = id) .Then(v => Cleaner.CleanUp(v)) - .ValidateAsync(v => v.Interop(() => FluentValidator.Create().Wrap()), cancellationToken: ct) + .ValidateAsync(vc => vc.Interop(() => FluentValidator.Create().Wrap()), cancellationToken: ct) .ThenAsAsync(v => _dataService.UpdateAsync(value)); }, InvokerArgs.Update); @@ -67,7 +67,7 @@ public Task> GetByArgsAsync(RobotArgs? args, Pagin { return Result.Go() .Then(() => Cleaner.CleanUp(args)) - .ValidatesAsync(args, v => v.Entity().With(), cancellationToken: ct) + .ValidatesAsync(args, vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(() => _dataService.GetByArgsAsync(args, paging)); }, InvokerArgs.Read); diff --git a/samples/Demo/Beef.Demo.Common/Beef.Demo.Common.csproj b/samples/Demo/Beef.Demo.Common/Beef.Demo.Common.csproj index 5c42f9649..c5055fff6 100644 --- a/samples/Demo/Beef.Demo.Common/Beef.Demo.Common.csproj +++ b/samples/Demo/Beef.Demo.Common/Beef.Demo.Common.csproj @@ -7,7 +7,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/samples/Demo/Beef.Demo.Test/Beef.Demo.Test.csproj b/samples/Demo/Beef.Demo.Test/Beef.Demo.Test.csproj index 8f14e6f8a..8fdad7e86 100644 --- a/samples/Demo/Beef.Demo.Test/Beef.Demo.Test.csproj +++ b/samples/Demo/Beef.Demo.Test/Beef.Demo.Test.csproj @@ -52,7 +52,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/samples/My.Hr/My.Hr.Api/My.Hr.Api.csproj b/samples/My.Hr/My.Hr.Api/My.Hr.Api.csproj index 2314c3752..fb604d330 100644 --- a/samples/My.Hr/My.Hr.Api/My.Hr.Api.csproj +++ b/samples/My.Hr/My.Hr.Api/My.Hr.Api.csproj @@ -5,7 +5,7 @@ true - + diff --git a/samples/My.Hr/My.Hr.Business/Generated/EmployeeManager.cs b/samples/My.Hr/My.Hr.Business/Generated/EmployeeManager.cs index 66d9359e3..5e29a63f4 100644 --- a/samples/My.Hr/My.Hr.Business/Generated/EmployeeManager.cs +++ b/samples/My.Hr/My.Hr.Business/Generated/EmployeeManager.cs @@ -31,7 +31,7 @@ public EmployeeManager(IEmployeeDataSvc dataService) public Task> CreateAsync(Employee value) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required() - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.CreateAsync(value)); }, InvokerArgs.Create); @@ -39,7 +39,7 @@ public Task> CreateAsync(Employee value) => ManagerInvoker.Curr public Task> UpdateAsync(Employee value, Guid id) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required().Requires(id).Then(v => v.Id = id) - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.UpdateAsync(value)); }, InvokerArgs.Update); @@ -47,7 +47,7 @@ public Task> UpdateAsync(Employee value, Guid id) => ManagerInv public Task DeleteAsync(Guid id) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go().Requires(id) - .ValidatesAsync(id, v => v.Common(EmployeeValidator.CanDelete), cancellationToken: ct) + .ValidatesAsync(id, vc => vc.Common(EmployeeValidator.CanDelete), cancellationToken: ct) .ThenAsync(() => _dataService.DeleteAsync(id)); }, InvokerArgs.Delete); @@ -55,7 +55,7 @@ public Task DeleteAsync(Guid id) => ManagerInvoker.Current.InvokeAsync(t public Task> GetByArgsAsync(EmployeeArgs? args, PagingArgs? paging) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go() - .ValidatesAsync(args, v => v.Entity().With(), cancellationToken: ct) + .ValidatesAsync(args, vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(() => _dataService.GetByArgsAsync(args, paging)); }, InvokerArgs.Read); @@ -63,7 +63,7 @@ public Task> GetByArgsAsync(EmployeeArgs? a public Task> TerminateAsync(TerminationDetail value, Guid id) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required() - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.TerminateAsync(value, id)); }, InvokerArgs.Update); } \ No newline at end of file diff --git a/samples/My.Hr/My.Hr.Business/Generated/PerformanceReviewManager.cs b/samples/My.Hr/My.Hr.Business/Generated/PerformanceReviewManager.cs index 63732cee6..86ef76c17 100644 --- a/samples/My.Hr/My.Hr.Business/Generated/PerformanceReviewManager.cs +++ b/samples/My.Hr/My.Hr.Business/Generated/PerformanceReviewManager.cs @@ -38,7 +38,7 @@ public Task> GetByEmployeeIdAsync(Guid public Task> CreateAsync(PerformanceReview value, Guid employeeId) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required().Then(v => v.EmployeeId = employeeId) - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.CreateAsync(value)); }, InvokerArgs.Create); @@ -46,7 +46,7 @@ public Task> CreateAsync(PerformanceReview value, Guid public Task> UpdateAsync(PerformanceReview value, Guid id) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required().Requires(id).Then(v => v.Id = id) - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.UpdateAsync(value)); }, InvokerArgs.Update); diff --git a/samples/My.Hr/My.Hr.Business/My.Hr.Business.csproj b/samples/My.Hr/My.Hr.Business/My.Hr.Business.csproj index db2fc3088..e48aebbb8 100644 --- a/samples/My.Hr/My.Hr.Business/My.Hr.Business.csproj +++ b/samples/My.Hr/My.Hr.Business/My.Hr.Business.csproj @@ -6,10 +6,10 @@ latest - - - - + + + + \ No newline at end of file diff --git a/samples/My.Hr/My.Hr.Common/My.Hr.Common.csproj b/samples/My.Hr/My.Hr.Common/My.Hr.Common.csproj index 06a775642..49951a5f9 100644 --- a/samples/My.Hr/My.Hr.Common/My.Hr.Common.csproj +++ b/samples/My.Hr/My.Hr.Common/My.Hr.Common.csproj @@ -4,6 +4,6 @@ enable - + \ No newline at end of file diff --git a/samples/My.Hr/My.Hr.Test/My.Hr.Test.csproj b/samples/My.Hr/My.Hr.Test/My.Hr.Test.csproj index 7b1464621..ebc621249 100644 --- a/samples/My.Hr/My.Hr.Test/My.Hr.Test.csproj +++ b/samples/My.Hr/My.Hr.Test/My.Hr.Test.csproj @@ -32,7 +32,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -42,7 +42,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/samples/My.Hr/My.Hr.Test/Validators/EmployeeValidatorTest.cs b/samples/My.Hr/My.Hr.Test/Validators/EmployeeValidatorTest.cs index fd5e71061..21fdf6f2c 100644 --- a/samples/My.Hr/My.Hr.Test/Validators/EmployeeValidatorTest.cs +++ b/samples/My.Hr/My.Hr.Test/Validators/EmployeeValidatorTest.cs @@ -231,7 +231,7 @@ public void B110_CanDelete_NotFound() test.ConfigureServices(_testSetup!) .MockScoped(eds) .ExpectException().Type() - .Validation().With(async () => await EmployeeValidator.CanDelete.ValidateAsync(1.ToGuid())); + .Validation().With(async () => await 1.ToGuid().Validate(EmployeeValidator.CanDelete).ValidateAsync()); } [Test] @@ -245,6 +245,6 @@ public void B110_CanDelete_Invalid() test.ConfigureServices(_testSetup!) .MockScoped(eds) .ExpectException().Type("An employee cannot be deleted after they have started their employment.") - .Validation().With(() => EmployeeValidator.CanDelete.ValidateAsync(1.ToGuid()).Result); + .Validation().With(() => 1.ToGuid().Validate(EmployeeValidator.CanDelete).ValidateAsync().Result); } } \ No newline at end of file diff --git a/samples/MyEf.Hr/MyEf.Hr.Api/MyEf.Hr.Api.csproj b/samples/MyEf.Hr/MyEf.Hr.Api/MyEf.Hr.Api.csproj index 7ca63b6b2..37b33f801 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Api/MyEf.Hr.Api.csproj +++ b/samples/MyEf.Hr/MyEf.Hr.Api/MyEf.Hr.Api.csproj @@ -6,8 +6,8 @@ True - - + + diff --git a/samples/MyEf.Hr/MyEf.Hr.Business/Generated/EmployeeManager.cs b/samples/MyEf.Hr/MyEf.Hr.Business/Generated/EmployeeManager.cs index 18cf75a45..252bcc776 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Business/Generated/EmployeeManager.cs +++ b/samples/MyEf.Hr/MyEf.Hr.Business/Generated/EmployeeManager.cs @@ -31,7 +31,7 @@ public EmployeeManager(IEmployeeDataSvc dataService) public Task> CreateAsync(Employee value) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required() - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.CreateAsync(value)); }, InvokerArgs.Create); @@ -39,7 +39,7 @@ public Task> CreateAsync(Employee value) => ManagerInvoker.Curr public Task> UpdateAsync(Employee value, Guid id) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required().Requires(id).Then(v => v.Id = id) - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.UpdateAsync(value)); }, InvokerArgs.Update); @@ -47,7 +47,7 @@ public Task> UpdateAsync(Employee value, Guid id) => ManagerInv public Task DeleteAsync(Guid id) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go().Requires(id) - .ValidatesAsync(id, v => v.Common(EmployeeValidator.CanDelete), cancellationToken: ct) + .ValidatesAsync(id, vc => vc.Common(EmployeeValidator.CanDelete), cancellationToken: ct) .ThenAsync(() => _dataService.DeleteAsync(id)); }, InvokerArgs.Delete); @@ -55,7 +55,7 @@ public Task DeleteAsync(Guid id) => ManagerInvoker.Current.InvokeAsync(t public Task> GetByArgsAsync(EmployeeArgs? args, PagingArgs? paging) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go() - .ValidatesAsync(args, v => v.Entity().With(), cancellationToken: ct) + .ValidatesAsync(args, vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(() => _dataService.GetByArgsAsync(args, paging)); }, InvokerArgs.Read); @@ -63,7 +63,7 @@ public Task> GetByArgsAsync(EmployeeArgs? a public Task> TerminateAsync(TerminationDetail value, Guid id) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required().Requires(id) - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.TerminateAsync(value, id)); }, InvokerArgs.Update); } \ No newline at end of file diff --git a/samples/MyEf.Hr/MyEf.Hr.Business/Generated/PerformanceReviewManager.cs b/samples/MyEf.Hr/MyEf.Hr.Business/Generated/PerformanceReviewManager.cs index 7da9e576e..b2190fcc5 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Business/Generated/PerformanceReviewManager.cs +++ b/samples/MyEf.Hr/MyEf.Hr.Business/Generated/PerformanceReviewManager.cs @@ -31,7 +31,7 @@ public PerformanceReviewManager(IPerformanceReviewDataSvc dataService) public Task> UpdateAsync(PerformanceReview value, Guid id) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required().Requires(id).Then(v => v.Id = id) - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.UpdateAsync(value)); }, InvokerArgs.Update); @@ -53,7 +53,7 @@ public Task> GetByEmployeeIdAsync(Guid public Task> CreateAsync(PerformanceReview value, Guid employeeId) => ManagerInvoker.Current.InvokeAsync(this, (_, ct) => { return Result.Go(value).Required().Requires(employeeId).Then(v => v.EmployeeId = employeeId) - .ValidateAsync(v => v.Entity().With(), cancellationToken: ct) + .ValidateAsync(vc => vc.Entity().With(), cancellationToken: ct) .ThenAsAsync(v => _dataService.CreateAsync(value)); }, InvokerArgs.Create); } \ No newline at end of file diff --git a/samples/MyEf.Hr/MyEf.Hr.Business/MyEf.Hr.Business.csproj b/samples/MyEf.Hr/MyEf.Hr.Business/MyEf.Hr.Business.csproj index 1ec79eb18..819ae29da 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Business/MyEf.Hr.Business.csproj +++ b/samples/MyEf.Hr/MyEf.Hr.Business/MyEf.Hr.Business.csproj @@ -6,11 +6,11 @@ latest - - - - - + + + + + diff --git a/samples/MyEf.Hr/MyEf.Hr.Common/MyEf.Hr.Common.csproj b/samples/MyEf.Hr/MyEf.Hr.Common/MyEf.Hr.Common.csproj index 06a775642..49951a5f9 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Common/MyEf.Hr.Common.csproj +++ b/samples/MyEf.Hr/MyEf.Hr.Common/MyEf.Hr.Common.csproj @@ -4,6 +4,6 @@ enable - + \ No newline at end of file diff --git a/samples/MyEf.Hr/MyEf.Hr.Security.Subscriptions/MyEf.Hr.Security.Subscriptions.csproj b/samples/MyEf.Hr/MyEf.Hr.Security.Subscriptions/MyEf.Hr.Security.Subscriptions.csproj index a4fee172e..8b3cf03aa 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Security.Subscriptions/MyEf.Hr.Security.Subscriptions.csproj +++ b/samples/MyEf.Hr/MyEf.Hr.Security.Subscriptions/MyEf.Hr.Security.Subscriptions.csproj @@ -15,14 +15,14 @@ - - + + - + diff --git a/samples/MyEf.Hr/MyEf.Hr.Security.Test/MyEf.Hr.Security.Test.csproj b/samples/MyEf.Hr/MyEf.Hr.Security.Test/MyEf.Hr.Security.Test.csproj index 83b8d2086..17c43eadf 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Security.Test/MyEf.Hr.Security.Test.csproj +++ b/samples/MyEf.Hr/MyEf.Hr.Security.Test/MyEf.Hr.Security.Test.csproj @@ -27,7 +27,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/samples/MyEf.Hr/MyEf.Hr.Test/MyEf.Hr.Test.csproj b/samples/MyEf.Hr/MyEf.Hr.Test/MyEf.Hr.Test.csproj index 95b1b20ce..96eb8e7a0 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Test/MyEf.Hr.Test.csproj +++ b/samples/MyEf.Hr/MyEf.Hr.Test/MyEf.Hr.Test.csproj @@ -32,7 +32,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -42,7 +42,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/samples/MyEf.Hr/MyEf.Hr.Test/Validators/EmployeeValidatorTest.cs b/samples/MyEf.Hr/MyEf.Hr.Test/Validators/EmployeeValidatorTest.cs index 14387fc3c..707999ad2 100644 --- a/samples/MyEf.Hr/MyEf.Hr.Test/Validators/EmployeeValidatorTest.cs +++ b/samples/MyEf.Hr/MyEf.Hr.Test/Validators/EmployeeValidatorTest.cs @@ -231,7 +231,7 @@ public void B110_CanDelete_NotFound() test.ConfigureServices(_testSetup!) .MockScoped(eds) .ExpectException().Type() - .Validation().With(async () => await EmployeeValidator.CanDelete.ValidateAsync(1.ToGuid())); + .Validation().With(async () => await 1.ToGuid().Validate(EmployeeValidator.CanDelete).ValidateAsync()); } [Test] @@ -245,6 +245,6 @@ public void B110_CanDelete_Invalid() test.ConfigureServices(_testSetup!) .MockScoped(eds) .ExpectException().Type("An employee cannot be deleted after they have started their employment.") - .Validation().With(() => EmployeeValidator.CanDelete.ValidateAsync(1.ToGuid()).Result); + .Validation().With(() => 1.ToGuid().Validate(EmployeeValidator.CanDelete).ValidateAsync().Result); } } \ No newline at end of file diff --git a/templates/Beef.Template.Solution/Beef.Template.Solution.csproj b/templates/Beef.Template.Solution/Beef.Template.Solution.csproj index fba1a06cd..c82dcef3b 100644 --- a/templates/Beef.Template.Solution/Beef.Template.Solution.csproj +++ b/templates/Beef.Template.Solution/Beef.Template.Solution.csproj @@ -34,8 +34,11 @@ + + + diff --git a/templates/Beef.Template.Solution/content/.template.config/template.json b/templates/Beef.Template.Solution/content/.template.config/template.json index 3f7df77ce..fbf12718a 100644 --- a/templates/Beef.Template.Solution/content/.template.config/template.json +++ b/templates/Beef.Template.Solution/content/.template.config/template.json @@ -85,7 +85,7 @@ "type": "generated", "generator": "constant", "parameters": { - "value": "3.17.0" + "value": "3.18.0" }, "replaces": "CoreExVersion" }, @@ -93,7 +93,7 @@ "type": "generated", "generator": "constant", "parameters": { - "value": "5.12.3" + "value": "5.12.4" }, "replaces": "BeefVersion" }, diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Api/GlobalUsings.cs b/templates/Beef.Template.Solution/content/Company.AppName.Api/GlobalUsings.cs index f9dd71b28..1518ec8c4 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.Api/GlobalUsings.cs +++ b/templates/Beef.Template.Solution/content/Company.AppName.Api/GlobalUsings.cs @@ -8,6 +8,7 @@ global using CoreEx.Azure.Storage; global using CoreEx.Database; global using CoreEx.Database.HealthChecks; +global using CoreEx.Database.SqlServer.Outbox; #endif #endif global using CoreEx.Entities; diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Api/Startup.cs b/templates/Beef.Template.Solution/content/Company.AppName.Api/Startup.cs index 809c3c366..4bf194404 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.Api/Startup.cs +++ b/templates/Beef.Template.Solution/content/Company.AppName.Api/Startup.cs @@ -78,8 +78,8 @@ public void ConfigureServices(IServiceCollection services) .AddEventPublisher(); #if (implement_database || implement_sqlserver) - // Add sql server transactional event outbox enqueue services. - services.AddScoped(); + // Add sql server transactional event outbox enqueue services; AfterSend used to trigger the hosted service to dequeue within 5 seconds. + services.AddEventSender((sp, es) => es.AfterSend += (sender, e) => EventOutboxHostedService.OneOffTrigger(sp, TimeSpan.FromSeconds(5))); // Add transactional event outbox dequeue dependencies. services.AddSingleton(sp => new AzServiceBus.ServiceBusClient(sp.GetRequiredService().ServiceBusConnectionString)) @@ -105,20 +105,20 @@ public void ConfigureServices(IServiceCollection services) services.AddControllers(); // Add health checks. - services.AddHealthChecks() #if (implement_services) + services.AddHealthChecks() #if (implement_database || implement_sqlserver) .AddAzureBlobStorage(sp => new AzBlobs.BlobServiceClient(sp.GetRequiredService().StorageConnectionString), name: "azure-blob-storage") - .AddEventPublisherHealthCheck("event-publisher", sp => new EventPublisher(sp.GetRequiredService(), sp.GetRequiredService(), sp.GetRequiredService())); + .AddEventPublisherHealthCheck("azure-service-bus", sp => new EventPublisher(sp.GetRequiredService(), sp.GetRequiredService(), sp.GetRequiredService())); #else - .AddEventPublisherHealthCheck("event-publisher", sp => new EventPublisher(sp.GetRequiredService(), sp.GetRequiredService(), sp.GetRequiredService())); + .AddEventPublisherHealthCheck("azure-service-bus", sp => new EventPublisher(sp.GetRequiredService(), sp.GetRequiredService(), sp.GetRequiredService())); #endif #else - .AddEventPublisherHealthCheck("event-publisher", sp => new EventPublisher(sp.GetRequiredService(), sp.GetRequiredService(), sp.GetRequiredService())); + services.AddHealthChecks(); #endif // Add Azure monitor open telemetry. - services.AddOpenTelemetry().UseAzureMonitor().WithTracing(b => b.AddSource("CoreEx.*", "MyEf.Hr.*", "Microsoft.EntityFrameworkCore.*", "EntityFrameworkCore.*")); + services.AddOpenTelemetry().UseAzureMonitor().WithTracing(b => b.AddSource("CoreEx.*", "Company.AppName.*", "Microsoft.EntityFrameworkCore.*", "EntityFrameworkCore.*")); // Add the swagger capabilities. services.AddSwaggerGen(options => @@ -138,9 +138,16 @@ public void Configure(IApplicationBuilder app) // Handle any unhandled exceptions. app.UseWebApiExceptionHandler(); + // Authenticate the user. + //app.UseAuthentication(); + // Add Swagger as an endpoint and to serve the swagger-ui to the pipeline. app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Company.AppName")); + app.UseSwaggerUI(c => + { + c.RoutePrefix = ""; // Default as the root/home page. + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Company.AppName"); + }); // Add execution context set up to the pipeline. app.UseExecutionContext(); @@ -152,9 +159,7 @@ public void Configure(IApplicationBuilder app) // Use controllers. app.UseRouting(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); + //app.UseAuthorization(); + app.UseEndpoints(endpoints => endpoints.MapControllers()); } } \ No newline at end of file diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Business/Company.AppName.Business.csproj b/templates/Beef.Template.Solution/content/Company.AppName.Business/Company.AppName.Business.csproj index a3181740c..56572f1b1 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.Business/Company.AppName.Business.csproj +++ b/templates/Beef.Template.Solution/content/Company.AppName.Business/Company.AppName.Business.csproj @@ -24,7 +24,7 @@ - + diff --git a/templates/Beef.Template.Solution/content/Company.AppName.CodeGen/Program.cs b/templates/Beef.Template.Solution/content/Company.AppName.CodeGen/Program.cs index 5d13d4878..8114eb997 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.CodeGen/Program.cs +++ b/templates/Beef.Template.Solution/content/Company.AppName.CodeGen/Program.cs @@ -3,6 +3,7 @@ /// /// Represents the code generation program (capability). /// +[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public static class Program { /// diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Database/Data/RefData.yaml b/templates/Beef.Template.Solution/content/Company.AppName.Database/Data/RefData.yaml index d60db1934..2a678bfd5 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.Database/Data/RefData.yaml +++ b/templates/Beef.Template.Solution/content/Company.AppName.Database/Data/RefData.yaml @@ -6,5 +6,5 @@ AppName: lowerapp: - $gender: //#endif - - M: Male - - F: Female \ No newline at end of file + - F: Female + - M: Male \ No newline at end of file diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Database/Program.cs b/templates/Beef.Template.Solution/content/Company.AppName.Database/Program.cs index 7ab28c8db..4909dfb53 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.Database/Program.cs +++ b/templates/Beef.Template.Solution/content/Company.AppName.Database/Program.cs @@ -15,6 +15,7 @@ namespace Company.AppName.Database; /// /// Represents the database migration program (capability). /// +[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] public class Program { /// diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Services.Test/Company.AppName.Services.Test.csproj b/templates/Beef.Template.Solution/content/Company.AppName.Services.Test/Company.AppName.Services.Test.csproj index 489b80dda..933ddedd6 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.Services.Test/Company.AppName.Services.Test.csproj +++ b/templates/Beef.Template.Solution/content/Company.AppName.Services.Test/Company.AppName.Services.Test.csproj @@ -34,6 +34,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Test/Apis/PersonTest.cs b/templates/Beef.Template.Solution/content/Company.AppName.Test/Apis/PersonTest.cs index 034e559b6..9120049a9 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.Test/Apis/PersonTest.cs +++ b/templates/Beef.Template.Solution/content/Company.AppName.Test/Apis/PersonTest.cs @@ -8,8 +8,8 @@ public class PersonTest : UsingApiTester #if (!implement_httpagent) [OneTimeSetUp] public void OneTimeSetUp() => Assert.That(TestSetUp.Default.SetUp(), Is.True); -#endif +#endif #region Get [Test] @@ -200,7 +200,7 @@ public void A280_GetByArgs_RefDataText() var r = Agent() .ExpectStatusCode(HttpStatusCode.OK) .Run(a => a.GetByArgsAsync(new PersonArgs { Genders = ["F"] }, requestOptions: new HttpRequestOptions { IncludeText = true })) - .AssertJsonFromResource("A280_GetByArgs_RefDataText-Response.json", "etag", "changeLog"); + .AssertJsonFromResource("Person_A280_GetByArgs_Response.json", "etag", "changeLog"); } #endregion diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Test/Apis/ReferenceDataTest.cs b/templates/Beef.Template.Solution/content/Company.AppName.Test/Apis/ReferenceDataTest.cs new file mode 100644 index 000000000..1c251c307 --- /dev/null +++ b/templates/Beef.Template.Solution/content/Company.AppName.Test/Apis/ReferenceDataTest.cs @@ -0,0 +1,37 @@ +using Company.AppName.Common.Entities; + +namespace Company.AppName.Test.Apis; + +[TestFixture] +public class ReferenceDataTest : UsingApiTester +{ +#if (!implement_httpagent) + [OneTimeSetUp] + public void OneTimeSetUp() => Assert.That(TestSetUp.Default.SetUp(), Is.True); +#endif +#if (implement_httpagent) + /* The remainder of the tests for an HttpAgent are commented out and are provided as a guide; MockHttpClientFactory will be needed per test to enable. +#endif + + [Test] + public void A110_Genders() + { + Agent() + .ExpectStatusCode(HttpStatusCode.OK) + .Run(a => a.GenderGetAllAsync()) + .AssertJsonFromResource("ReferenceData_A110_Genders_Response.json", "id", "etag"); + } + + [Test] + public void B110_GetNamed() + { + Agent() + .ExpectStatusCode(HttpStatusCode.OK) + .Run(a => a.GetNamedAsync(["gender"])) + .AssertJsonFromResource("ReferenceData_B110_GetNamed_Response.json", "gender.id", "gender.etag"); + } +#if (implement_httpagent) + + */ +#endif +} \ No newline at end of file diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Test/Company.AppName.Test.csproj b/templates/Beef.Template.Solution/content/Company.AppName.Test/Company.AppName.Test.csproj index e8a693e2a..4c8fe826e 100644 --- a/templates/Beef.Template.Solution/content/Company.AppName.Test/Company.AppName.Test.csproj +++ b/templates/Beef.Template.Solution/content/Company.AppName.Test/Company.AppName.Test.csproj @@ -34,6 +34,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/A280_GetByArgs_RefDataText-Response.json b/templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/Person_A280_GetByArgs_Response.json similarity index 100% rename from templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/A280_GetByArgs_RefDataText-Response.json rename to templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/Person_A280_GetByArgs_Response.json diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/ReferenceData_A110_Genders_Response.json b/templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/ReferenceData_A110_Genders_Response.json new file mode 100644 index 000000000..4a469e46c --- /dev/null +++ b/templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/ReferenceData_A110_Genders_Response.json @@ -0,0 +1,14 @@ +[ + { + "code": "F", + "text": "Female", + "sortOrder": 1, + "isActive": true + }, + { + "code": "M", + "text": "Male", + "sortOrder": 2, + "isActive": true + } +] \ No newline at end of file diff --git a/templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/ReferenceData_B110_GetNamed_Response.json b/templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/ReferenceData_B110_GetNamed_Response.json new file mode 100644 index 000000000..a9b649025 --- /dev/null +++ b/templates/Beef.Template.Solution/content/Company.AppName.Test/Resources/ReferenceData_B110_GetNamed_Response.json @@ -0,0 +1,16 @@ +{ + "gender": [ + { + "code": "F", + "text": "Female", + "sortOrder": 1, + "isActive": true + }, + { + "code": "M", + "text": "Male", + "sortOrder": 2, + "isActive": true + } + ] +} \ No newline at end of file diff --git a/tools/Beef.CodeGen.Core/Beef.CodeGen.Core.csproj b/tools/Beef.CodeGen.Core/Beef.CodeGen.Core.csproj index c49d8cd73..4134f32f7 100644 --- a/tools/Beef.CodeGen.Core/Beef.CodeGen.Core.csproj +++ b/tools/Beef.CodeGen.Core/Beef.CodeGen.Core.csproj @@ -32,7 +32,7 @@ - + diff --git a/tools/Beef.CodeGen.Core/Templates/EntityManager_cs.hbs b/tools/Beef.CodeGen.Core/Templates/EntityManager_cs.hbs index d8d3829cb..635095e3a 100644 --- a/tools/Beef.CodeGen.Core/Templates/EntityManager_cs.hbs +++ b/tools/Beef.CodeGen.Core/Templates/EntityManager_cs.hbs @@ -150,12 +150,12 @@ public partial class {{Name}}Manager{{#if GenericWithT}}{{/if}} : I{{Name}}Ma {{#if WithResult}} {{#if SingleValidatorParameters}} {{#each ValidatorParameters}} - .Validate{{#if IsValueArg}}Async({{else}}sAsync({{ArgumentName}}, {{/if}}v => v{{#ifval Validator}}{{#ifeq ValidationFramework 'FluentValidation'}}.Interop(() => FluentValidator.Create<{{Validator}}>().Wrap()){{else}}.Entity().With<{{Validator}}>(){{/ifeq}}{{/ifval}}{{#ifval ValidatorCode}}.{{ValidatorCode}}{{/ifval}}, cancellationToken: ct) + .Validate{{#if IsValueArg}}Async({{else}}sAsync({{ArgumentName}}, {{/if}}vc => vc{{#ifval Validator}}{{#ifeq ValidationFramework 'FluentValidation'}}.Interop(() => FluentValidator.Create<{{Validator}}>().Wrap()){{else}}.Entity().With<{{Validator}}>(){{/ifeq}}{{/ifval}}{{#ifval ValidatorCode}}.{{ValidatorCode}}{{/ifval}}, cancellationToken: ct) {{/each}} {{else}} .ValidateAsync({{#if HasValue}}v{{else}}(){{/if}} => MultiValidator.Create() {{#each ValidatorParameters}} - .Add({{#if IsValueArg}}v{{else}}{{ArgumentName}}{{/if}}.Validate(){{#ifval Validator}}{{#ifeq ValidationFramework 'FluentValidation'}}.Interop(() => FluentValidator.Create<{{Validator}}>().Wrap()){{else}}.Entity().With<{{Validator}}>(){{/ifeq}}{{/ifval}}{{#ifval ValidatorCode}}.{{ValidatorCode}}{{/ifval}}){{#if @last}}{{#unless Parent.ManagerExtensions}}){{/unless}}{{/if}} + .Add({{#if IsValueArg}}v{{else}}{{ArgumentName}}{{/if}}.Validate().Configure(vc => vc{{#ifval Validator}}{{#ifeq ValidationFramework 'FluentValidation'}}.Interop(() => FluentValidator.Create<{{Validator}}>().Wrap()){{else}}.Entity().With<{{Validator}}>(){{/ifeq}}{{/ifval}}{{#ifval ValidatorCode}}.{{ValidatorCode}}{{/ifval}})){{#if @last}}, cancellationToken: ct{{#unless Parent.ManagerExtensions}}){{/unless}}{{/if}} {{/each}} {{#if ManagerExtensions}} .Additional(mv => {{PrivateName}}OnValidate?.Invoke(mv{{#each Parameters}}, {{ArgumentName}}{{/each}})), cancellationToken: ct) @@ -164,12 +164,12 @@ public partial class {{Name}}Manager{{#if GenericWithT}}{{/if}} : I{{Name}}Ma {{else}} {{#if SingleValidateParameters}} {{#each ValidateParameters}} - await {{ArgumentName}}.Validate({{#ifne ArgumentName 'value'}}{{/ifne}}){{#if IsValueArg}}{{#ifeq Parent.EnsureValueCount 0}}.Mandatory(){{/ifeq}}{{else}}{{#if IsMandatory}}.Mandatory(){{/if}}{{/if}}{{#ifval Validator}}{{#ifeq ValidationFramework 'FluentValidation'}}.Interop(() => FluentValidator.Create<{{Validator}}>().Wrap()){{else}}.Entity().With<{{Validator}}>(){{/ifeq}}{{/ifval}}{{#ifval ValidatorCode}}.{{ValidatorCode}}{{/ifval}}.ValidateAsync(true{{#if Root.CancellationToken}}, ct{{/if}}).ConfigureAwait(false); + await {{ArgumentName}}.Validate({{#ifne ArgumentName 'value'}}{{/ifne}}).Configure(vc => vc{{#if IsValueArg}}{{#ifeq Parent.EnsureValueCount 0}}.Mandatory(){{/ifeq}}{{else}}{{#if IsMandatory}}.Mandatory(){{/if}}{{/if}}{{#ifval Validator}}{{#ifeq ValidationFramework 'FluentValidation'}}.Interop(() => FluentValidator.Create<{{Validator}}>().Wrap()){{else}}.Entity().With<{{Validator}}>(){{/ifeq}}{{/ifval}}{{#ifval ValidatorCode}}.{{ValidatorCode}}{{/ifval}}).ValidateAsync(true{{#if Root.CancellationToken}}, ct{{/if}}).ConfigureAwait(false); {{/each}} {{else}} await MultiValidator.Create() {{#each ValidateParameters}} - .Add({{ArgumentName}}.Validate(){{#if IsMandatory}}.Mandatory(){{else}}{{#if IsValueArg}}{{#ifeq Parent.EnsureValueCount 0}}.Mandatory(){{/ifeq}}{{/if}}{{/if}}{{#ifval Validator}}{{#ifeq ValidationFramework 'FluentValidation'}}.Interop(() => FluentValidator.Create<{{Validator}}>().Wrap()){{else}}.Entity().With<{{Validator}}>(){{/ifeq}}{{/ifval}}{{#ifval ValidatorCode}}.{{ValidatorCode}}{{/ifval}}) + .Add({{ArgumentName}}.Validate().Configure(vc => vc{{#if IsMandatory}}.Mandatory(){{else}}{{#if IsValueArg}}{{#ifeq Parent.EnsureValueCount 0}}.Mandatory(){{/ifeq}}{{/if}}{{/if}}{{#ifval Validator}}{{#ifeq ValidationFramework 'FluentValidation'}}.Interop(() => FluentValidator.Create<{{Validator}}>().Wrap()){{else}}.Entity().With<{{Validator}}>(){{/ifeq}}{{/ifval}}{{#ifval ValidatorCode}}.{{ValidatorCode}}{{/ifval}})) {{/each}} {{#if ManagerExtensions}} {{#unless SingleValidateParameters}} diff --git a/tools/Beef.Database.Core/Beef.Database.Core.csproj b/tools/Beef.Database.Core/Beef.Database.Core.csproj index a5d7ab750..16cca3595 100644 --- a/tools/Beef.Database.Core/Beef.Database.Core.csproj +++ b/tools/Beef.Database.Core/Beef.Database.Core.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/tools/Beef.Database.MySql/Beef.Database.MySql.csproj b/tools/Beef.Database.MySql/Beef.Database.MySql.csproj index 78c7b6211..d0040d4ab 100644 --- a/tools/Beef.Database.MySql/Beef.Database.MySql.csproj +++ b/tools/Beef.Database.MySql/Beef.Database.MySql.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/tools/Beef.Database.Postgres/Beef.Database.Postgres.csproj b/tools/Beef.Database.Postgres/Beef.Database.Postgres.csproj index fb6b21e9c..92412900a 100644 --- a/tools/Beef.Database.Postgres/Beef.Database.Postgres.csproj +++ b/tools/Beef.Database.Postgres/Beef.Database.Postgres.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/tools/Beef.Database.SqlServer/Beef.Database.SqlServer.csproj b/tools/Beef.Database.SqlServer/Beef.Database.SqlServer.csproj index 64347f352..5711d12ea 100644 --- a/tools/Beef.Database.SqlServer/Beef.Database.SqlServer.csproj +++ b/tools/Beef.Database.SqlServer/Beef.Database.SqlServer.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/tools/Beef.Test.NUnit/Beef.Test.NUnit.csproj b/tools/Beef.Test.NUnit/Beef.Test.NUnit.csproj index 4d572f2c4..b9dac4491 100644 --- a/tools/Beef.Test.NUnit/Beef.Test.NUnit.csproj +++ b/tools/Beef.Test.NUnit/Beef.Test.NUnit.csproj @@ -8,7 +8,7 @@ - +