From 48a346984290839fe06eb028281d7645f3008fb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 10:05:22 +0000 Subject: [PATCH 01/41] Bump Microsoft.CodeAnalysis.NetAnalyzers Bumps [Microsoft.CodeAnalysis.NetAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 7.0.1 to 7.0.4. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/main/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/commits) --- updated-dependencies: - dependency-name: Microsoft.CodeAnalysis.NetAnalyzers dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj index 793f362..b94b013 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj @@ -142,7 +142,7 @@ 5.2.9 - 7.0.1 + 7.0.4 runtime; build; native; contentfiles; analyzers; buildtransitive all From 2aec86ee280edd8a560bf478edeb2343b84a27e6 Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Mon, 19 Aug 2024 01:31:41 -0400 Subject: [PATCH 02/41] Update ProjectTemplate.csproj to net48 --- .../UnitTests/ProjectTemplate.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj index 592ca70..b12025f 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj @@ -2,7 +2,7 @@ win {745843B0-F86F-4CE1-BE21-E6FBCFE167DC} - net472 + net48 Unit Tests UnitTests Copyright © 2023 @@ -58,4 +58,4 @@ all - \ No newline at end of file + From 4d297b7c18701035bf2b20470a278365c983559f Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Mon, 19 Aug 2024 01:33:06 -0400 Subject: [PATCH 03/41] Update ProjectTemplate.csproj for net48 --- .../IntegrationTests/ProjectTemplate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj index d1ef898..0eb9954 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj @@ -2,7 +2,7 @@ win {71A94484-BE72-4864-AEC0-B42E766313BF} - net472 + net48 IntegrationTests IntegrationTests Copyright © 2023 From a15aa4e64e14a1b46baae040ff839cc248ca0a1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 05:47:43 +0000 Subject: [PATCH 04/41] Bump @stencil/core in /Eraware_Dnn_Spa_Ef_Di_Stencil/module.web Bumps [@stencil/core](https://github.com/ionic-team/stencil) from 3.4.2 to 4.20.0. - [Release notes](https://github.com/ionic-team/stencil/releases) - [Changelog](https://github.com/ionic-team/stencil/blob/main/CHANGELOG.md) - [Commits](https://github.com/ionic-team/stencil/compare/v3.4.2...v4.20.0) --- updated-dependencies: - dependency-name: "@stencil/core" dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json index c230810..d0d9d7b 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json @@ -29,7 +29,7 @@ "@microsoft/api-documenter": "^7.13.49", "@microsoft/api-extractor": "^7.18.9", "@stencil-community/eslint-plugin": "^0.5.0", - "@stencil/core": "^3.2.2", + "@stencil/core": "^4.20.0", "@stencil/sass": "^3.0.2", "@stencil/store": "^2.0.0", "eslint-plugin-tsdoc": "^0.2.11" From 3d00400dc5cfa4fa436dc3bf292333d58dfa8c75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 05:49:41 +0000 Subject: [PATCH 05/41] Bump @dnncommunity/dnn-elements Bumps [@dnncommunity/dnn-elements](https://github.com/dnncommunity/dnn-elements) from 0.18.0 to 0.23.3. - [Release notes](https://github.com/dnncommunity/dnn-elements/releases) - [Commits](https://github.com/dnncommunity/dnn-elements/compare/v0.18.0...v0.23.3) --- updated-dependencies: - dependency-name: "@dnncommunity/dnn-elements" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json index c230810..d71a04f 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json @@ -25,7 +25,7 @@ "tsdoc": "tsc ./src/services/services.ts --declaration --emitDeclarationOnly --target es2017 --moduleResolution nodenext && api-extractor run --local && api-documenter markdown -i temp -o tempmd" }, "devDependencies": { - "@dnncommunity/dnn-elements": "^0.18.0", + "@dnncommunity/dnn-elements": "^0.23.3", "@microsoft/api-documenter": "^7.13.49", "@microsoft/api-extractor": "^7.18.9", "@stencil-community/eslint-plugin": "^0.5.0", From 166d34c7fcef6cec8299fbd344e4e733ad35c6db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 05:51:17 +0000 Subject: [PATCH 06/41] Bump xunit.runner.console in /Eraware_Dnn_Spa_Ef_Di_Stencil/build Bumps [xunit.runner.console](https://github.com/xunit/xunit) from 2.4.2 to 2.9.0. - [Commits](https://github.com/xunit/xunit/compare/2.4.2...2.9.0) --- updated-dependencies: - dependency-name: xunit.runner.console dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj index 98941a1..61f0faf 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj @@ -17,7 +17,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 7c795e32e89637c2e9b2c58822c9c052d45d80cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 21:10:41 +0000 Subject: [PATCH 07/41] Bump NSwag.MSBuild in /Eraware_Dnn_Spa_Ef_Di_Stencil/build Bumps [NSwag.MSBuild](https://github.com/RicoSuter/NSwag) from 13.19.0 to 14.1.0. - [Release notes](https://github.com/RicoSuter/NSwag/releases) - [Changelog](https://github.com/RicoSuter/NSwag/blob/master/CHANGELOG.md) - [Commits](https://github.com/RicoSuter/NSwag/compare/v13.19.0...v14.1.0) --- updated-dependencies: - dependency-name: NSwag.MSBuild dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj index 98941a1..c38c60e 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj @@ -21,7 +21,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From cf00913c7bd42595176d80d8cb968fc13762b19d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 21:11:33 +0000 Subject: [PATCH 08/41] Bump NuGet.CommandLine in /Eraware_Dnn_Spa_Ef_Di_Stencil/build Bumps [NuGet.CommandLine](https://github.com/NuGet/NuGet.Client) from 6.5.0 to 6.11.0. - [Release notes](https://github.com/NuGet/NuGet.Client/releases) - [Commits](https://github.com/NuGet/NuGet.Client/commits) --- updated-dependencies: - dependency-name: NuGet.CommandLine dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj index 98941a1..fcd5f52 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From a4d485d8e4c3c853f07d5732b58663741fd4107c Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Mon, 19 Aug 2024 17:13:35 -0400 Subject: [PATCH 09/41] Update ProjectTemplate.csproj --- Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj index b94b013..1352ad1 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj @@ -142,7 +142,7 @@ 5.2.9 - 7.0.4 + 8.0.0 runtime; build; native; contentfiles; analyzers; buildtransitive all From 5c53ac299c31e16d60946b14244b8a534578127a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Aug 2024 21:15:30 +0000 Subject: [PATCH 10/41] Bump ReportGenerator in /Eraware_Dnn_Spa_Ef_Di_Stencil/build Bumps [ReportGenerator](https://github.com/danielpalme/ReportGenerator) from 5.1.21 to 5.3.8. - [Release notes](https://github.com/danielpalme/ReportGenerator/releases) - [Commits](https://github.com/danielpalme/ReportGenerator/compare/v5.1.21...v5.3.8) --- updated-dependencies: - dependency-name: ReportGenerator dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj index 61f0faf..714fb34 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj @@ -16,7 +16,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 427df911bed46a9ed62d83ea4968d04f84ca8c9c Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 20 Aug 2024 16:37:36 -0400 Subject: [PATCH 11/41] Removed LoggingService Closes #703 --- .../Eraware_Dnn_Spa_Ef_Di_Stencil.csproj | 3 - .../ModuleExceptionFilterAttributeTests.cs | 14 ++++ .../UnitTests/Services/LoggingServiceTests.cs | 41 ----------- .../UnitTests/StartupTests.cs | 3 +- .../UnitTests/UnitTests.vstemplate | 1 - .../ModuleExceptionFilterAttribute.cs | 13 +++- .../module/Module.vstemplate | 4 +- .../module/ProjectTemplate.csproj | 2 - .../module/Services/ILoggingService.cs | 26 ------- .../module/Services/LoggingService.cs | 71 ------------------- .../module/Startup.cs | 4 +- 11 files changed, 30 insertions(+), 152 deletions(-) delete mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/LoggingServiceTests.cs delete mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ILoggingService.cs delete mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/LoggingService.cs diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj index bf62ea9..28d24fd 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj @@ -201,10 +201,7 @@ - - - diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs index 60c7350..4218095 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs @@ -1,5 +1,7 @@ using DotNetNuke.Web.Api; +using Moq; using $ext_rootnamespace$.Controllers; +using DotNetNuke.Instrumentation; using System; using System.Collections.Generic; using System.Net; @@ -16,6 +18,10 @@ public class ModuleExceptionFilterAttributeTests public static void NoException_DoesNothing() { var attribute = new ModuleExceptionFilterAttribute(); + var loggerSource = new Mock(); + var log = new Mock(); + loggerSource.Setup(l => l.GetLogger(It.IsAny())).Returns(log.Object); + attribute.LoggerSource = loggerSource.Object; var actionContext = new HttpActionContext { Response = new HttpResponseMessage(HttpStatusCode.OK) @@ -33,6 +39,10 @@ public static void ArgumentException_BadRequest( Exception exception, HttpStatusCode expectedStatusCode) { var attribute = new ModuleExceptionFilterAttribute(); + var loggerSource = new Mock(); + var log = new Mock(); + loggerSource.Setup(l => l.GetLogger(It.IsAny())).Returns(log.Object); + attribute.LoggerSource = loggerSource.Object; var actionContext = new HttpActionContext { Response = new HttpResponseMessage(HttpStatusCode.OK), @@ -49,6 +59,10 @@ public static void ArgumentException_BadRequest( public static void SystemException_DoesNotExposeDetails() { var attribute = new ModuleExceptionFilterAttribute(); + var loggerSource = new Mock(); + var log = new Mock(); + loggerSource.Setup(l => l.GetLogger(It.IsAny())).Returns(log.Object); + attribute.LoggerSource = loggerSource.Object; var actionContext = new HttpActionContext { Response = new HttpResponseMessage(HttpStatusCode.OK), diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/LoggingServiceTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/LoggingServiceTests.cs deleted file mode 100644 index 22b9ef3..0000000 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/LoggingServiceTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using DotNetNuke.Instrumentation; -using $ext_rootnamespace$.Services; -using Moq; -using System; -using Xunit; - -namespace UnitTests.Services -{ - public class LoggingServiceTests - { - [Fact] - public static void LoggingService_DefaultConstructorExists() - { - var service = new LoggingService(); - service.LogError("This is a test"); - } - - [Fact] - public static void LogginService_TestableConstructorLogsError() - { - var logger = new Mock(); - ILoggingService service = new LoggingService(logger.Object); - - service.LogError("Test"); - - logger.Verify(l => l.Error("Test"), Times.Once); - } - - [Fact] - public static void LogginService_TestableConstructorLogsErrorWithException() - { - var logger = new Mock(); - ILoggingService service = new LoggingService(logger.Object); - var exception = new ArgumentNullException("test"); - - service.LogError("Test", exception); - - logger.Verify(l => l.Error("Test", exception), Times.Once); - } - } -} diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/StartupTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/StartupTests.cs index e1f06cb..1a10f5f 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/StartupTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/StartupTests.cs @@ -2,6 +2,7 @@ using $ext_rootnamespace$.Data.Repositories; using $ext_rootnamespace$.Providers; using $ext_rootnamespace$.Services; +using DotNetNuke.Instrumentation; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; @@ -23,7 +24,7 @@ public void Startup_RegistersAllRequiredServices() typeof(ModuleDbContext), typeof(IRepository<>), typeof(IItemService), - typeof(ILoggingService), + typeof(ILoggerSource), typeof(ILocalizationService), typeof(IDateTimeProvider), }; diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/UnitTests.vstemplate b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/UnitTests.vstemplate index 381b2db..f338afe 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/UnitTests.vstemplate +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/UnitTests.vstemplate @@ -44,7 +44,6 @@ ItemServiceTests.cs - LoggingServiceTests.cs FakeDatacontext.cs Startup.cs diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleExceptionFilterAttribute.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleExceptionFilterAttribute.cs index 32c6ef3..9c3f186 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleExceptionFilterAttribute.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleExceptionFilterAttribute.cs @@ -1,11 +1,13 @@ // MIT License // Copyright $ext_companyname$ +using DotNetNuke.DependencyInjection; using DotNetNuke.Instrumentation; using $ext_rootnamespace$.Services; using System; using System.Net; using System.Net.Http; +using System.Runtime.CompilerServices; using System.Web.Http.Filters; namespace $ext_rootnamespace$.Controllers @@ -15,6 +17,12 @@ namespace $ext_rootnamespace$.Controllers /// internal class ModuleExceptionFilterAttribute : ExceptionFilterAttribute { + /// + /// Gets or sets the logger source. + /// + [DotNetNuke.DependencyInjection.Dependency] + public ILoggerSource LoggerSource { get; set; } + /// public override void OnException(HttpActionExecutedContext actionExecutedContext) { @@ -25,9 +33,8 @@ public override void OnException(HttpActionExecutedContext actionExecutedContext return; } - // TODO: When 9.9.0 comes out, this can be replaced with property injection. - ILoggingService logger = new LoggingService(); - logger.LogError(exception.Message, exception); + var log = this.LoggerSource.GetLogger(nameof(ModuleExceptionFilterAttribute)); + log.Error(exception.Message, exception); if (exception is ArgumentException) { diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Module.vstemplate b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Module.vstemplate index ce9871a..834ff9b 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Module.vstemplate +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Module.vstemplate @@ -22,7 +22,7 @@ dependabot.yml - mergeable.ymls + mergeable.yml Globals.cs @@ -132,8 +132,6 @@ ServiceRouteMapper.cs - ILoggingService.cs - LoggingService.cs IItemService.cs ILocalizationService.cs ItemService.cs diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj index 793f362..6685081 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj @@ -73,8 +73,6 @@ - - diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ILoggingService.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ILoggingService.cs deleted file mode 100644 index 7cb14e9..0000000 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ILoggingService.cs +++ /dev/null @@ -1,26 +0,0 @@ -// MIT License -// Copyright $ext_companyname$ - -using System; - -namespace $ext_rootnamespace$.Services -{ - /// - /// Allows logging. - /// - internal interface ILoggingService - { - /// - /// Logs an error. - /// - /// The error message. - void LogError(string message); - - /// - /// Logs and error with an exception details. - /// - /// The error message. - /// The exception details. - void LogError(string message, Exception ex); - } -} \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/LoggingService.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/LoggingService.cs deleted file mode 100644 index 14871b4..0000000 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/LoggingService.cs +++ /dev/null @@ -1,71 +0,0 @@ -// MIT License -// Copyright $ext_companyname$ - -using DotNetNuke.Instrumentation; -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace $ext_rootnamespace$.Services -{ - /// - /// Implements a default logging mechanism. - /// - internal class LoggingService : ILoggingService - { - private ILog logger; - - /// - /// Initializes a new instance of the class. - /// - public LoggingService() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// User this constructor only for testing. - /// The logger to use during testing. - internal LoggingService(ILog logger) - { - this.logger = logger; - } - - /// - public void LogError(string message) - { - StackFrame frame = new StackFrame(1); - var method = frame.GetMethod(); - this.LogError(message, method.DeclaringType); - } - - /// - public void LogError(string message, Exception ex) - { - StackFrame frame = new StackFrame(1); - var method = frame.GetMethod(); - this.LogError(message, ex, method.DeclaringType); - } - - private void LogError(string message, Type type) - { - this.SetupLogger(type); - this.logger.Error(message); - } - - private void LogError(string message, Exception ex, Type type) - { - this.SetupLogger(type); - this.logger.Error(message, ex); - } - - private void SetupLogger(Type type) - { - if (this.logger is null) - { - this.logger = LoggerSource.Instance.GetLogger(type); - } - } - } -} \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Startup.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Startup.cs index 030b53f..b029771 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Startup.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Startup.cs @@ -4,12 +4,14 @@ namespace $ext_rootnamespace$ { using DotNetNuke.DependencyInjection; + using DotNetNuke.Instrumentation; using $ext_rootnamespace$.Data; using $ext_rootnamespace$.Data.Entities; using $ext_rootnamespace$.Data.Repositories; using $ext_rootnamespace$.Providers; using $ext_rootnamespace$.Services; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.DependencyInjection.Extensions; using System.Diagnostics.CodeAnalysis; /// @@ -27,7 +29,7 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); services.AddScoped(provider => new ItemService(provider.GetService>())); - services.AddScoped(); + services.TryAddScoped(x => LoggerSource.Instance); services.AddScoped(); services.AddSingleton(); } From 25b2404718cb4e3cad6051dc0bd6f568994a2cc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 22:47:18 +0000 Subject: [PATCH 12/41] Bump Microsoft.TestPlatform.ObjectModel Bumps [Microsoft.TestPlatform.ObjectModel](https://github.com/microsoft/vstest) from 17.6.0 to 17.11.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md) - [Commits](https://github.com/microsoft/vstest/compare/v17.6.0...v17.11.0) --- updated-dependencies: - dependency-name: Microsoft.TestPlatform.ObjectModel dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj index b12025f..b14d7a5 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj @@ -45,7 +45,7 @@ - + From aeac4c615e55848130f30688ba55c0b19caae047 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 20 Aug 2024 20:09:53 -0400 Subject: [PATCH 13/41] Added dependabot groups Closes #707 --- .github/dependabot.yml | 28 +++++++++---------- .../module/.github/dependabot.yml | 10 +++++++ 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9ef9eed..43ceb23 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,8 +5,8 @@ version: 2 updates: - - package-ecosystem: "npm" # See documentation for possible values - directory: "/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web" # Location of package manifests + - package-ecosystem: "npm" + directory: "/" schedule: interval: "monthly" - package-ecosystem: "nuget" @@ -14,7 +14,7 @@ updates: schedule: interval: "monthly" - package-ecosystem: "nuget" - directory: "/Eraware_Dnn_Spa_Ef_Di_Stencil/module" + directory: "/" schedule: interval: "monthly" ignore: @@ -23,15 +23,13 @@ updates: - dependency-name: "Microsoft.Extensions.DependencyInjection" - dependency-name: "Microsoft.Extensions.DependencyInjection.Abstractions" - dependency-name: "Newtonsoft.Json" - - package-ecosystem: "nuget" - directory: "/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests" - schedule: - interval: "monthly" - ignore: - - dependency-name: "Newtonsoft.Json" - - package-ecosystem: "nuget" - directory: "/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests" - schedule: - interval: "monthly" - ignore: - - dependency-name: "Newtonsoft.Json" + groups: + xunit: + patterns: + - "xunit*" + dnn: + patterns: + - "DotNetNuke*" + nswag: + patterns: + - "NSwag*" diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml index e49e283..1766d7b 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml @@ -19,3 +19,13 @@ updates: - dependency-name: "Microsoft.Extensions.DependencyInjection" - dependency-name: "Microsoft.Extensions.DependencyInjection.Abstractions" - dependency-name: "Newtonsoft.Json" + groups: + xunit: + patterns: + - "xunit*" + dnn: + patterns: + - "DotNetNuke*" + nswag: + patterns: + - "NSwag*" From a503d3b8db15cf01ced1728a6742fc6c6439bba0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 00:26:59 +0000 Subject: [PATCH 14/41] Bump EntityFramework from 6.4.0 to 6.5.1 Bumps [EntityFramework](https://github.com/dotnet/ef6) from 6.4.0 to 6.5.1. - [Release notes](https://github.com/dotnet/ef6/releases) - [Commits](https://github.com/dotnet/ef6/compare/v6.4.0...v6.5.1) --- updated-dependencies: - dependency-name: EntityFramework dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../Eraware_Dnn_Spa_Ef_Di_Stencil.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj index 28d24fd..182cec1 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj @@ -263,7 +263,7 @@ - 6.4.0 + 6.5.1 From 43e8bd4ce24e5214409ef739e3c963e9ae4427ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 00:27:37 +0000 Subject: [PATCH 15/41] Bump Microsoft.VisualStudio.SDK from 17.0.31902.203 to 17.11.40262 Bumps Microsoft.VisualStudio.SDK from 17.0.31902.203 to 17.11.40262. --- updated-dependencies: - dependency-name: Microsoft.VisualStudio.SDK dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj b/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj index 72e9b9c..dbcdec9 100644 --- a/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj +++ b/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj @@ -73,7 +73,7 @@ - + compile; build; native; contentfiles; analyzers; buildtransitive From 2b8d102492d23bdfadc7a899465040cb274b3d4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 00:27:56 +0000 Subject: [PATCH 16/41] Bump Microsoft.VSSDK.BuildTools from 17.0.5232 to 17.11.435 Bumps Microsoft.VSSDK.BuildTools from 17.0.5232 to 17.11.435. --- updated-dependencies: - dependency-name: Microsoft.VSSDK.BuildTools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj b/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj index 72e9b9c..d62256e 100644 --- a/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj +++ b/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj @@ -76,7 +76,7 @@ compile; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive all From a3b69ada5a876ebe9f48bef2cc1872935102853b Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 20 Aug 2024 20:42:45 -0400 Subject: [PATCH 17/41] Bumped DNN dependency to 9.13.4 Bumped DNN dependency to 9.13.4 --- .../IntegrationTests/ProjectTemplate.csproj | 12 ++++++------ .../UnitTests/ProjectTemplate.csproj | 10 +++++----- Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs | 14 ++++++++++++++ .../module/ProjectTemplate.csproj | 10 +++++----- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj index 0eb9954..948f51a 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj @@ -30,14 +30,14 @@ all - - - - - + + + + + - + diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj index b14d7a5..7a4f5c3 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj @@ -38,11 +38,11 @@ all - - - - - + + + + + diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs index 20628e3..cd9c323 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs @@ -144,8 +144,21 @@ class Build : NukeBuild .SetProjectFile(Solution.GetProject("IntegrationTests"))); }); + // TODO: This is a workaround for https://github.com/dnnsoftware/Dnn.Platform/issues/6024 and can be removed once a new release with that fix comes out. + Target AdjustCasing => _ => _ + .After(Compile) + .Executes(() => + { + if (!IsWin) + { + var log4netFiles = RootDirectory.GlobFiles("**/DotNetNuke.Log4Net.dll"); + log4netFiles.ForEach(f => f.Rename("DotNetNuke.log4net.dll")); + } + }); + Target UnitTests => _ => _ .DependsOn(Compile) + .DependsOn(AdjustCasing) .Executes(() => { MSBuild(_ => _ @@ -188,6 +201,7 @@ class Build : NukeBuild Target IntegrationTests => _ => _ .DependsOn(Compile) + .DependsOn(AdjustCasing) .Executes(() => { MSBuild(_ => _ diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj index 6685081..0446e7a 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj @@ -119,19 +119,19 @@ - 9.11.2 + 9.13.4 - 9.11.2 + 9.13.4 - 9.11.2 + 9.13.4 - 9.11.2 + 9.13.4 - 9.11.2 + 9.13.4 6.4.4 From 840b2e5df43f24db07122dcb9d1a0dda73304d11 Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Tue, 20 Aug 2024 21:37:37 -0400 Subject: [PATCH 18/41] Update manifest.dnn --- Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn index fd7d9fa..da7a48f 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn @@ -27,12 +27,12 @@ EntityFramework.dll bin - 6.4.4 + 6.5.1 EntityFramework.SqlServer.dll bin - 6.4.4 + 6.5.1 NSwag.Annotations.dll From 0911fb4ff51d41b802e8b747332babf05e96c8af Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 20 Aug 2024 22:37:37 -0400 Subject: [PATCH 19/41] Bumped Nuke to v8.0.0 Bumped Nuke to v8.0.0 --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs | 4 ++-- .../build/ProjectTemplate.csproj | 4 ++-- Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.ps1 | 11 ++++++++--- Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.sh | 11 ++++++++--- Eraware_Dnn_Spa_Ef_Di_Stencil/module/global.json | 4 ++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs index cd9c323..c952c56 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs @@ -724,12 +724,12 @@ class Build : NukeBuild .SetInfoVersion(GitVersion != null ? GitVersion.AssemblySemVer : "0.1.0") .SetProcessArgumentConfigurator(a => a.Add("/DefaultUrlTemplate:{{controller}}/{{action}}")) .SetOutput(swaggerFile) - .SetNSwagRuntime("Net70")); + .SetNSwagRuntime("Net80")); NSwagTasks.NSwagOpenApiToTypeScriptClient(c => c .SetInput(swaggerFile) .SetOutput(ClientServicesDirectory / "services.ts") - .SetNSwagRuntime("Net70") + .SetNSwagRuntime("Net80") .SetProcessArgumentConfigurator(c => c .Add("/Template:Fetch") .Add("/GenerateClientClasses:True") diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj index 7fb87fb..2562564 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 false False @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.ps1 b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.ps1 index f8c2eb2..9a48eaf 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.ps1 +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.ps1 @@ -18,11 +18,10 @@ $TempDirectory = "$PSScriptRoot\\.nuke\temp" $DotNetGlobalFile = "$PSScriptRoot\\global.json" $DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1" -$DotNetChannel = "Current" +$DotNetChannel = "STS" -$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1 $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 -$env:DOTNET_MULTILEVEL_LOOKUP = 0 +$env:DOTNET_NOLOGO = 1 ########################################################################### # EXECUTION @@ -61,9 +60,15 @@ else { ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } } $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" + $env:PATH = "$DotNetDirectory;$env:PATH" } Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)" +if (Test-Path env:NUKE_ENTERPRISE_TOKEN) { + & $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null + & $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null +} + ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet } ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments } diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.sh b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.sh index b6c5821..e58b138 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.sh +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/build.sh @@ -14,11 +14,10 @@ TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" -DOTNET_CHANNEL="Current" +DOTNET_CHANNEL="STS" export DOTNET_CLI_TELEMETRY_OPTOUT=1 -export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 -export DOTNET_MULTILEVEL_LOOKUP=0 +export DOTNET_NOLOGO=1 ########################################################################### # EXECUTION @@ -54,9 +53,15 @@ else "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path fi export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" + export PATH="$DOTNET_DIRECTORY:$PATH" fi echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" +if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then + "$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true + "$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true +fi + "$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/global.json b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/global.json index b3981be..d66f18b 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/global.json +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.302", - "rollForward": "latestMajor" + "version": "8.0.400", + "rollForward": "latestMinor" } } \ No newline at end of file From b3b8c9a548cb0caac50211639eb0cfb033c0092f Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 20 Aug 2024 22:47:58 -0400 Subject: [PATCH 20/41] Adjusted usage of NSwag per breaking changes Adjusted usage of NSwag per breaking changes --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs | 21 +++++++++---------- .../build/ProjectTemplate.csproj | 7 ++++--- .../module/Controllers/ItemController.cs | 6 ------ .../module/ProjectTemplate.csproj | 2 +- .../module/manifest.dnn | 2 +- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs index cd9c323..f75e8ff 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs @@ -71,6 +71,9 @@ class Build : NukeBuild [GitRepository] readonly GitRepository GitRepository; [GitVersion(Framework = "net6.0", UpdateAssemblyInfo = false, NoFetch = true)] readonly GitVersion GitVersion; + [NuGetPackage("WebApiToOpenApiReflector", "WebApiToOpenApiReflector.dll")] + readonly Tool WebApiToOpenApiReflector; + AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts"; AbsolutePath InstallDirectory => RootDirectory.Parent.Parent / "Install" / "Module"; AbsolutePath WebProjectDirectory => RootDirectory / "module.web"; @@ -87,6 +90,7 @@ class Build : NukeBuild private const string devViewsPath = "http://localhost:3333/build/"; private const string prodViewsPath = "/DesktopModules/$ext_modulefoldername$/resources/scripts/$ext_scopeprefixkebab$/"; + private const string moduleName = "$ext_rootnamespace$"; private bool FirstBuild = false; string releaseNotes = ""; @@ -716,31 +720,26 @@ class Build : NukeBuild .DependsOn(Compile) .Executes(() => { + var swaggerDir = DocsDirectory / "rest"; + swaggerDir.CreateOrCleanDirectory(); var swaggerFile = DocsDirectory / "rest" / "rest.json"; - - NSwagTasks.NSwagWebApiToOpenApi(c => c - .AddAssembly(RootDirectory / "bin" / Configuration / "$ext_rootnamespace$.dll") - .SetInfoTitle("$ext_companyname$ $ext_modulefriendlyname$") - .SetInfoVersion(GitVersion != null ? GitVersion.AssemblySemVer : "0.1.0") - .SetProcessArgumentConfigurator(a => a.Add("/DefaultUrlTemplate:{{controller}}/{{action}}")) - .SetOutput(swaggerFile) - .SetNSwagRuntime("Net70")); + var assembly = RootDirectory / "bin" / Configuration / $"{ModuleName}.dll"; + var version = GitVersion != null ? GitVersion.AssemblySemVer : "0.1.0"; + WebApiToOpenApiReflector($@"{assembly} --title "$ext_companyname$ $ext_modulefriendlyname$"" --info-version {version} --default-url-template {{controller}}/{{action}} --output {swaggerFile}"); NSwagTasks.NSwagOpenApiToTypeScriptClient(c => c .SetInput(swaggerFile) .SetOutput(ClientServicesDirectory / "services.ts") - .SetNSwagRuntime("Net70") + .SetNSwagRuntime("Net80") .SetProcessArgumentConfigurator(c => c .Add("/Template:Fetch") .Add("/GenerateClientClasses:True") - .Add("/GenerateOptionalParameters") .Add("/ClientBaseClass:ClientBase") .Add("/ConfigurationClass:ConfigureRequest") .Add("/UseTransformOptionsMethod:True") .Add("/MarkOptionalProperties:True") .Add($"/ExtensionCode:{ClientServicesDirectory / "client-base.ts"}") .Add("/UseGetBaseUrlMethod:True") - .Add("/ProtectedMethods=ClientBase.getBaseUrl,ClientBase.transformOptions") .Add("/UseAbortSignal:True"))); }); diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj index 7fb87fb..9e4b8dc 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/ProjectTemplate.csproj @@ -11,9 +11,10 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ItemController.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ItemController.cs index 21cbf14..e75da11 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ItemController.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ItemController.cs @@ -40,7 +40,6 @@ public ItemController(IItemService itemService) [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)] [SwaggerResponse(HttpStatusCode.OK, typeof(ItemViewModel), Description = "OK")] [SwaggerResponse(HttpStatusCode.BadRequest, typeof(string), Description = "Bad Request")] - [SwaggerResponse(HttpStatusCode.InternalServerError, typeof(Exception), Description = "Error")] public async Task CreateItem(CreateItemDTO item) { var result = await this.itemService.CreateItemAsync(item, this.UserInfo.UserID); @@ -58,7 +57,6 @@ public async Task CreateItem(CreateItemDTO item) HttpStatusCode.OK, typeof(ItemsPageViewModel), Description = "OK")] - [SwaggerResponse(HttpStatusCode.InternalServerError, typeof(Exception), Description = "Error")] public async Task GetItemsPage([FromUri] GetItemsPageDTO dto) { var page = await this.itemService.GetItemsPageAsync(dto.Query, dto.Page, dto.PageSize, dto.Descending); @@ -74,7 +72,6 @@ public async Task GetItemsPage([FromUri] GetItemsPageDTO dto) [ValidateAntiForgeryToken] [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)] [SwaggerResponse(HttpStatusCode.OK, typeof(void), Description = "OK")] - [SwaggerResponse(HttpStatusCode.InternalServerError, typeof(Exception), Description = "Error")] public async Task DeleteItem(int itemId) { await this.itemService.DeleteItemAsync(itemId); @@ -88,7 +85,6 @@ public async Task DeleteItem(int itemId) [HttpGet] [AllowAnonymous] [SwaggerResponse(HttpStatusCode.OK, typeof(bool), Description = "OK")] - [SwaggerResponse(HttpStatusCode.InternalServerError, typeof(Exception), Description = "Error")] public IHttpActionResult UserCanEdit() { return this.Ok(this.CanEdit); @@ -103,8 +99,6 @@ public IHttpActionResult UserCanEdit() [ValidateAntiForgeryToken] [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Edit)] [SwaggerResponse(HttpStatusCode.OK, null, Description = "OK")] - [SwaggerResponse(HttpStatusCode.BadRequest, typeof(ArgumentException), Description = "Malformed request")] - [SwaggerResponse(HttpStatusCode.InternalServerError, typeof(Exception), Description = "Error")] public async Task UpdateItem(UpdateItemDTO item) { await this.itemService.UpdateItemAsync(item, this.UserInfo.UserID); diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj index 82a171a..972de17 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj @@ -148,7 +148,7 @@ 13.0.3 - 13.19.0 + 14.1.0 1.1.118 diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn index da7a48f..2d5db20 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/manifest.dnn @@ -37,7 +37,7 @@ NSwag.Annotations.dll bin - 13.19.0 + 14.1.0 From 7252deb291a157a9eae4d6ef9d818846b4437c0e Mon Sep 17 00:00:00 2001 From: Daniel Valadas Date: Tue, 20 Aug 2024 22:58:04 -0400 Subject: [PATCH 21/41] Update dependabot.yml --- .github/dependabot.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 43ceb23..920f129 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,7 +6,7 @@ version: 2 updates: - package-ecosystem: "npm" - directory: "/" + directory: "/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web" schedule: interval: "monthly" - package-ecosystem: "nuget" @@ -14,7 +14,9 @@ updates: schedule: interval: "monthly" - package-ecosystem: "nuget" - directory: "/" + directories: + - "/Eraware_Dnn_Templates" + - "/Eraware_Dnn_Spa_Ef_Di_Stencil" schedule: interval: "monthly" ignore: From c8030dad6ec2f356c953c075798dce8d4283a99b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 03:22:39 +0000 Subject: [PATCH 22/41] Bump eslint-plugin-tsdoc in /Eraware_Dnn_Spa_Ef_Di_Stencil/module.web Bumps [eslint-plugin-tsdoc](https://github.com/microsoft/tsdoc/tree/HEAD/eslint-plugin) from 0.2.17 to 0.3.0. - [Changelog](https://github.com/microsoft/tsdoc/blob/main/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/microsoft/tsdoc/commits/eslint-plugin-tsdoc_v0.3.0/eslint-plugin) --- updated-dependencies: - dependency-name: eslint-plugin-tsdoc dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json index dfc0b3f..e0b8fb1 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json @@ -32,7 +32,7 @@ "@stencil/core": "^4.20.0", "@stencil/sass": "^3.0.2", "@stencil/store": "^2.0.0", - "eslint-plugin-tsdoc": "^0.2.11" + "eslint-plugin-tsdoc": "^0.3.0" }, "license": "MIT" } From 1a09181aeb245a78d0eee1671bed4a0003e10c66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 03:22:49 +0000 Subject: [PATCH 23/41] Bump @stencil-community/eslint-plugin Bumps [@stencil-community/eslint-plugin](https://github.com/stencil-community/stencil-eslint) from 0.5.0 to 0.8.0. - [Release notes](https://github.com/stencil-community/stencil-eslint/releases) - [Commits](https://github.com/stencil-community/stencil-eslint/compare/v0.5.0...v0.8.0) --- updated-dependencies: - dependency-name: "@stencil-community/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json index dfc0b3f..46a5f1f 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json @@ -28,7 +28,7 @@ "@dnncommunity/dnn-elements": "^0.23.3", "@microsoft/api-documenter": "^7.13.49", "@microsoft/api-extractor": "^7.18.9", - "@stencil-community/eslint-plugin": "^0.5.0", + "@stencil-community/eslint-plugin": "^0.8.0", "@stencil/core": "^4.20.0", "@stencil/sass": "^3.0.2", "@stencil/store": "^2.0.0", From 2e0951be64f59ac424aba76c1e35ee69e2792eda Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 02:16:30 -0400 Subject: [PATCH 24/41] Fixed some typos and bugs after dependency updates Fixed some typos and bugs after dependency updates --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs | 5 +++-- Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json | 2 +- Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/tsconfig.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs index f75e8ff..b66a3fb 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs @@ -723,9 +723,10 @@ class Build : NukeBuild var swaggerDir = DocsDirectory / "rest"; swaggerDir.CreateOrCleanDirectory(); var swaggerFile = DocsDirectory / "rest" / "rest.json"; - var assembly = RootDirectory / "bin" / Configuration / $"{ModuleName}.dll"; + var assembly = RootDirectory / "bin" / Configuration / $"{moduleName}.dll"; var version = GitVersion != null ? GitVersion.AssemblySemVer : "0.1.0"; - WebApiToOpenApiReflector($@"{assembly} --title "$ext_companyname$ $ext_modulefriendlyname$"" --info-version {version} --default-url-template {{controller}}/{{action}} --output {swaggerFile}"); + var title = "$ext_companyname$ $ext_modulefriendlyname$"; + WebApiToOpenApiReflector($@"{assembly} --title {title} --info-version {version} --default-url-template {{controller}}/{{action}} --output {swaggerFile}"); NSwagTasks.NSwagOpenApiToTypeScriptClient(c => c .SetInput(swaggerFile) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json index 44373f4..cac6a90 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/package.json @@ -22,7 +22,7 @@ "test": "stencil test --spec --e2e", "test.watch": "stencil test --spec --e2e --watchAll", "generate": "stencil generate", - "tsdoc": "tsc ./src/services/services.ts --declaration --emitDeclarationOnly --target es2017 --moduleResolution nodenext && api-extractor run --local && api-documenter markdown -i temp -o tempmd" + "tsdoc": "tsc src/services/services.ts --declaration --emitDeclarationOnly --target es2017 --moduleResolution nodenext --module nodenext && api-extractor run --local && api-documenter markdown -i temp -o tempmd" }, "devDependencies": { "@dnncommunity/dnn-elements": "^0.23.3", diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/tsconfig.json b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/tsconfig.json index 8eaf127..5d5ba04 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/tsconfig.json +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module.web/tsconfig.json @@ -9,7 +9,7 @@ "dom", "es2017" ], - "moduleResolution": "node", + "moduleResolution": "NodeNext", "module": "esnext", "target": "es2017", "noUnusedLocals": true, From 010392cc894c8d6a647899a65eeb5d73fa9ab730 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 15:06:17 -0400 Subject: [PATCH 25/41] Bumped xunit to v2.9.0 Bumped xunit to v2.9.0 --- .../IntegrationTests/ProjectTemplate.csproj | 6 +++--- .../UnitTests/ProjectTemplate.csproj | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj index 948f51a..b959f70 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj @@ -42,11 +42,11 @@ - - + + all - + all diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj index 7a4f5c3..599c62e 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj @@ -50,11 +50,11 @@ - - + + all - + all From 8b5f19feefda2000bf687035cf45277ed6dbf797 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 15:10:31 -0400 Subject: [PATCH 26/41] Bumped Moq to v4.20.70 Bumped Moq to v4.20.70 --- .../IntegrationTests/ProjectTemplate.csproj | 2 +- Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj index 948f51a..d90d4d5 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj @@ -38,7 +38,7 @@ - + diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj index 7a4f5c3..afa4095 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj @@ -46,7 +46,7 @@ - + From 1b5143cbb2b4b7c063e7ebdd1043899e680ef859 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 15:15:52 -0400 Subject: [PATCH 27/41] Bumped coverlet to 6.0.1 Bumped coverlet to 6.0.1 --- .github/dependabot.yml | 3 +++ .../IntegrationTests/ProjectTemplate.csproj | 4 ++-- .../UnitTests/ProjectTemplate.csproj | 4 ++-- Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml | 3 +++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 920f129..48ef7aa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -35,3 +35,6 @@ updates: nswag: patterns: - "NSwag*" + coverlet: + patterns: + - "coverlet*" diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj index b959f70..379498f 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj @@ -24,10 +24,10 @@ - + all - + all diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj index 599c62e..6182115 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj @@ -32,10 +32,10 @@ - + all - + all diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml index 1766d7b..bcbf066 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/.github/dependabot.yml @@ -29,3 +29,6 @@ updates: nswag: patterns: - "NSwag*" + coverlet: + patterns: + - "coverlet*" From 29063b2b5ac852068454be7ad19aeeaf79d49a3f Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 15:23:01 -0400 Subject: [PATCH 28/41] Fixed inconsistencies with last EntityFramework update The version was not bumped everywhere and a config was wrong possibly causing flaky tests. --- Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/App.Config | 1 - Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/App.config | 1 - Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/App.Config b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/App.Config index d5ca425..2a93f43 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/App.Config +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/App.Config @@ -14,7 +14,6 @@ - diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/App.config b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/App.config index d5ca425..2a93f43 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/App.config +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/App.config @@ -14,7 +14,6 @@ - diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj index 972de17..33e6bce 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj @@ -134,7 +134,7 @@ 9.13.4 - 6.4.4 + 6.5.1 5.2.9 From 801f7354b9af67d51acb7e2abe2377d3322d3bec Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 15:25:43 -0400 Subject: [PATCH 29/41] Disabled caching in CI builds Closes #720 --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs index b66a3fb..ce3aa07 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs @@ -48,7 +48,8 @@ OnPullRequestBranches = new[] { "develop", "main", "master", "release/*" }, OnPushBranches = new[] { "main", "master", "develop", "release/*" }, InvokedTargets = new[] { nameof(Package), nameof(DeployGeneratedFiles), nameof(Release) }, - FetchDepth = 0 + FetchDepth = 0, + CacheKeyFiles = new string[] { } )] [UnsetVisualStudioEnvironmentVariables] class Build : NukeBuild From 97f205bed52c7895643e121403083ed562a1742b Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 15:38:46 -0400 Subject: [PATCH 30/41] Bumped Effort.EF6 to v2.2.17 Bumped Effort.EF6 to v2.2.17 --- .../IntegrationTests/ProjectTemplate.csproj | 2 +- Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj index d427a6b..07c5e66 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj @@ -35,7 +35,7 @@ - + diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj index 3fea3cf..8849107 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj @@ -43,7 +43,7 @@ - + From d1a245dca2304c0a2e27430b55ec4ecd19f9d869 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 16:06:52 -0400 Subject: [PATCH 31/41] Migrated to nuke with github actions Migrated to nuke with github actions --- .github/workflows/Build.yml | 47 ++++++++ .nuke/build.schema.json | 110 ++++++++++++++++++ .nuke/parameters.json | 4 + .../Eraware_Dnn_Spa_Ef_Di_Stencil.csproj | 1 + Eraware_Dnn_Templates.sln | 4 + .../Eraware_Dnn_Templates.csproj | 1 + build.cmd | 7 ++ build.ps1 | 74 ++++++++++++ build.sh | 67 +++++++++++ build/.editorconfig | 11 ++ build/Build.cs | 75 ++++++++++++ build/Configuration.cs | 16 +++ build/Directory.Build.props | 8 ++ build/Directory.Build.targets | 8 ++ build/_build.csproj | 18 +++ build/_build.csproj.DotSettings | 27 +++++ 16 files changed, 478 insertions(+) create mode 100644 .github/workflows/Build.yml create mode 100644 .nuke/build.schema.json create mode 100644 .nuke/parameters.json create mode 100755 build.cmd create mode 100644 build.ps1 create mode 100755 build.sh create mode 100644 build/.editorconfig create mode 100644 build/Build.cs create mode 100644 build/Configuration.cs create mode 100644 build/Directory.Build.props create mode 100644 build/Directory.Build.targets create mode 100644 build/_build.csproj create mode 100644 build/_build.csproj.DotSettings diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml new file mode 100644 index 0000000..78bcc27 --- /dev/null +++ b/.github/workflows/Build.yml @@ -0,0 +1,47 @@ +# ------------------------------------------------------------------------------ +# +# +# This code was generated. +# +# - To turn off auto-generation set: +# +# [GitHubActions (AutoGenerate = false)] +# +# - To trigger manual generation invoke: +# +# nuke --generate-configuration GitHubActions_Build --host GitHubActions +# +# +# ------------------------------------------------------------------------------ + +name: Build + +on: + push: + branches: + - master + - develop + - 'release/*' + pull_request: + branches: + - master + - main + - develop + - development + - 'release/*' + +jobs: + ubuntu-latest: + name: ubuntu-latest + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: 'Run: Compile' + run: ./build.cmd Compile + - name: 'Publish: artifacts' + uses: actions/upload-artifact@v3 + with: + name: artifacts + path: artifacts diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json new file mode 100644 index 0000000..db869b0 --- /dev/null +++ b/.nuke/build.schema.json @@ -0,0 +1,110 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/build", + "title": "Build Schema", + "definitions": { + "build": { + "type": "object", + "properties": { + "Configuration": { + "type": "string", + "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)", + "enum": [ + "Debug", + "Release" + ] + }, + "Continue": { + "type": "boolean", + "description": "Indicates to continue a previously failed build attempt" + }, + "Help": { + "type": "boolean", + "description": "Shows the help text for this build assembly" + }, + "Host": { + "type": "string", + "description": "Host for execution. Default is 'automatic'", + "enum": [ + "AppVeyor", + "AzurePipelines", + "Bamboo", + "Bitbucket", + "Bitrise", + "GitHubActions", + "GitLab", + "Jenkins", + "Rider", + "SpaceAutomation", + "TeamCity", + "Terminal", + "TravisCI", + "VisualStudio", + "VSCode" + ] + }, + "NoLogo": { + "type": "boolean", + "description": "Disables displaying the NUKE logo" + }, + "Partition": { + "type": "string", + "description": "Partition to use on CI" + }, + "Plan": { + "type": "boolean", + "description": "Shows the execution plan (HTML)" + }, + "Profile": { + "type": "array", + "description": "Defines the profiles to load", + "items": { + "type": "string" + } + }, + "Root": { + "type": "string", + "description": "Root directory during build execution" + }, + "Skip": { + "type": "array", + "description": "List of targets to be skipped. Empty list skips all dependencies", + "items": { + "type": "string", + "enum": [ + "Clean", + "Compile", + "Restore" + ] + } + }, + "Solution": { + "type": "string", + "description": "Path to a solution file that is automatically loaded" + }, + "Target": { + "type": "array", + "description": "List of targets to be invoked. Default is '{default_target}'", + "items": { + "type": "string", + "enum": [ + "Clean", + "Compile", + "Restore" + ] + } + }, + "Verbosity": { + "type": "string", + "description": "Logging verbosity during build execution. Default is 'Normal'", + "enum": [ + "Minimal", + "Normal", + "Quiet", + "Verbose" + ] + } + } + } + } +} diff --git a/.nuke/parameters.json b/.nuke/parameters.json new file mode 100644 index 0000000..1a426d9 --- /dev/null +++ b/.nuke/parameters.json @@ -0,0 +1,4 @@ +{ + "$schema": "./build.schema.json", + "Solution": "Eraware_Dnn_Templates.sln" +} diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj index 182cec1..dc38fb9 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj @@ -3,6 +3,7 @@ 16.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + win diff --git a/Eraware_Dnn_Templates.sln b/Eraware_Dnn_Templates.sln index 32bdb3a..16e2733 100644 --- a/Eraware_Dnn_Templates.sln +++ b/Eraware_Dnn_Templates.sln @@ -12,12 +12,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt LICENSE = LICENSE EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{DEC1FDF7-0D64-4992-BB69-0E15EA6E8088}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DEC1FDF7-0D64-4992-BB69-0E15EA6E8088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DEC1FDF7-0D64-4992-BB69-0E15EA6E8088}.Release|Any CPU.ActiveCfg = Release|Any CPU {1AABA73D-8159-4BD7-BD86-F711E9BF8106}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1AABA73D-8159-4BD7-BD86-F711E9BF8106}.Debug|Any CPU.Build.0 = Debug|Any CPU {1AABA73D-8159-4BD7-BD86-F711E9BF8106}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj b/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj index 3a3e965..b6958c4 100644 --- a/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj +++ b/Eraware_Dnn_Templates/Eraware_Dnn_Templates.csproj @@ -3,6 +3,7 @@ 16.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + win true diff --git a/build.cmd b/build.cmd new file mode 100755 index 0000000..b08cc59 --- /dev/null +++ b/build.cmd @@ -0,0 +1,7 @@ +:; set -eo pipefail +:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) +:; ${SCRIPT_DIR}/build.sh "$@" +:; exit $? + +@ECHO OFF +powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %* diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..4634dc0 --- /dev/null +++ b/build.ps1 @@ -0,0 +1,74 @@ +[CmdletBinding()] +Param( + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$BuildArguments +) + +Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)" + +Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 } +$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent + +########################################################################### +# CONFIGURATION +########################################################################### + +$BuildProjectFile = "$PSScriptRoot\build\_build.csproj" +$TempDirectory = "$PSScriptRoot\\.nuke\temp" + +$DotNetGlobalFile = "$PSScriptRoot\\global.json" +$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1" +$DotNetChannel = "STS" + +$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 +$env:DOTNET_NOLOGO = 1 + +########################################################################### +# EXECUTION +########################################################################### + +function ExecSafe([scriptblock] $cmd) { + & $cmd + if ($LASTEXITCODE) { exit $LASTEXITCODE } +} + +# If dotnet CLI is installed globally and it matches requested version, use for execution +if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and ` + $(dotnet --version) -and $LASTEXITCODE -eq 0) { + $env:DOTNET_EXE = (Get-Command "dotnet").Path +} +else { + # Download install script + $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1" + New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile) + + # If global.json exists, load expected version + if (Test-Path $DotNetGlobalFile) { + $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json) + if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) { + $DotNetVersion = $DotNetGlobal.sdk.version + } + } + + # Install by channel or version + $DotNetDirectory = "$TempDirectory\dotnet-win" + if (!(Test-Path variable:DotNetVersion)) { + ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } + } else { + ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } + } + $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" + $env:PATH = "$DotNetDirectory;$env:PATH" +} + +Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)" + +if (Test-Path env:NUKE_ENTERPRISE_TOKEN) { + & $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null + & $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null +} + +ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet } +ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments } diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..fdff0c6 --- /dev/null +++ b/build.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +bash --version 2>&1 | head -n 1 + +set -eo pipefail +SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) + +########################################################################### +# CONFIGURATION +########################################################################### + +BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj" +TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" + +DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" +DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" +DOTNET_CHANNEL="STS" + +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +export DOTNET_NOLOGO=1 + +########################################################################### +# EXECUTION +########################################################################### + +function FirstJsonValue { + perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}" +} + +# If dotnet CLI is installed globally and it matches requested version, use for execution +if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then + export DOTNET_EXE="$(command -v dotnet)" +else + # Download install script + DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" + mkdir -p "$TEMP_DIRECTORY" + curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" + chmod +x "$DOTNET_INSTALL_FILE" + + # If global.json exists, load expected version + if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then + DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")") + if [[ "$DOTNET_VERSION" == "" ]]; then + unset DOTNET_VERSION + fi + fi + + # Install by channel or version + DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" + if [[ -z ${DOTNET_VERSION+x} ]]; then + "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path + else + "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path + fi + export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" + export PATH="$DOTNET_DIRECTORY:$PATH" +fi + +echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" + +if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then + "$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true + "$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true +fi + +"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet +"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" diff --git a/build/.editorconfig b/build/.editorconfig new file mode 100644 index 0000000..31e43dc --- /dev/null +++ b/build/.editorconfig @@ -0,0 +1,11 @@ +[*.cs] +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_property = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_event = false:warning +dotnet_style_require_accessibility_modifiers = never:warning + +csharp_style_expression_bodied_methods = true:silent +csharp_style_expression_bodied_properties = true:warning +csharp_style_expression_bodied_indexers = true:warning +csharp_style_expression_bodied_accessors = true:warning diff --git a/build/Build.cs b/build/Build.cs new file mode 100644 index 0000000..296d1ff --- /dev/null +++ b/build/Build.cs @@ -0,0 +1,75 @@ +using System; +using System.Linq; +using Nuke.Common; +using Nuke.Common.CI; +using Nuke.Common.CI.GitHubActions; +using Nuke.Common.Execution; +using Nuke.Common.IO; +using Nuke.Common.ProjectModel; +using Nuke.Common.Tooling; +using Nuke.Common.Tools.DotNet; +using Nuke.Common.Tools.MSBuild; +using Nuke.Common.Utilities.Collections; +using Octokit; +using static Nuke.Common.EnvironmentInfo; +using static Nuke.Common.IO.FileSystemTasks; +using static Nuke.Common.IO.PathConstruction; +using static Nuke.Common.Tools.DotNet.DotNetTasks; +using static Nuke.Common.Tools.MSBuild.MSBuildTasks; + +[GitHubActions( + "Build", + GitHubActionsImage.UbuntuLatest, + OnPullRequestBranches = new[] { "master", "main", "develop", "development", "release/*" }, + OnPushBranches = new[] { "master", "develop", "release/*" }, + InvokedTargets = new[] { nameof(Compile) }, + FetchDepth = 0, + CacheKeyFiles = new string[0] + )] +class Build : NukeBuild +{ + /// Support plugins are available for: + /// - JetBrains ReSharper https://nuke.build/resharper + /// - JetBrains Rider https://nuke.build/rider + /// - Microsoft VisualStudio https://nuke.build/visualstudio + /// - Microsoft VSCode https://nuke.build/vscode + + public static int Main () => Execute(x => x.Compile); + + [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] + readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; + + [Solution] readonly Solution Solution; + + AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts"; + + Target Clean => _ => _ + .Before(Restore) + .Executes(() => + { + ArtifactsDirectory.CreateOrCleanDirectory(); + }); + + Target Restore => _ => _ + .Executes(() => + { + var projects = Solution.GetAllProjects("*"); + + foreach (var project in projects.Where(p => p.Name != "_build")) + { + DotNetRestore(s => s + .SetProjectFile(project)); + } + }); + + Target Compile => _ => _ + .DependsOn(Restore) + .Produces(ArtifactsDirectory / "*.vsix") + .Executes(() => + { + MSBuild(s => s + .SetTargetPath(Solution) + .SetConfiguration(Configuration)); + }); + +} diff --git a/build/Configuration.cs b/build/Configuration.cs new file mode 100644 index 0000000..9c08b1a --- /dev/null +++ b/build/Configuration.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel; +using System.Linq; +using Nuke.Common.Tooling; + +[TypeConverter(typeof(TypeConverter))] +public class Configuration : Enumeration +{ + public static Configuration Debug = new Configuration { Value = nameof(Debug) }; + public static Configuration Release = new Configuration { Value = nameof(Release) }; + + public static implicit operator string(Configuration configuration) + { + return configuration.Value; + } +} diff --git a/build/Directory.Build.props b/build/Directory.Build.props new file mode 100644 index 0000000..e147d63 --- /dev/null +++ b/build/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/build/Directory.Build.targets b/build/Directory.Build.targets new file mode 100644 index 0000000..2532609 --- /dev/null +++ b/build/Directory.Build.targets @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/build/_build.csproj b/build/_build.csproj new file mode 100644 index 0000000..b1965fa --- /dev/null +++ b/build/_build.csproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0 + + CS0649;CS0169;CA1050;CA1822;CA2211;IDE1006 + .. + .. + 1 + false + + + + + + + diff --git a/build/_build.csproj.DotSettings b/build/_build.csproj.DotSettings new file mode 100644 index 0000000..a778f33 --- /dev/null +++ b/build/_build.csproj.DotSettings @@ -0,0 +1,27 @@ + + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + Implicit + Implicit + ExpressionBody + 0 + NEXT_LINE + True + False + 120 + IF_OWNER_IS_SINGLE_LINE + WRAP_IF_LONG + False + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True + True + True + True + True + True + True + True From 095703cf7c018aeb70b27634d204ceb366beffba Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 16:16:41 -0400 Subject: [PATCH 32/41] Switched to a windows runner --- .github/workflows/Build.yml | 6 +++--- build/Build.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 78bcc27..947b38a 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -31,9 +31,9 @@ on: - 'release/*' jobs: - ubuntu-latest: - name: ubuntu-latest - runs-on: ubuntu-latest + windows-latest: + name: windows-latest + runs-on: windows-latest steps: - uses: actions/checkout@v3 with: diff --git a/build/Build.cs b/build/Build.cs index 296d1ff..a0fef59 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -19,7 +19,7 @@ [GitHubActions( "Build", - GitHubActionsImage.UbuntuLatest, + GitHubActionsImage.WindowsLatest, OnPullRequestBranches = new[] { "master", "main", "develop", "development", "release/*" }, OnPushBranches = new[] { "master", "develop", "release/*" }, InvokedTargets = new[] { nameof(Compile) }, From 7ce76c549c1fbdbf24d39b3683b510ad52198ea6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 16:27:54 -0400 Subject: [PATCH 33/41] Moved buidl result to artifacts directory --- .github/workflows/Build.yml | 4 ++-- .nuke/build.schema.json | 2 ++ build/Build.cs | 12 ++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 947b38a..dc3d6ac 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -38,8 +38,8 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - - name: 'Run: Compile' - run: ./build.cmd Compile + - name: 'Run: CI' + run: ./build.cmd CI - name: 'Publish: artifacts' uses: actions/upload-artifact@v3 with: diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index db869b0..3ca5c22 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -72,6 +72,7 @@ "items": { "type": "string", "enum": [ + "CI", "Clean", "Compile", "Restore" @@ -88,6 +89,7 @@ "items": { "type": "string", "enum": [ + "CI", "Clean", "Compile", "Restore" diff --git a/build/Build.cs b/build/Build.cs index a0fef59..7b85226 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -22,7 +22,7 @@ GitHubActionsImage.WindowsLatest, OnPullRequestBranches = new[] { "master", "main", "develop", "development", "release/*" }, OnPushBranches = new[] { "master", "develop", "release/*" }, - InvokedTargets = new[] { nameof(Compile) }, + InvokedTargets = new[] { nameof(CI) }, FetchDepth = 0, CacheKeyFiles = new string[0] )] @@ -42,6 +42,7 @@ class Build : NukeBuild [Solution] readonly Solution Solution; AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts"; + AbsolutePath TemplateProjectDirectory => RootDirectory / "Eraware_Dnn_Templates"; Target Clean => _ => _ .Before(Restore) @@ -64,7 +65,6 @@ class Build : NukeBuild Target Compile => _ => _ .DependsOn(Restore) - .Produces(ArtifactsDirectory / "*.vsix") .Executes(() => { MSBuild(s => s @@ -72,4 +72,12 @@ class Build : NukeBuild .SetConfiguration(Configuration)); }); + Target CI => _ => _ + .DependsOn(Compile) + .Produces(ArtifactsDirectory / "*.vsix") + .Executes(() => + { + var vsix = TemplateProjectDirectory / "bin" / Configuration / "Eraware_Dnn_Templates.vsix"; + CopyFileToDirectory(vsix, ArtifactsDirectory, FileExistsPolicy.Overwrite); + }); } From 13f97eb32a58d20648924cbb1d059d3012a85757 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 20:04:34 -0400 Subject: [PATCH 34/41] Added release steps --- .github/workflows/Build.yml | 2 + .nuke/build.schema.json | 8 +- Eraware_Dnn_Templates.sln | 4 +- .../source.extension.vsixmanifest | 82 +++++++++---------- build/Build.cs | 75 ++++++++++++++++- build/_build.csproj | 4 + 6 files changed, 129 insertions(+), 46 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index dc3d6ac..c926e00 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -40,6 +40,8 @@ jobs: fetch-depth: 0 - name: 'Run: CI' run: ./build.cmd CI + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: 'Publish: artifacts' uses: actions/upload-artifact@v3 with: diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 3ca5c22..5a3dc5b 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -75,7 +75,9 @@ "CI", "Clean", "Compile", - "Restore" + "Release", + "Restore", + "SetVsixVersion" ] } }, @@ -92,7 +94,9 @@ "CI", "Clean", "Compile", - "Restore" + "Release", + "Restore", + "SetVsixVersion" ] } }, diff --git a/Eraware_Dnn_Templates.sln b/Eraware_Dnn_Templates.sln index 16e2733..18fd984 100644 --- a/Eraware_Dnn_Templates.sln +++ b/Eraware_Dnn_Templates.sln @@ -20,8 +20,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DEC1FDF7-0D64-4992-BB69-0E15EA6E8088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DEC1FDF7-0D64-4992-BB69-0E15EA6E8088}.Release|Any CPU.ActiveCfg = Release|Any CPU {1AABA73D-8159-4BD7-BD86-F711E9BF8106}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1AABA73D-8159-4BD7-BD86-F711E9BF8106}.Debug|Any CPU.Build.0 = Debug|Any CPU {1AABA73D-8159-4BD7-BD86-F711E9BF8106}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -30,6 +28,8 @@ Global {6C652B7C-F011-419E-B90D-F75AB49A8F4B}.Debug|Any CPU.Build.0 = Debug|Any CPU {6C652B7C-F011-419E-B90D-F75AB49A8F4B}.Release|Any CPU.ActiveCfg = Release|Any CPU {6C652B7C-F011-419E-B90D-F75AB49A8F4B}.Release|Any CPU.Build.0 = Release|Any CPU + {DEC1FDF7-0D64-4992-BB69-0E15EA6E8088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DEC1FDF7-0D64-4992-BB69-0E15EA6E8088}.Release|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Eraware_Dnn_Templates/source.extension.vsixmanifest b/Eraware_Dnn_Templates/source.extension.vsixmanifest index 19f0f9a..e604dff 100644 --- a/Eraware_Dnn_Templates/source.extension.vsixmanifest +++ b/Eraware_Dnn_Templates/source.extension.vsixmanifest @@ -1,42 +1,42 @@ - + - - - Eraware_Dnn_Templates - A WebAPI/WebComponents module template for DNN extensions. - LICENSE - https://github.com/valadas/Eraware_Dnn_Templates#readme - Eraware.ico - dnn - - - - x86 - - - x86 - - - x86 - - - amd64 - - - amd64 - - - amd64 - - - - - - - - - - - - - + + + Eraware_Dnn_Templates + A WebAPI/WebComponents module template for DNN extensions. + LICENSE + https://github.com/valadas/Eraware_Dnn_Templates#readme + Eraware.ico + dnn + + + + x86 + + + x86 + + + x86 + + + amd64 + + + amd64 + + + amd64 + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/Build.cs b/build/Build.cs index 7b85226..d91f4b0 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -1,13 +1,18 @@ using System; +using System.IO; using System.Linq; +using System.Xml; using Nuke.Common; using Nuke.Common.CI; using Nuke.Common.CI.GitHubActions; using Nuke.Common.Execution; +using Nuke.Common.Git; using Nuke.Common.IO; using Nuke.Common.ProjectModel; using Nuke.Common.Tooling; using Nuke.Common.Tools.DotNet; +using Nuke.Common.Tools.GitHub; +using Nuke.Common.Tools.GitVersion; using Nuke.Common.Tools.MSBuild; using Nuke.Common.Utilities.Collections; using Octokit; @@ -15,11 +20,13 @@ using static Nuke.Common.IO.FileSystemTasks; using static Nuke.Common.IO.PathConstruction; using static Nuke.Common.Tools.DotNet.DotNetTasks; +using static Nuke.Common.Tools.GitHub.GitHubTasks; using static Nuke.Common.Tools.MSBuild.MSBuildTasks; [GitHubActions( "Build", GitHubActionsImage.WindowsLatest, + EnableGitHubToken = true, OnPullRequestBranches = new[] { "master", "main", "develop", "development", "release/*" }, OnPushBranches = new[] { "master", "develop", "release/*" }, InvokedTargets = new[] { nameof(CI) }, @@ -40,6 +47,11 @@ class Build : NukeBuild readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; [Solution] readonly Solution Solution; + [GitRepository] readonly GitRepository GitRepository; + [GitVersion(UpdateAssemblyInfo = false)] readonly GitVersion GitVersion; + + static GitHubActions GitHubActions => GitHubActions.Instance; + static readonly string PackageContentType = "application/octet-stream"; AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts"; AbsolutePath TemplateProjectDirectory => RootDirectory / "Eraware_Dnn_Templates"; @@ -63,21 +75,82 @@ class Build : NukeBuild } }); + Target SetVsixVersion => _ => _ + .DependsOn(Restore) + .Executes(() => + { + var manifestFile = TemplateProjectDirectory / "source.extension.vsixmanifest"; + var manifest = new XmlDocument(); + manifest.Load(manifestFile); + var metadataNode = manifest.DocumentElement.ChildNodes.Cast().First(n => n.Name == "Metadata") as XmlElement; + var identityNode = metadataNode.ChildNodes.Cast().First(n => n.Name == "Identity") as XmlElement; + var versionAttribute = identityNode.Attributes["Version"]; + versionAttribute.Value = GitVersion.MajorMinorPatch; + manifest.Save(manifestFile); + }); + Target Compile => _ => _ .DependsOn(Restore) + .DependsOn(SetVsixVersion) .Executes(() => { MSBuild(s => s .SetTargetPath(Solution) - .SetConfiguration(Configuration)); + .SetConfiguration(Configuration) + .SetAssemblyVersion(GitVersion.AssemblySemVer) + .SetFileVersion(GitVersion.MajorMinorPatch) + .SetPackageVersion(GitVersion.MajorMinorPatch)); }); Target CI => _ => _ + .Description("Handles everything needed for CI") .DependsOn(Compile) .Produces(ArtifactsDirectory / "*.vsix") + .Triggers(Release) .Executes(() => { var vsix = TemplateProjectDirectory / "bin" / Configuration / "Eraware_Dnn_Templates.vsix"; CopyFileToDirectory(vsix, ArtifactsDirectory, FileExistsPolicy.Overwrite); }); + + Target Release => _ => _ + .OnlyWhenStatic(() => GitRepository.IsOnReleaseBranch() || GitRepository.IsOnMainOrMasterBranch()) + .Requires(() => Configuration.Equals(Configuration.Release)) + .Executes(async () => + { + var credentials = new Credentials(GitHubActions.Token); + GitHubTasks.GitHubClient = new GitHubClient(new ProductHeaderValue("Eraware.Dnn.Templates")) + { + Credentials = credentials, + }; + var (owner, name) = (GitRepository.GetGitHubOwner(), GitRepository.GetGitHubName()); + + var newRelease = new NewRelease(GitVersion.FullSemVer) + { + Draft = true, + Name = $"v{GitVersion.FullSemVer}", + GenerateReleaseNotes = true, + TargetCommitish = GitVersion.Sha, + Prerelease = GitRepository.IsOnReleaseBranch(), + }; + + var createdRelease = await GitHubTasks + .GitHubClient + .Repository + .Release + .Create(owner, name, newRelease); + + ArtifactsDirectory.GlobFiles("*") + .ForEach(async file => + { + await using var artifactStream = File.OpenRead(file); + var fileName = Path.GetFileName(file); + var assetUpload = new ReleaseAssetUpload + { + FileName = fileName, + }; + }); + + }); + } diff --git a/build/_build.csproj b/build/_build.csproj index b1965fa..f4c817f 100644 --- a/build/_build.csproj +++ b/build/_build.csproj @@ -15,4 +15,8 @@ + + + + From d187c304f0032ba4629cda383f22b9114d6daf32 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 20:07:07 -0400 Subject: [PATCH 35/41] Removed azure pipelines config --- azure-pipelines.yml | 51 --------------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 azure-pipelines.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index e3a3123..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,51 +0,0 @@ -# ASP.NET -# Build and test ASP.NET projects. -# Add steps that publish symbols, save build artifacts, deploy, and more: -# https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4 - -trigger: -- master -- develop -- release - -pool: - vmImage: 'windows-latest' - -variables: - solution: '**/*.sln' - buildPlatform: 'Any CPU' - buildConfiguration: 'Release' - -steps: -- task: NuGetToolInstaller@1 - -- task: NuGetCommand@2 - inputs: - restoreSolution: '$(solution)' - -- task: VSBuild@1 - inputs: - solution: '$(solution)' - msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"' - platform: '$(buildPlatform)' - configuration: '$(buildConfiguration)' - -- task: VSTest@2 - inputs: - platform: '$(buildPlatform)' - configuration: '$(buildConfiguration)' - -- task: CopyFiles@2 - inputs: - SourceFolder: 'Eraware_Dnn_Templates\bin\Release' - Contents: '*.vsix' - TargetFolder: '$(Build.ArtifactStagingDirectory)' - CleanTargetFolder: true - OverWrite: true - flattenFolders: true - -- task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: '$(Build.ArtifactStagingDirectory)' - ArtifactName: 'drop' - publishLocation: Container \ No newline at end of file From e8926ff4cbbf6a544cd7c0d8c871261910a384a7 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 21 Aug 2024 21:17:00 -0400 Subject: [PATCH 36/41] Fixed an async unit test Closes #702 --- .../Controllers/ModuleExceptionFilterAttributeTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs index 4218095..4cba76f 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs @@ -56,7 +56,7 @@ public static void ArgumentException_BadRequest( } [Fact] - public static void SystemException_DoesNotExposeDetails() + public async Task SystemException_DoesNotExposeDetails() { var attribute = new ModuleExceptionFilterAttribute(); var loggerSource = new Mock(); @@ -72,7 +72,8 @@ public static void SystemException_DoesNotExposeDetails() attribute.OnException(actionExecutedContext); Assert.Equal(HttpStatusCode.InternalServerError, actionExecutedContext.Response.StatusCode); - Assert.NotEqual("Danger", actionExecutedContext.Response.Content.ReadAsStringAsync().Result); + var response = await actionExecutedContext.Response.Content.ReadAsStringAsync(); + Assert.NotEqual("Danger", response); } public static IEnumerable GetExceptionsTestData() From 00e905866e887859065444a4e7a5d55ecda6f980 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 22 Aug 2024 17:04:31 -0400 Subject: [PATCH 37/41] Replaced validations from Exceptions to OneOf/FluentValidation Closes #428 Closes #701 Closes #729 --- .../Eraware_Dnn_Spa_Ef_Di_Stencil.csproj | 32 ++--- .../Controllers/ItemControllerTests.cs | 40 +++++- .../Controllers/ItemControllerTests.cs | 18 ++- .../LocalizationControllerTests.cs | 3 +- .../ModuleExceptionFilterAttributeTests.cs | 118 ---------------- .../ValidateModelAttributeTests.cs | 49 ------- .../Items/CreateItemDtoValidatorTests.cs | 52 +++++++ .../Services/{ => Items}/ItemServiceTests.cs | 127 ++++++++++-------- .../Items/UpdateItemDtoValidatorTests.cs | 93 +++++++++++++ .../UnitTests/StartupTests.cs | 6 +- .../UnitTests/UnitTests.vstemplate | 8 +- .../build/Helpers.cs | 11 +- .../module/Controllers/ItemController.cs | 18 +-- .../Controllers/LocalizationController.cs | 3 +- .../module/Controllers/ModuleApiController.cs | 2 - .../ModuleExceptionFilterAttribute.cs | 88 ------------ .../Controllers/ValidateModelAttribute.cs | 64 --------- .../module/Module.vstemplate | 33 ++--- .../module/ProjectTemplate.csproj | 30 +++-- .../module/Services/ItemService.cs | 105 --------------- .../{DTO => Services/Items}/CreateItemDTO.cs | 5 +- .../Services/Items/CreateItemDtoValidator.cs | 27 ++++ .../Items}/GetItemsPageDTO.cs | 2 +- .../Services/{ => Items}/IItemService.cs | 20 ++- .../module/Services/Items/ItemService.cs | 112 +++++++++++++++ .../Items}/ItemViewModel.cs | 3 +- .../Items}/ItemsPageViewModel.cs | 2 +- .../{DTO => Services/Items}/UpdateItemDTO.cs | 5 +- .../Services/Items/UpdateItemDtoValidator.cs | 29 ++++ .../ILocalizationService.cs | 3 +- .../{ => Localization}/LocalizationService.cs | 6 +- .../Localization}/LocalizationViewModel.cs | 2 +- .../module/Startup.cs | 8 +- .../articles/project-architecture.md | 70 ++++++---- 34 files changed, 581 insertions(+), 613 deletions(-) delete mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs delete mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ValidateModelAttributeTests.cs create mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/CreateItemDtoValidatorTests.cs rename Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/{ => Items}/ItemServiceTests.cs (50%) create mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/UpdateItemDtoValidatorTests.cs delete mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleExceptionFilterAttribute.cs delete mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ValidateModelAttribute.cs delete mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ItemService.cs rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/{DTO => Services/Items}/CreateItemDTO.cs (78%) create mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/CreateItemDtoValidator.cs rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/{DTO => Services/Items}/GetItemsPageDTO.cs (94%) rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/{ => Items}/IItemService.cs (66%) create mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemService.cs rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/{ViewModels => Services/Items}/ItemViewModel.cs (94%) rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/{ViewModels => Services/Items}/ItemsPageViewModel.cs (95%) rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/{DTO => Services/Items}/UpdateItemDTO.cs (69%) create mode 100644 Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/UpdateItemDtoValidator.cs rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/{ => Localization}/ILocalizationService.cs (82%) rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/{ => Localization}/LocalizationService.cs (94%) rename Eraware_Dnn_Spa_Ef_Di_Stencil/module/{ViewModels => Services/Localization}/LocalizationViewModel.cs (98%) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj index dc38fb9..123d6c5 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/Eraware_Dnn_Spa_Ef_Di_Stencil.csproj @@ -3,7 +3,7 @@ 16.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - win + win @@ -191,6 +191,10 @@ + + + + @@ -198,20 +202,18 @@ - + - - - - + + - - - - - + + + + + @@ -232,14 +234,12 @@ - + - - - - + + diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ItemControllerTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ItemControllerTests.cs index be5c93d..5043873 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ItemControllerTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ItemControllerTests.cs @@ -1,11 +1,11 @@ using $ext_rootnamespace$.Controllers; using $ext_rootnamespace$.Data.Entities; using $ext_rootnamespace$.Data.Repositories; -using $ext_rootnamespace$.DTO; using $ext_rootnamespace$.Providers; -using $ext_rootnamespace$.Services; -using $ext_rootnamespace$.ViewModels; +using $ext_rootnamespace$.Services.Items; +using $ext_rootnamespace$.Services.Localization; using DotNetNuke.Entities.Users; +using FluentValidation; using Moq; using System; using System.Linq; @@ -20,6 +20,9 @@ public class ItemControllerTests : FakeDataContext private readonly Mock dateTimeProvider; private readonly IRepository itemRepository; private readonly IItemService itemService; + private readonly IValidator createItemDtoValidator; + private readonly IValidator updateItemDtoValidator; + private readonly Mock localizationService; private readonly ItemController itemController; @@ -28,7 +31,36 @@ public ItemControllerTests() this.dateTimeProvider = new Mock(); this.dateTimeProvider.Setup(p => p.GetUtcNow()).Returns(new DateTime(2022, 1, 1)); this.itemRepository = new Repository(this.dataContext, this.dateTimeProvider.Object); - this.itemService = new ItemService(this.itemRepository); + this.localizationService = new Mock(); + var resx = new LocalizationViewModel + { + ModelValidation = new LocalizationViewModel.ModelValidationInfo + { + NameRequired = "Name is required.", + IdGreaterThanZero = "Id must be greater than zero.", + }, + UI = new LocalizationViewModel.UIInfo + { + AddItem = "Add Item", + Cancel = "Cancel", + Create = "Create", + Delete = "Delete", + DeleteItemConfirm = "Are you sure you want to delete this item?", + Description = "Description", + Edit = "Edit", + LoadMore = "Load more", + Name = "Name", + No = "No", + Save = "Save", + Yes = "Yes", + SearchPlaceholder = "Search...", + ShownItems = "Shown items", + }, + }; + this.localizationService.SetupGet(s => s.ViewModel).Returns(resx); + this.createItemDtoValidator = new CreateItemDtoValidator(localizationService.Object); + this.updateItemDtoValidator = new UpdateItemDtoValidator(localizationService.Object); + this.itemService = new ItemService(this.itemRepository, this.createItemDtoValidator, this.updateItemDtoValidator); this.itemController = new FakeItemController(this.itemService); } diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ItemControllerTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ItemControllerTests.cs index 4af3aa9..763c3de 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ItemControllerTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ItemControllerTests.cs @@ -1,11 +1,12 @@ using $ext_rootnamespace$.Controllers; -using $ext_rootnamespace$.DTO; -using $ext_rootnamespace$.Services; -using $ext_rootnamespace$.ViewModels; +using $ext_rootnamespace$.Services.Items; using DotNetNuke.Entities.Users; using Moq; +using OneOf; +using OneOf.Types; using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using System.Web.Http.Results; using Xunit; @@ -14,12 +15,13 @@ namespace UnitTests.Controllers { public class ItemControllerTests { + private CancellationToken token; private readonly Mock itemService; private readonly ItemController itemController; - public ItemControllerTests() { + this.token = new CancellationToken(); this.itemService = new Mock(); this.itemController = new FakeItemController(this.itemService.Object); } @@ -29,14 +31,16 @@ public async Task CreateItem_Creates() { var name = "Name"; var description = "Description"; + var userId = 123; var dto = new CreateItemDTO() { Name = name, Description = description, }; var viewModel = new ItemViewModel() { Id = 1, Name = name, Description = description }; - this.itemService.Setup(i => i.CreateItemAsync(It.IsAny(), It.IsAny())) - .Returns(Task.FromResult(new ItemViewModel() { Id = 1, Name = name, Description = description })); + this.itemService.Setup(i => i.CreateItemAsync(It.IsAny(), userId, this.token)) + .Returns(Task.FromResult, Error>>>( + new Success(new ItemViewModel() { Id = 1, Name = name, Description = description }))); var result = await this.itemController.CreateItem(dto); @@ -111,7 +115,7 @@ public async Task UpdateItem_Updates() await this.itemController.UpdateItem(item); - this.itemService.Verify(s => s.UpdateItemAsync(item, It.IsAny()), Times.Once); + this.itemService.Verify(s => s.UpdateItemAsync(item, It.IsAny(), this.token), Times.Once); } public class FakeItemController : ItemController diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/LocalizationControllerTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/LocalizationControllerTests.cs index f872ba7..55f83f0 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/LocalizationControllerTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/LocalizationControllerTests.cs @@ -1,7 +1,6 @@ using DotNetNuke.Entities.Users; using $ext_rootnamespace$.Controllers; -using $ext_rootnamespace$.Services; -using $ext_rootnamespace$.ViewModels; +using $ext_rootnamespace$.Services.Localization; using Moq; using System.Web.Http.Results; using Xunit; diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs deleted file mode 100644 index 4cba76f..0000000 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ModuleExceptionFilterAttributeTests.cs +++ /dev/null @@ -1,118 +0,0 @@ -using DotNetNuke.Web.Api; -using Moq; -using $ext_rootnamespace$.Controllers; -using DotNetNuke.Instrumentation; -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Web.Http.Controllers; -using System.Web.Http.Filters; -using Xunit; - -namespace UnitTests.Controllers -{ - public class ModuleExceptionFilterAttributeTests - { - [Fact] - public static void NoException_DoesNothing() - { - var attribute = new ModuleExceptionFilterAttribute(); - var loggerSource = new Mock(); - var log = new Mock(); - loggerSource.Setup(l => l.GetLogger(It.IsAny())).Returns(log.Object); - attribute.LoggerSource = loggerSource.Object; - var actionContext = new HttpActionContext - { - Response = new HttpResponseMessage(HttpStatusCode.OK) - }; - var actionExecutedContext = new HttpActionExecutedContext(actionContext, null); - - attribute.OnException(actionExecutedContext); - - Assert.Equal(HttpStatusCode.OK, actionExecutedContext.Response.StatusCode); - } - - [Theory] - [MemberData(nameof(GetExceptionsTestData))] - public static void ArgumentException_BadRequest( - Exception exception, HttpStatusCode expectedStatusCode) - { - var attribute = new ModuleExceptionFilterAttribute(); - var loggerSource = new Mock(); - var log = new Mock(); - loggerSource.Setup(l => l.GetLogger(It.IsAny())).Returns(log.Object); - attribute.LoggerSource = loggerSource.Object; - var actionContext = new HttpActionContext - { - Response = new HttpResponseMessage(HttpStatusCode.OK), - }; - var actionExecutedContext = new HttpActionExecutedContext(actionContext, exception); - actionExecutedContext.ActionContext.ControllerContext = new HttpControllerContext(); - - attribute.OnException(actionExecutedContext); - - Assert.Equal(expectedStatusCode, actionExecutedContext.Response.StatusCode); - } - - [Fact] - public async Task SystemException_DoesNotExposeDetails() - { - var attribute = new ModuleExceptionFilterAttribute(); - var loggerSource = new Mock(); - var log = new Mock(); - loggerSource.Setup(l => l.GetLogger(It.IsAny())).Returns(log.Object); - attribute.LoggerSource = loggerSource.Object; - var actionContext = new HttpActionContext - { - Response = new HttpResponseMessage(HttpStatusCode.OK), - }; - var actionExecutedContext = new HttpActionExecutedContext(actionContext, new Exception("Danger")); - - attribute.OnException(actionExecutedContext); - - Assert.Equal(HttpStatusCode.InternalServerError, actionExecutedContext.Response.StatusCode); - var response = await actionExecutedContext.Response.Content.ReadAsStringAsync(); - Assert.NotEqual("Danger", response); - } - - public static IEnumerable GetExceptionsTestData() - { - yield return new object[] - { - new ArgumentNullException("Null"), - HttpStatusCode.BadRequest, - }; - - yield return new object[] - { - new ArgumentOutOfRangeException("Out of range"), - HttpStatusCode.BadRequest, - }; - - yield return new object[] - { - new ArgumentException("Argument"), - HttpStatusCode.BadRequest, - }; - - yield return new object[] - { - new NotImplementedException("Not Implemented"), - HttpStatusCode.NotImplemented, - }; - - yield return new object[] - { - new TimeoutException("Timed out"), - HttpStatusCode.RequestTimeout, - }; - - yield return new object[] - { - new UnauthorizedAccessException("Unauthorized"), - HttpStatusCode.Unauthorized, - }; - } - } -} diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ValidateModelAttributeTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ValidateModelAttributeTests.cs deleted file mode 100644 index 5d980b2..0000000 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ValidateModelAttributeTests.cs +++ /dev/null @@ -1,49 +0,0 @@ -using $ext_rootnamespace$.Controllers; -using Newtonsoft.Json; -using System.Net; -using System.Net.Http; -using System.Web.Http; -using System.Web.Http.Controllers; -using Xunit; - -namespace UnitTests.Controllers -{ - public class ValidateModelAttributeTests - { - private readonly HttpActionContext actionContext; - private readonly HttpControllerContext controllerContext; - private readonly HttpRequestMessage request; - - public ValidateModelAttributeTests() - { - this.actionContext = new HttpActionContext(); - this.controllerContext = new HttpControllerContext(); - this.request = new HttpRequestMessage(); - this.controllerContext.Request = this.request; - this.actionContext.ControllerContext = this.controllerContext; - } - - [Fact] - public void OnActionExecuting_Invalid_Works() - { - var attribute = new ValidateModelAttribute(); - this.actionContext.ModelState.AddModelError("Name", "Name is required"); - attribute.OnActionExecuting(this.actionContext); - - Assert.Equal(HttpStatusCode.BadRequest, this.actionContext.Response.StatusCode); - var error = Assert.IsType>(this.actionContext.Response.Content); - var modelState = JsonConvert.SerializeObject(error.Value); - Assert.NotNull(modelState); - } - - [Fact] - public void OnActionExecuting_Valid_Works() - { - var attribute = new ValidateModelAttribute(); - - attribute.OnActionExecuting(this.actionContext); - - Assert.Null(this.actionContext.Response); - } - } -} \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/CreateItemDtoValidatorTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/CreateItemDtoValidatorTests.cs new file mode 100644 index 0000000..b5e4c26 --- /dev/null +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/CreateItemDtoValidatorTests.cs @@ -0,0 +1,52 @@ +using $ext_rootnamespace$.Services.Items; +using $ext_rootnamespace$.Services.Localization; +using FluentValidation; +using Moq; +using System.Threading.Tasks; +using Xunit; + +namespace UnitTests.Services.Items +{ + public class CreateItemDtoValidatorTests + { + LocalizationViewModel localizationViewModel; + Mock localizationService; + private readonly IValidator validator; + + public CreateItemDtoValidatorTests() + { + this.localizationViewModel = new LocalizationViewModel + { + ModelValidation = new LocalizationViewModel.ModelValidationInfo + { + NameRequired = "Name is required", + }, + }; + this.localizationService = new Mock(); + localizationService.Setup(l => l.ViewModel).Returns(localizationViewModel); + this.validator = new CreateItemDtoValidator(localizationService.Object); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public async Task RequiresName(string name) + { + // Arrange + var item = new CreateItemDTO + { + Name = name + }; + + // Act + var result = await validator.ValidateAsync(item); + + // Assert + Assert.False(result.IsValid); + Assert.Contains(result.Errors, e => e.PropertyName == nameof(item.Name)); + var nameError = result.Errors.Find(e => e.PropertyName == nameof(item.Name)); + Assert.Equal(this.localizationViewModel.ModelValidation.NameRequired, nameError.ErrorMessage); + } + } +} \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/ItemServiceTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/ItemServiceTests.cs similarity index 50% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/ItemServiceTests.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/ItemServiceTests.cs index 554958c..d760d7e 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/ItemServiceTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/ItemServiceTests.cs @@ -1,65 +1,82 @@ using $ext_rootnamespace$.Data.Entities; using $ext_rootnamespace$.Data.Repositories; -using $ext_rootnamespace$.DTO; -using $ext_rootnamespace$.Services; -using $ext_rootnamespace$.ViewModels; +using $ext_rootnamespace$.Services.Items; +using FluentValidation; +using FluentValidation.Results; using Moq; using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; +using System.Threading; using System.Threading.Tasks; using Xunit; -namespace UnitTests.Services +namespace UnitTests.Services.Items { public class ItemServiceTests { + private CancellationToken token; private Mock> itemRepository; private IItemService itemService; + private Mock> createItemDtoValidator; + private Mock> updateItemDtoValidator; public ItemServiceTests() { + this.token = new CancellationToken(); this.itemRepository = new Mock>(); - this.itemService = new ItemService(this.itemRepository.Object); + this.createItemDtoValidator = new Mock>(); + this.updateItemDtoValidator = new Mock>(); + this.itemService = new ItemService( + this.itemRepository.Object, + this.createItemDtoValidator.Object, + this.updateItemDtoValidator.Object); } [Fact] - public async Task CreateItem_NoItemThrows() + public async Task CreateItem_ValidatesDto() { - Task createItem() => this.itemService.CreateItemAsync(null, 123); - - await Assert.ThrowsAsync(createItem); - } + // Arrange + var dto = new CreateItemDTO(); + var userId = 123; + this.createItemDtoValidator.Setup(v => v.ValidateAsync(It.IsAny(), this.token)) + .Returns(Task.FromResult(new ValidationResult + { + Errors = { new ValidationFailure("Name", "Name is required.") }, + })); - [Fact] - public async Task CreateItem_NoNameThrows() - { - Task createItem() => this.itemService.CreateItemAsync(new CreateItemDTO(), 123); + // Act + var result = await this.itemService.CreateItemAsync(dto, userId, token); - await Assert.ThrowsAsync(createItem); + // Assert } [Fact] public async Task CreateItem_Creates() { var item = new CreateItemDTO() { Name = "Name", Description = "Description" }; - itemRepository.Setup(r => r.CreateAsync(It.IsAny(), It.IsAny())) - .Callback((i, u) => { + this.createItemDtoValidator.Setup(v => v.ValidateAsync(It.IsAny(), this.token)) + .Returns(Task.FromResult(new ValidationResult())); + this.itemRepository.Setup(r => r.CreateAsync(It.IsAny(), It.IsAny())) + .Callback((i, u) => + { i.Id = 1; i.Name = item.Name; i.Description = item.Description; }); - - var createdItem = await this.itemService.CreateItemAsync(item, 123); + var result = await this.itemService.CreateItemAsync(item, 123); this.itemRepository.Verify(r => r.CreateAsync(It.Is(i => i.Name == item.Name && i.Description == item.Description), 123)); - Assert.Equal(1, createdItem.Id); - Assert.Equal(item.Name, createdItem.Name); - Assert.Equal(item.Description, createdItem.Description); + result.Switch( + success => { + Assert.Equal(1, success.Value.Id); + Assert.Equal(item.Name, success.Value.Name); + Assert.Equal(item.Description, success.Value.Description); + }, + error => Assert.Fail()); } [Theory] @@ -103,64 +120,66 @@ public async Task DeleteItem_Deletes() } [Fact] - public async Task UpdateItem_Updates() + public async Task UpdateItem_ValidatesDto() { + // Arrange var originalItem = new Item { Id = 1, Name = "Original Name", Description = "Original Description", }; - var item = new UpdateItemDTO { Id = 1, Name = "New Item Name", Description = "New Item Description", }; + var userId = 123; this.itemRepository.Setup(r => r.GetByIdAsync(It.IsAny())) .Returns(Task.FromResult(originalItem)); + this.updateItemDtoValidator.Setup(v => v.ValidateAsync(It.IsAny(), this.token)) + .Returns(Task.FromResult(new ValidationResult + { + Errors = { new ValidationFailure("Id", "ID must be positive") }, + })); - await this.itemService.UpdateItemAsync(item, 2); + // Act + var result = await this.itemService.UpdateItemAsync(item, userId, this.token); - itemRepository.Verify(r => r.UpdateAsync(It.Is(i => - i.Id == item.Id && - i.Name == item.Name && - i.Description == item.Description), 2), Times.Once); + // Assert + result.Switch( + success => Assert.Fail(), + error => Assert.Equal("Id", error.Value.First().PropertyName)); } [Fact] - public async Task UpdateItem_NullDto_Throws() + public async Task UpdateItem_Updates() { - Task nullDto() => this.itemService.UpdateItemAsync(null, 2); - - var ex = await Assert.ThrowsAsync(nullDto); - Assert.Equal("dto", ex.ParamName); - itemRepository.Verify(r => - r.UpdateAsync( - It.IsAny(), - It.IsAny() - ), Times.Never); - } + var originalItem = new Item + { + Id = 1, + Name = "Original Name", + Description = "Original Description", + }; - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData(" ")] - [InlineData(" ")] - public async Task UpdateItem_NoName_Throws(string name) - { var item = new UpdateItemDTO { - Id = 123, - Name = name, - Description = null, + Id = 1, + Name = "New Item Name", + Description = "New Item Description", }; + this.itemRepository.Setup(r => r.GetByIdAsync(It.IsAny())) + .Returns(Task.FromResult(originalItem)); + this.updateItemDtoValidator.Setup(v => v.ValidateAsync(It.IsAny(), this.token)) + .Returns(Task.FromResult(new ValidationResult())); - Task noName() => this.itemService.UpdateItemAsync(item, 2); + await this.itemService.UpdateItemAsync(item, 2); - var ex = await Assert.ThrowsAsync(noName); - Assert.Equal("Name", ex.ParamName); + itemRepository.Verify(r => r.UpdateAsync(It.Is(i => + i.Id == item.Id && + i.Name == item.Name && + i.Description == item.Description), 2), Times.Once); } } } diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/UpdateItemDtoValidatorTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/UpdateItemDtoValidatorTests.cs new file mode 100644 index 0000000..b4651b5 --- /dev/null +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/UpdateItemDtoValidatorTests.cs @@ -0,0 +1,93 @@ +using $ext_rootnamespace$.Services.Items; +using $ext_rootnamespace$.Services.Localization; +using FluentValidation; +using Moq; +using System.Threading.Tasks; +using Xunit; + +namespace UnitTests.Services.Items +{ + public class UpdateItemDtoValidatorTests + { + LocalizationViewModel localizationViewModel; + Mock localizationService; + private readonly IValidator validator; + + public UpdateItemDtoValidatorTests() + { + this.localizationViewModel = new LocalizationViewModel + { + ModelValidation = new LocalizationViewModel.ModelValidationInfo + { + NameRequired = "Name is required", + IdGreaterThanZero = "Id must be greater than zero", + }, + }; + this.localizationService = new Mock(); + localizationService.Setup(l => l.ViewModel).Returns(localizationViewModel); + this.validator = new UpdateItemDtoValidator(localizationService.Object); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public async Task RequiresName(string name) + { + // Arrange + var item = new UpdateItemDTO + { + Id = 123, + Name = name, + }; + + // Act + var result = await validator.ValidateAsync(item); + + // Assert + Assert.False(result.IsValid); + Assert.Contains(result.Errors, e => e.PropertyName == nameof(item.Name)); + var nameError = result.Errors.Find(e => e.PropertyName == nameof(item.Name)); + Assert.Equal(this.localizationViewModel.ModelValidation.NameRequired, nameError.ErrorMessage); + } + + [Theory] + [InlineData(0)] + [InlineData(-1)] + public async Task RequiresIdGreaterThanZero(int id) + { + // Arrange + var item = new UpdateItemDTO + { + Name = "test name", + Id = id, + }; + + // Act + var result = await validator.ValidateAsync(item); + + // Assert + Assert.False(result.IsValid); + Assert.Contains(result.Errors, e => e.PropertyName == nameof(item.Id)); + var idError = result.Errors.Find(e => e.PropertyName == nameof(item.Id)); + Assert.Equal(this.localizationViewModel.ModelValidation.IdGreaterThanZero, idError.ErrorMessage); + } + + [Fact] + public async Task ValidEntity_ReturnsSuccess() + { + // Arrange + var item = new UpdateItemDTO + { + Name = "test name", + Id = 123, + }; + + // Act + var result = await validator.ValidateAsync(item); + + // Assert + Assert.True(result.IsValid); + } + } +} \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/StartupTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/StartupTests.cs index 1a10f5f..2b29bdf 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/StartupTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/StartupTests.cs @@ -1,7 +1,9 @@ using $ext_rootnamespace$.Data; using $ext_rootnamespace$.Data.Repositories; using $ext_rootnamespace$.Providers; -using $ext_rootnamespace$.Services; +using $ext_rootnamespace$.Services.Items; +using $ext_rootnamespace$.Services.Localization; +using FluentValidation; using DotNetNuke.Instrumentation; using Microsoft.Extensions.DependencyInjection; using System; @@ -27,6 +29,8 @@ public void Startup_RegistersAllRequiredServices() typeof(ILoggerSource), typeof(ILocalizationService), typeof(IDateTimeProvider), + typeof(IValidator), + typeof(IValidator), }; // Act diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/UnitTests.vstemplate b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/UnitTests.vstemplate index f338afe..c9df234 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/UnitTests.vstemplate +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/UnitTests.vstemplate @@ -26,9 +26,7 @@ ItemControllerTests.cs LocalizationControllerTests.cs ModuleApiControllerTests.cs - ModuleExceptionFilterAttributeTests.cs ServiceRouteMapperTests.cs - ValidateModelAttributeTests.cs @@ -43,7 +41,11 @@ DateTimeProviderTests.cs - ItemServiceTests.cs + + ItemServiceTests.cs + CreateItemDtoValidatorTests.cs + UpdateItemDtoValidatorTests.cs + FakeDatacontext.cs Startup.cs diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Helpers.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Helpers.cs index ab918ae..0ffe062 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Helpers.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Helpers.cs @@ -191,8 +191,8 @@ public static void GenerateLocalizationFiles(string rootNamespace) svc.AppendLine(GetGeneratedComment()); svc.AppendLine(GenerateLocalizationService(rootNamespace, localizationFiles)); - File.WriteAllText(RootDirectory / "ViewModels" / "LocalizationViewModel.cs", vm.ToString()); - File.WriteAllText(RootDirectory / "Services" / "LocalizationService.cs", svc.ToString()); + File.WriteAllText(RootDirectory / "Services" / "Localization" / "LocalizationViewModel.cs", vm.ToString()); + File.WriteAllText(RootDirectory / "Services" / "Localization" / "LocalizationService.cs", svc.ToString()); } public static string GetManifestOwnerName(string manifestPath) @@ -216,15 +216,14 @@ private static string GenerateLocalizationService(string rootNamespace, List") .AppendLine($" /// Provides strongly typed localization services for this module.") @@ -333,7 +332,7 @@ private static string GenerateLocalizationViewModel(string rootNamespace, List CreateItem(CreateItemDTO item) { var result = await this.itemService.CreateItemAsync(item, this.UserInfo.UserID); - return this.Ok(result); + return result.Match( + success => this.Ok(success.Value), + error => this.BadRequest(string.Join(System.Environment.NewLine, error.Value.Select(e => e.ErrorMessage)))); } /// @@ -101,8 +101,10 @@ public IHttpActionResult UserCanEdit() [SwaggerResponse(HttpStatusCode.OK, null, Description = "OK")] public async Task UpdateItem(UpdateItemDTO item) { - await this.itemService.UpdateItemAsync(item, this.UserInfo.UserID); - return this.Ok(); - } + var result = await this.itemService.UpdateItemAsync(item, this.UserInfo.UserID); + return result.Match( + success => this.Ok(), + error => this.BadRequest(string.Join(System.Environment.NewLine, error.Value.Select(e => e.ErrorMessage)))); + } } } diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/LocalizationController.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/LocalizationController.cs index 9b380f9..a72ca24 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/LocalizationController.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/LocalizationController.cs @@ -1,8 +1,7 @@ // MIT License // Copyright $ext_companyname$ -using $ext_rootnamespace$.Services; -using $ext_rootnamespace$.ViewModels; +using $ext_rootnamespace$.Services.Localization; using NSwag.Annotations; using System.Net; using System.Web.Http; diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleApiController.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleApiController.cs index 5440bf3..9714620 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleApiController.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleApiController.cs @@ -12,8 +12,6 @@ namespace $ext_rootnamespace$.Controllers /// /// Provides common features to all module controller. /// - [ModuleExceptionFilter] - [ValidateModel] public abstract class ModuleApiController : DnnApiController { /// diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleExceptionFilterAttribute.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleExceptionFilterAttribute.cs deleted file mode 100644 index 9c3f186..0000000 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ModuleExceptionFilterAttribute.cs +++ /dev/null @@ -1,88 +0,0 @@ -// MIT License -// Copyright $ext_companyname$ - -using DotNetNuke.DependencyInjection; -using DotNetNuke.Instrumentation; -using $ext_rootnamespace$.Services; -using System; -using System.Net; -using System.Net.Http; -using System.Runtime.CompilerServices; -using System.Web.Http.Filters; - -namespace $ext_rootnamespace$.Controllers -{ - /// - /// Handles exceptions on API endpoint calls. - /// - internal class ModuleExceptionFilterAttribute : ExceptionFilterAttribute - { - /// - /// Gets or sets the logger source. - /// - [DotNetNuke.DependencyInjection.Dependency] - public ILoggerSource LoggerSource { get; set; } - - /// - public override void OnException(HttpActionExecutedContext actionExecutedContext) - { - var exception = actionExecutedContext.Exception; - - if (exception is null) - { - return; - } - - var log = this.LoggerSource.GetLogger(nameof(ModuleExceptionFilterAttribute)); - log.Error(exception.Message, exception); - - if (exception is ArgumentException) - { - actionExecutedContext.Response = new - HttpResponseMessage(HttpStatusCode.BadRequest) - { - Content = new StringContent(exception.Message), - }; - return; - } - - if (exception is NotImplementedException) - { - actionExecutedContext.Response = new - HttpResponseMessage(HttpStatusCode.NotImplemented) - { - Content = new StringContent(exception.Message), - }; - return; - } - - if (exception is TimeoutException) - { - actionExecutedContext.Response = new - HttpResponseMessage(HttpStatusCode.RequestTimeout) - { - Content = new StringContent(exception.Message), - }; - return; - } - - if (exception is UnauthorizedAccessException) - { - actionExecutedContext.Response = new - HttpResponseMessage(HttpStatusCode.Unauthorized) - { - Content = new StringContent(exception.Message), - }; - return; - } - - // This fallback prevents exposing details about - // unexpected exceptions for security reasons. - actionExecutedContext.Response = new - HttpResponseMessage(HttpStatusCode.InternalServerError) - { - Content = new StringContent("An unexpected error occurred."), - }; - } - } -} \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ValidateModelAttribute.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ValidateModelAttribute.cs deleted file mode 100644 index 57120f4..0000000 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Controllers/ValidateModelAttribute.cs +++ /dev/null @@ -1,64 +0,0 @@ -// MIT License -// Copyright $ext_companyname$ - -namespace $ext_rootnamespace$.Controllers -{ - using DotNetNuke.Services.Localization; - using System.Net; - using System.Net.Http; - using System.Text; - using System.Web.Hosting; - using System.Web.Http.Controllers; - using System.Web.Http.Filters; - - /// - /// Validates the DTO for the request. - /// - internal class ValidateModelAttribute : ActionFilterAttribute - { - private string resourceFileRoot; - - private string ResourceFileRoot - { - get - { - if (string.IsNullOrWhiteSpace(this.resourceFileRoot)) - { - this.resourceFileRoot = HostingEnvironment.MapPath("~/DesktopModules/$ext_modulefoldername$/resources/App_LocalResources/ModelValidation.resx"); - } - - return this.resourceFileRoot; - } - } - - /// - /// When the action executes, validates the model state. - /// - /// The context of the action. - public override void OnActionExecuting(HttpActionContext actionContext) - { - if (actionContext.ModelState.IsValid == false) - { - var localization = new LocalizationProvider(); - var sb = new StringBuilder(); - foreach (var value in actionContext.ModelState.Values) - { - foreach (var error in value.Errors) - { - var localized = localization.GetString(error.ErrorMessage, this.ResourceFileRoot); - if (string.IsNullOrWhiteSpace(localized)) - { - localized = error.ErrorMessage; - } - - sb.AppendLine(localized); - } - } - - actionContext.Response = actionContext.Request.CreateErrorResponse( - HttpStatusCode.BadRequest, - sb.ToString()); - } - } - } -} diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Module.vstemplate b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Module.vstemplate index 834ff9b..87b4dc0 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Module.vstemplate +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Module.vstemplate @@ -35,7 +35,6 @@ LocalizationController.cs ModuleApiController.cs ServiceRouteMapper.cs - ValidateModelAttribute.cs @@ -50,11 +49,6 @@ ModuleDbContext.cs - - CreateItemDTO.cs - GetItemsPageDTO.cs - UpdateItemDTO.cs - git.md @@ -120,22 +114,29 @@ view.html - - ItemsPageViewModel.cs - ItemViewModel.cs - LocalizationViewModel.cs - ItemController.cs ModuleApiController.cs - ModuleExceptionFilterAttribute.cs ServiceRouteMapper.cs - IItemService.cs - ILocalizationService.cs - ItemService.cs - LocalizationService.cs + + CreateItemDtoValidator.cs + UpdateItemDtoValidator.cs + CreateItemDTO.cs + GetItemsPageDTO.cs + ItemsPageViewModel.cs + ItemViewModel.cs + IItemService.cs + ItemService.cs + UpdateItemDTO.cs + UpdateItemDtoValidator.cs + + + ILocalizationService.cs + LocalizationService.cs + LocalizationViewModel.cs + .gitignore .editorconfig diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj index 33e6bce..5a9083e 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ProjectTemplate.csproj @@ -56,31 +56,31 @@ - - + + - - + + - - - - - + + + + + - - - + + + @@ -136,6 +136,9 @@ 6.5.1 + + 11.9.2 + 5.2.9 @@ -150,6 +153,9 @@ 14.1.0 + + 3.0.271 + 1.1.118 runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ItemService.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ItemService.cs deleted file mode 100644 index ef56bf4..0000000 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ItemService.cs +++ /dev/null @@ -1,105 +0,0 @@ -// MIT License -// Copyright $ext_companyname$ - -using $ext_rootnamespace$.Common.Extensions; -using $ext_rootnamespace$.Data.Entities; -using $ext_rootnamespace$.Data.Repositories; -using $ext_rootnamespace$.DTO; -using $ext_rootnamespace$.Services; -using $ext_rootnamespace$.ViewModels; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace $ext_rootnamespace$.Services -{ - /// - /// Provides services to manage items. - /// - public class ItemService : IItemService - { - private IRepository itemRepository; - - /// - /// Initializes a new instance of the class. - /// - /// The items repository. - public ItemService(IRepository itemRepository) - { - this.itemRepository = itemRepository; - } - - /// - /// is thrown if the item or one of its required properties are missing. - public async Task CreateItemAsync(CreateItemDTO item, int userId) - { - if (item == null) - { - throw new ArgumentNullException(nameof(item)); - } - - if (string.IsNullOrWhiteSpace(item.Name)) - { - throw new ArgumentNullException("The item name is required.", nameof(item.Name)); - } - - var newItem = new Item() { Name = item.Name, Description = item.Description }; - await this.itemRepository.CreateAsync(newItem, userId); - - return new ItemViewModel(newItem); - } - - /// - public async Task GetItemsPageAsync(string query, int page = 1, int pageSize = 10, bool descending = false) - { - var items = await this.itemRepository.GetPageAsync( - page, - pageSize, - entities => entities - .Where(item => string.IsNullOrEmpty(query) || item.Name.ToUpper().Contains(query.ToUpper())) - .Order(item => item.Name, descending)); - - var itemsPageViewModel = new ItemsPageViewModel() - { - Items = items.Items.Select(item => new ItemViewModel - { - Description = item.Description, - Id = item.Id, - Name = item.Name, - }).ToList(), - Page = items.Page, - ResultCount = items.ResultCount, - PageCount = items.PageCount, - }; - - return itemsPageViewModel; - } - - /// - public async Task DeleteItemAsync(int itemId) - { - await this.itemRepository.DeleteAsync(itemId); - } - - /// - public async Task UpdateItemAsync(UpdateItemDTO dto, int userId) - { - if (dto is null) - { - throw new ArgumentNullException(nameof(dto)); - } - - if (string.IsNullOrWhiteSpace(dto.Name)) - { - throw new ArgumentNullException(nameof(dto.Name)); - } - - var item = await this.itemRepository.GetByIdAsync(dto.Id); - item.Name = dto.Name; - item.Description = dto.Description; - - await this.itemRepository.UpdateAsync(item, userId); - } - } -} diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/CreateItemDTO.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/CreateItemDTO.cs similarity index 78% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/CreateItemDTO.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/CreateItemDTO.cs index d70c649..c6a4b0c 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/CreateItemDTO.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/CreateItemDTO.cs @@ -1,9 +1,7 @@ // MIT License // Copyright $ext_companyname$ -using System.ComponentModel.DataAnnotations; - -namespace $ext_rootnamespace$.DTO +namespace $ext_rootnamespace$.Services.Items { /// /// Data transfer object to create a new item. @@ -13,7 +11,6 @@ public class CreateItemDTO /// /// Gets or sets the name for the item. /// - [Required(ErrorMessage = "NameRequired")] public string Name { get; set; } /// diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/CreateItemDtoValidator.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/CreateItemDtoValidator.cs new file mode 100644 index 0000000..05c46f2 --- /dev/null +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/CreateItemDtoValidator.cs @@ -0,0 +1,27 @@ +// MIT License +// Copyright $ext_companyname$ + +using $ext_rootnamespace$.Services.Localization; +using FluentValidation; + +namespace $ext_rootnamespace$.Services.Items +{ + /// + /// Validates the . + /// + public class CreateItemDtoValidator : AbstractValidator + { + /// + /// Initializes a new instance of the class. + /// + /// The localization service. + public CreateItemDtoValidator(ILocalizationService localizationService) + { + var modelValidationViewModel = localizationService.ViewModel.ModelValidation; + + this.RuleFor(x => x.Name) + .NotEmpty() + .WithMessage(modelValidationViewModel.NameRequired); + } + } +} diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/GetItemsPageDTO.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/GetItemsPageDTO.cs similarity index 94% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/GetItemsPageDTO.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/GetItemsPageDTO.cs index 38084b7..51a4779 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/GetItemsPageDTO.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/GetItemsPageDTO.cs @@ -1,6 +1,6 @@ // MIT License // Copyright $ext_companyname$ -namespace $ext_rootnamespace$.DTO +namespace $ext_rootnamespace$.Services.Items { /// /// The data object to request a paged list of items. diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/IItemService.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/IItemService.cs similarity index 66% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/IItemService.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/IItemService.cs index 6558e61..59ad927 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/IItemService.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/IItemService.cs @@ -2,11 +2,14 @@ // Copyright $ext_companyname$ using $ext_rootnamespace$.Data.Entities; -using $ext_rootnamespace$.DTO; -using $ext_rootnamespace$.ViewModels; +using FluentValidation.Results; +using OneOf; +using OneOf.Types; +using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; -namespace $ext_rootnamespace$.Services +namespace $ext_rootnamespace$.Services.Items { /// /// Provides services to manage items. @@ -18,8 +21,12 @@ public interface IItemService /// /// The item to create. /// The acting user id. - /// . - Task CreateItemAsync(CreateItemDTO item, int userId); + /// A token that can be used to abort the request early. + /// Either a success of of an error of string. + Task, Error>>> CreateItemAsync( + CreateItemDTO item, + int userId, + CancellationToken token = default); /// /// Deletes an item. @@ -43,7 +50,8 @@ public interface IItemService /// /// The item to edit with its new details. /// The id of the acting DNN user. + /// A token that can be used to abort the request early. /// An awaitable task. - Task UpdateItemAsync(UpdateItemDTO item, int userId); + Task>>> UpdateItemAsync(UpdateItemDTO item, int userId, CancellationToken token = default); } } diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemService.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemService.cs new file mode 100644 index 0000000..67e1ff8 --- /dev/null +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemService.cs @@ -0,0 +1,112 @@ +// MIT License +// Copyright $ext_companyname$ + +using $ext_rootnamespace$.Common.Extensions; +using $ext_rootnamespace$.Data.Entities; +using $ext_rootnamespace$.Data.Repositories; +using FluentValidation; +using FluentValidation.Results; +using OneOf; +using OneOf.Types; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace $ext_rootnamespace$.Services.Items +{ + /// + /// Provides services to manage items. + /// + public class ItemService : IItemService + { + private readonly IRepository itemRepository; + private readonly IValidator createItemDtoValidator; + private readonly IValidator updateItemDtoValidator; + + /// + /// Initializes a new instance of the class. + /// + /// The items repository. + /// The validator for the entity. + /// The validator for the entity. + public ItemService( + IRepository itemRepository, + IValidator createItemDtoValidator, + IValidator updateItemDtoValidator) + { + this.itemRepository = itemRepository; + this.createItemDtoValidator = createItemDtoValidator; + this.updateItemDtoValidator = updateItemDtoValidator; + } + + /// + public async Task, Error>>> CreateItemAsync(CreateItemDTO item, int userId, CancellationToken token = default) + { + var validationResult = await this.createItemDtoValidator.ValidateAsync(item); + + if (!validationResult.IsValid) + { + return new Error>(validationResult.Errors); + } + + var newItem = new Item() { Name = item.Name, Description = item.Description }; + await this.itemRepository.CreateAsync(newItem, userId); + + var vm = new ItemViewModel(newItem); + return new Success(vm); + } + + /// + public async Task GetItemsPageAsync(string query, int page = 1, int pageSize = 10, bool descending = false) + { + var items = await this.itemRepository.GetPageAsync( + page, + pageSize, + entities => entities + .Where(item => string.IsNullOrEmpty(query) || item.Name.ToUpper().Contains(query.ToUpper())) + .Order(item => item.Name, descending)); + + var itemsPageViewModel = new ItemsPageViewModel() + { + Items = items.Items.Select(item => new ItemViewModel + { + Description = item.Description, + Id = item.Id, + Name = item.Name, + }).ToList(), + Page = items.Page, + ResultCount = items.ResultCount, + PageCount = items.PageCount, + }; + + return itemsPageViewModel; + } + + /// + public async Task DeleteItemAsync(int itemId) + { + await this.itemRepository.DeleteAsync(itemId); + } + + /// + public async Task>>> UpdateItemAsync(UpdateItemDTO dto, int userId, CancellationToken token = default) + { + var validationResult = await this.updateItemDtoValidator.ValidateAsync(dto); + + if (!validationResult.IsValid) + { + return new Error>(validationResult.Errors); + } + + var item = await this.itemRepository.GetByIdAsync(dto.Id); + item.Name = dto.Name; + item.Description = dto.Description; + + await this.itemRepository.UpdateAsync(item, userId); + + return default(Success); + } + } +} diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/ItemViewModel.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemViewModel.cs similarity index 94% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/ItemViewModel.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemViewModel.cs index 6ef3bc7..6679f94 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/ItemViewModel.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemViewModel.cs @@ -2,10 +2,9 @@ // Copyright $ext_companyname$ using $ext_rootnamespace$.Data.Entities; -using $ext_rootnamespace$.DTO; using System.ComponentModel.DataAnnotations; -namespace $ext_rootnamespace$.ViewModels +namespace $ext_rootnamespace$.Services.Items { /// /// Represents the basic information about an item. diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/ItemsPageViewModel.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemsPageViewModel.cs similarity index 95% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/ItemsPageViewModel.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemsPageViewModel.cs index 52547d4..cae40ad 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/ItemsPageViewModel.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/ItemsPageViewModel.cs @@ -4,7 +4,7 @@ using $ext_rootnamespace$.Data.Entities; using System.Collections.Generic; -namespace $ext_rootnamespace$.ViewModels +namespace $ext_rootnamespace$.Services.Items { /// /// Represents a page of items, . diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/UpdateItemDTO.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/UpdateItemDTO.cs similarity index 69% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/UpdateItemDTO.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/UpdateItemDTO.cs index c5ca943..8b31bf8 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/DTO/UpdateItemDTO.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/UpdateItemDTO.cs @@ -1,9 +1,7 @@ // MIT License // Copyright $ext_companyname$ -using System.ComponentModel.DataAnnotations; - -namespace $ext_rootnamespace$.DTO +namespace $ext_rootnamespace$.Services.Items { /// /// Data transfer object used to update an item. @@ -13,7 +11,6 @@ public class UpdateItemDTO : CreateItemDTO /// /// Gets or sets the id of the item to edit. /// - [Range(1, int.MaxValue, ErrorMessage = "IdGreaterThanZero")] public int Id { get; set; } } } \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/UpdateItemDtoValidator.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/UpdateItemDtoValidator.cs new file mode 100644 index 0000000..ab3cfd6 --- /dev/null +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Items/UpdateItemDtoValidator.cs @@ -0,0 +1,29 @@ +// MIT License +// Copyright $ext_companyname$ + +using $ext_rootnamespace$.Services.Localization; +using FluentValidation; + +namespace $ext_rootnamespace$.Services.Items +{ + /// + /// Validator for the entity. + /// + internal class UpdateItemDtoValidator : AbstractValidator + { + /// + /// Initializes a new instance of the class. + /// + /// The localization service. + public UpdateItemDtoValidator(ILocalizationService localizationService) + { + var modelValidationViewModel = localizationService.ViewModel.ModelValidation; + + this.Include(new CreateItemDtoValidator(localizationService)); + + this.RuleFor(x => x.Id) + .GreaterThan(0) + .WithMessage(modelValidationViewModel.IdGreaterThanZero); + } + } +} diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ILocalizationService.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/ILocalizationService.cs similarity index 82% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ILocalizationService.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/ILocalizationService.cs index bccf7ba..6253e77 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/ILocalizationService.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/ILocalizationService.cs @@ -1,8 +1,7 @@ // MIT License // Copyright $ext_companyname$ -using $ext_rootnamespace$.ViewModels; -namespace $ext_rootnamespace$.Services +namespace $ext_rootnamespace$.Services.Localization { /// /// Provides strongly typed localization services for this module. diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/LocalizationService.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/LocalizationService.cs similarity index 94% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/LocalizationService.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/LocalizationService.cs index 1c7f4f8..510ff7a 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/LocalizationService.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/LocalizationService.cs @@ -11,11 +11,9 @@ namespace $ext_rootnamespace$.Services { using DotNetNuke.Common.Utilities; using DotNetNuke.Services.Localization; - using $ext_rootnamespace$.ViewModels; using System.Diagnostics.CodeAnalysis; - using System.Web.Hosting; using System.Threading; - using static $ext_rootnamespace$.ViewModels.LocalizationViewModel; + using static $ext_rootnamespace$.Services.Localization.LocalizationViewModel; /// /// Provides strongly typed localization services for this module. @@ -35,7 +33,7 @@ private string ResourceFileRoot if (string.IsNullOrWhiteSpace(this.resourceFileRoot)) { this.resourceFileRoot = HostingEnvironment.MapPath( - "~/DesktopModules/MyModule21/resources/App_LocalResources/"); + "~/DesktopModules/$ext_modulename$/resources/App_LocalResources/"); } return this.resourceFileRoot; diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/LocalizationViewModel.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/LocalizationViewModel.cs similarity index 98% rename from Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/LocalizationViewModel.cs rename to Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/LocalizationViewModel.cs index 097f083..21b577b 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/ViewModels/LocalizationViewModel.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Services/Localization/LocalizationViewModel.cs @@ -7,7 +7,7 @@ // //------------------------------------------------------------------------------ -namespace $ext_rootnamespace$.ViewModels +namespace $ext_rootnamespace$.Services.Localization { using System.Diagnostics.CodeAnalysis; diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Startup.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Startup.cs index b029771..06b02df 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Startup.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/Startup.cs @@ -9,7 +9,9 @@ namespace $ext_rootnamespace$ using $ext_rootnamespace$.Data.Entities; using $ext_rootnamespace$.Data.Repositories; using $ext_rootnamespace$.Providers; - using $ext_rootnamespace$.Services; + using $ext_rootnamespace$.Services.Items; + using $ext_rootnamespace$.Services.Localization; + using FluentValidation; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using System.Diagnostics.CodeAnalysis; @@ -28,10 +30,12 @@ public void ConfigureServices(IServiceCollection services) { services.AddScoped(); services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); - services.AddScoped(provider => new ItemService(provider.GetService>())); + services.AddScoped(); services.TryAddScoped(x => LoggerSource.Instance); services.AddScoped(); services.AddSingleton(); + services.AddScoped, CreateItemDtoValidator>(); + services.AddScoped, UpdateItemDtoValidator>(); } } } \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/project-architecture.md b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/project-architecture.md index 1b55474..d724910 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/project-architecture.md +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/project-architecture.md @@ -73,6 +73,8 @@ graph TB ItemClient[FrontEnd
ItemClient] -->|CreateItemDTO as JSON
Name and Description| ItemController[Backend
ItemController] ItemController -->|CreateItemDTO
UserId| ItemService ItemService -->|Item| Repository[Repository] + ItemService -->|Validate| Validator[IValidator] + Validator --> ItemService Repository -->|Item| DataContext[DataContext
Entity Framework] DataContext -->|SQL INSERT ...| Database Database -->|Table row| DataContext @@ -100,18 +102,29 @@ The below diagram explains the backend code that is part of the module. We will As we saw earlier, to create an item, the minimum information needed is only the `Name` and `Description`. The `ItemController` adds the acting user id and asks the `ItemService` to create the item. -Then the `Repository` adds the information each entity should have like the creation data and others and will save the data to the database (more on this later). It then knows about the `Id` of the recently created item and can return a fully populated `Item` back to the `ItemService`. +The IValidator class is used to ensure the data is valid and to provide user friendly localized messages if it is not. + +If the data is valid, then the `Repository` adds the information each entity should have like the creation data and others and will save the data to the database (more on this later). It then knows about the `Id` of the recently created item and can return a fully populated `Item` back to the `ItemService`. Because we don't need all this information for this view, it converts it into an `ItemViewModel` that only has the Id, Name and Description. The `ItemController` then serializes this `ItemViewModel` as json and returns it to the frontend. ```mermaid sequenceDiagram ItemController ->> ItemService: CreateItem(
CreateItemDTO item = {
Name = "First Item",
Description = "This is the first item"},
UserId userId = 123) + ItemService ->> IValidator#lt;T#gt;: ValidateAsync(createItemDto) + IValidator#lt;T#gt; ->> ItemService: ValidationResult.IsValid ItemService ->> Repository#lt;T#gt;: Create(Item item = {
Name = "First Item",
Description = "This is the first item"}) Repository#lt;T#gt; ->> ItemService: returns Item item = {
Id = 10,
CreatedAt = 2021-01-23 18:05:30,
CreatedByUserId = 123,
UpdatedAt = 2021-01-23 18:05:30,
UpdatedByUserId = 123,
Name = "First Item",
Description = "This is the first item"} ItemService ->> ItemController: returns
ItemViewModel item = {
Id = 10,
Name = "First Item",
Description = "This is the first item"} ``` +> [!NOTE] +> **What if the data is not valid?** +> We use [OneOf](https://www.nuget.org/packages/OneOf) to return either a Success or an Error as a "discriminated union". +> Basically the consumer of a OneOf with have to handle either a .Switch or .Match method to handle all possible return scenarios. +> Each of these scenarios may be a different object as a success and an error are wildly different things. +> In our case, should the DTO not be valid we have an Error<string> with localized errors (one per line) that are user friendly and we return a BadRequest from our controller. + ### External code This module uses [Entity Framework](https://www.entityframeworktutorial.net/what-is-entityframework.aspx) for the data layer. This means amongst other things that we define all our data entities from code using attributes and do not need SQL Scripts in the Dnn extension package. In combination with the [Repository Pattern](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-design) it allows in most cases to also not need complex stored procedures. It also uses IQueryable to combine many filtering/sorting requests and only actually touch the database when needed with a very optimized single query. EF (Entity Framework) supports many different types of databases, this unlinks the module logic from any type of data infrastructure. Right now, this module uses the Dnn database but it can easily be changed to a separate database or even another database type altogether. @@ -145,6 +158,8 @@ The itemController is responsible for: As you can see, this class has more than one responsability and inherits from other base classes that are not under our control. One of them, `DnnApiController` was not built with unit testing in mind. For those reasons, as part of our unit tests, we exclude the `Controllers` folder. +We use OneOf here to return a result that can be only one of many things. This avoids having to handle exceptions which are not great for performance and have no ways to force consumer implementations. In this case, we ensure that we always have to implement what to do for a success or a failure. + #### Inheritance The `ItemController` inherits from `ModuleApiController` which provides properties and methods we want to be available in all our controllers. For instance here, we provide an interface for logging and whether or not the user has module edit rights. @@ -235,22 +250,10 @@ public class ItemController : ModuleApiController ... public IHttpActionResult CreateItem(CreateItemDTO item) { - try - { - return this.Ok(this.itemService.CreateItem(item, this.UserInfo.UserID)); - } - catch (ArgumentNullException ex) - { - this.Logger.Error(ex.Message, ex); - return this.BadRequest(ex.Message); - } - catch (Exception ex) - { - string message = "An unexpected error occured while trying to create the item"; - this.Logger.Error(message, ex); - return this.InternalServerError(new Exception(message)); - throw; - } + var result = await this.itemService.CreateItemAsync(item, this.UserInfo.UserID); + return result.Match( + success => this.Ok(success.Value), + error => this.BadRequest(string.Join(System.Environment.NewLine, error.Value.Select(e => e.ErrorMessage)))); } ... } @@ -263,6 +266,7 @@ Service classes are core of our business logic in this pattern. In this case it #### Inheritance The `ItemController` inherits from the `IItemController` interface, again this is to allow using dependency injection where we need it and also help out with unit tests and decoupling classes for easier maintenance. +We also use [FluentValidation](https://www.nuget.org/packages/FluentValidation) here to extract validation into its own class (single responsability principle). #### Dependencies Again we only depend on interfaces and data-objects. For instance here we never create an instance of the `Repository`, we get in injected in the constructor from whowever calls this service. @@ -280,14 +284,16 @@ classDiagram class ItemService ItemService: -IRepository itemRepository + ItemService: -IValidator createItemDtoValidator ItemService: +ItemService(IRepository itemRepository) ItemService: +CreateItem(CreateItemDTO item, int userId) ItemViewModel ItemService: +GetItemsPage(GetItemsPageDTO request) ItemsPageViewModel ItemService: +DeleteItem(int itemId) - ItemService ..> CreateItemDTO - ItemService ..> ItemViewModel - ItemService ..> IRepository~T~ - ItemService ..> Item + ItemService ..> CreateItemDTO + ItemService ..> ItemViewModel + ItemService ..> IRepository~T~ + ItemService ..> Item + ItemService ..> IValidator~T~ class IItemService <> IItemService @@ -323,6 +329,14 @@ classDiagram IEntity: +DateTime UpdatedAt IEntity: +int UpdatedByUserId IEntity <|-- BaseEntity + + class SaveItemDtoValidator + SaveItemDtoValidator: +ValidationResult Validate + + class IValidator~T~ + <> IValidator~T~ + + IValidator~T~ <|-- SaveItemDtoValidator ``` ```cs @@ -346,20 +360,18 @@ public class ItemService : IItemService /// is thrown if the item or one of its required properties are missing. public ItemViewModel CreateItem(CreateItemDTO item, int userId) { - if (item == null) - { - throw new ArgumentNullException(nameof(item)); - } + var validationResult = await this.createItemDtoValidator.ValidateAsync(item); - if (string.IsNullOrWhiteSpace(item.Name)) + if (!validationResult.IsValid) { - throw new ArgumentNullException("The item name is required.", nameof(item.Name)); + return new Error>(validationResult.Errors); } var newItem = new Item() { Name = item.Name, Description = item.Description }; - this.itemRepository.Create(newItem, userId); + await this.itemRepository.CreateAsync(newItem, userId); - return new ItemViewModel(newItem); + var vm = new ItemViewModel(newItem); + return new Success(vm); } ... From fcea5622a4e7756a066fd24795239e6195923758 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 22 Aug 2024 20:44:56 -0400 Subject: [PATCH 38/41] Adjusted module build to publish build artifacts Closes #517 --- Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs index ce3aa07..23465a0 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/build/Build.cs @@ -634,6 +634,7 @@ class Build : NukeBuild .DependsOn(Test) .DependsOn(UpdateTokens) .DependsOn(Docs) + .Produces(ArtifactsDirectory / "*.zip") .Executes(() => { var stagingDirectory = ArtifactsDirectory / "staging"; From 15602e208e4a636f0f700c4d872810da3b55c8d9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 22 Aug 2024 21:41:17 -0400 Subject: [PATCH 39/41] Added additional documentation about assumptions Added additional documentation about assumptions. Closes #570 --- .../module/docfx_project/articles/intro.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/intro.md b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/intro.md index 2f26640..14deebf 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/intro.md +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/intro.md @@ -4,6 +4,16 @@ Welcome to you new module template! ## First build +- **Before you start** + + This module template makes a few assumptions about your environment, make sure you have the following installed: + - Latest version of Visual Studio, and updates (Free community edition is fine) + - Latest version of .NET Core SDK (LST) + - A test site that uses the latest version of DNN (you can target older versions but out-of-the-box this template is set to the latest) + - The solution and the project are expected to be in the same folder. + If you move the project to a different folder, you will need to update the paths in the `Build.cs` file. + + - **Package your module** Build tasks are placed in the launch profiles menu in Visual Studio, From b1cdf909b0b885248f264ca3ae5ca200ebbe8dcc Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 22 Aug 2024 21:58:41 -0400 Subject: [PATCH 40/41] Added documentation about kgithub actions permissions Also adds and corrects some other documentation Closes #610 --- .../module/docfx_project/articles/git.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/git.md b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/git.md index ad066bc..3d6530b 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/git.md +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/module/docfx_project/articles/git.md @@ -18,12 +18,22 @@ Create you repository by heading to View > Git Changes, the Git Changes side bar > You may be asked to login if it's the first time you are using Github integration in Visual Studio. If you are asked to login, it is recommended to create a [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) instead of using your login/password. Also the Github automations support both private and public repositories. ![Initial Commit](../images/initial-commit.gif) +## First CI Build +In a few minutes you should see that github actinos has run your first build automatically. +This first build will fail because the repository is new and actions don't yet have permissions to write to the repository. +In your repository settings, go to 'Actions' then 'Workflows' and enable "Read/Write" access. + ## Automated releases -In a few minutes if you navigate to your repository on Github, you will notice there is a draft release for v0.1.0. It has no release notes yet but it does have the fully packaged module ready for production install. +When you feel you are ready for a beta release, you can create a release branch. +The branch name should include the version number you want, such as `release/0.1.0`. +A few minutes later if you navigate to your repository on Github, you will notice there is a draft release for v0.1.0. +It has auto-generated release notes wrote from the title of all the PRs that went into a milestone of the save version. +It also has the fully packaged module ready for install from testers. +Each additional push or merge into that release branch will produce a new beta release for you automatically. +When you are ready for production, you can simply merge that release branch into `main` or `master` and it will produce a final release for you (non-beta). +If you had any last minute fixes on the release branch that don't exist in `develop` don't forget to merge that branch into `develop` too. -> [!TIP] -> This is a draft and the public won't see it as an available release yet. Since this is probably not ready for production, you can delete the release and the tag if you don't want to keep it (and reserve the v0.1.0 version from future use). If you do want to keep it, you can edit it and publish it. Each push to the `main` or `master` branch will trigger a draf release that is non-beta, this is how we will do releases in the future. ## Automatic Versioning The template uses [GitVersion](https://github.com/GitTools/GitVersion) and the [GitFlow](https://gitversion.net/docs/git-branching-strategies/gitflow) branching strategy in order to manage versions and releases. From 9f4ece3fbed7dcaa1c17ac33dbc283372c5a6056 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 23 Aug 2024 15:30:55 -0400 Subject: [PATCH 41/41] Replaced Moq with NSubstitute Closes #704 --- .../Controllers/ItemControllerTests.cs | 20 +++--- .../Controllers/ServiceRouteMapperTests.cs | 13 ++-- .../IntegrationTests/ProjectTemplate.csproj | 2 +- .../Controllers/ItemControllerTests.cs | 16 ++--- .../LocalizationControllerTests.cs | 11 ++-- .../Controllers/ServiceRouteMapperTests.cs | 13 ++-- .../Repositories/GenericRepositoryTests.cs | 56 ++++++++--------- .../UnitTests/ProjectTemplate.csproj | 2 +- .../Providers/DateTimeProviderTests.cs | 10 +-- .../Items/CreateItemDtoValidatorTests.cs | 10 +-- .../Services/Items/ItemServiceTests.cs | 61 ++++++++++--------- .../Items/UpdateItemDtoValidatorTests.cs | 10 +-- 12 files changed, 108 insertions(+), 116 deletions(-) diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ItemControllerTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ItemControllerTests.cs index 5043873..9c4b3f1 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ItemControllerTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ItemControllerTests.cs @@ -6,7 +6,7 @@ using $ext_rootnamespace$.Services.Localization; using DotNetNuke.Entities.Users; using FluentValidation; -using Moq; +using NSubstitute; using System; using System.Linq; using System.Threading.Tasks; @@ -17,21 +17,21 @@ namespace IntegrationTests.Controllers { public class ItemControllerTests : FakeDataContext { - private readonly Mock dateTimeProvider; + private readonly IDateTimeProvider dateTimeProvider; private readonly IRepository itemRepository; private readonly IItemService itemService; private readonly IValidator createItemDtoValidator; private readonly IValidator updateItemDtoValidator; - private readonly Mock localizationService; + private readonly ILocalizationService localizationService; private readonly ItemController itemController; public ItemControllerTests() { - this.dateTimeProvider = new Mock(); - this.dateTimeProvider.Setup(p => p.GetUtcNow()).Returns(new DateTime(2022, 1, 1)); - this.itemRepository = new Repository(this.dataContext, this.dateTimeProvider.Object); - this.localizationService = new Mock(); + this.dateTimeProvider = Substitute.For(); + this.dateTimeProvider.GetUtcNow().Returns(new DateTime(2022, 1, 1)); + this.itemRepository = new Repository(this.dataContext, this.dateTimeProvider); + this.localizationService = Substitute.For(); var resx = new LocalizationViewModel { ModelValidation = new LocalizationViewModel.ModelValidationInfo @@ -57,9 +57,9 @@ public ItemControllerTests() ShownItems = "Shown items", }, }; - this.localizationService.SetupGet(s => s.ViewModel).Returns(resx); - this.createItemDtoValidator = new CreateItemDtoValidator(localizationService.Object); - this.updateItemDtoValidator = new UpdateItemDtoValidator(localizationService.Object); + this.localizationService.ViewModel.Returns(resx); + this.createItemDtoValidator = new CreateItemDtoValidator(localizationService); + this.updateItemDtoValidator = new UpdateItemDtoValidator(localizationService); this.itemService = new ItemService(this.itemRepository, this.createItemDtoValidator, this.updateItemDtoValidator); this.itemController = new FakeItemController(this.itemService); } diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ServiceRouteMapperTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ServiceRouteMapperTests.cs index 00a673f..c97308e 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ServiceRouteMapperTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/Controllers/ServiceRouteMapperTests.cs @@ -1,11 +1,6 @@ using $ext_rootnamespace$.Controllers; using DotNetNuke.Web.Api; -using Moq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using NSubstitute; using Xunit; namespace IntegrationTests.Controllers @@ -15,12 +10,12 @@ public class ServiceRouteMapperTests [Fact] public void RegisterRoutes_RegistersAtLestOneRoute() { - var mapRouteManager = new Mock(); + var mapRouteManager = Substitute.For(); var serviceRouteMapper = new ServiceRouteMapper(); - serviceRouteMapper.RegisterRoutes(mapRouteManager.Object); + serviceRouteMapper.RegisterRoutes(mapRouteManager); - mapRouteManager.Verify(m => m.MapHttpRoute(It.IsAny(), It.IsAny(), It.IsAny(), It.IsNotNull()), Times.AtLeastOnce); + mapRouteManager.Received().MapHttpRoute(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Is(x => x != null)); } } } \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj index 07c5e66..1694d7a 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/IntegrationTests/ProjectTemplate.csproj @@ -38,8 +38,8 @@ - + diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ItemControllerTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ItemControllerTests.cs index 763c3de..9518bb6 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ItemControllerTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ItemControllerTests.cs @@ -1,7 +1,7 @@ using $ext_rootnamespace$.Controllers; using $ext_rootnamespace$.Services.Items; using DotNetNuke.Entities.Users; -using Moq; +using NSubstitute; using OneOf; using OneOf.Types; using System; @@ -16,14 +16,14 @@ namespace UnitTests.Controllers public class ItemControllerTests { private CancellationToken token; - private readonly Mock itemService; + private readonly IItemService itemService; private readonly ItemController itemController; public ItemControllerTests() { this.token = new CancellationToken(); - this.itemService = new Mock(); - this.itemController = new FakeItemController(this.itemService.Object); + this.itemService = Substitute.For(); + this.itemController = new FakeItemController(this.itemService); } [Fact] @@ -38,7 +38,7 @@ public async Task CreateItem_Creates() Description = description, }; var viewModel = new ItemViewModel() { Id = 1, Name = name, Description = description }; - this.itemService.Setup(i => i.CreateItemAsync(It.IsAny(), userId, this.token)) + this.itemService.CreateItemAsync(Arg.Any(), userId, this.token) .Returns(Task.FromResult, Error>>>( new Success(new ItemViewModel() { Id = 1, Name = name, Description = description }))); @@ -60,7 +60,7 @@ public async Task GetItemsPage_GetsProperPages() items.Add(item); } var itemsPageViewModel = new ItemsPageViewModel() { Items = items, Page = 1, PageCount = 10, ResultCount = 100 }; - this.itemService.Setup(i => i.GetItemsPageAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + this.itemService.GetItemsPageAsync(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()) .Returns(Task.FromResult(itemsPageViewModel)); var dto = new GetItemsPageDTO { @@ -87,7 +87,7 @@ public async Task DeleteItem_Deletes(int itemId) var result = await this.itemController.DeleteItem(itemId); Assert.IsType(result); - this.itemService.Verify(i => i.DeleteItemAsync(itemId), Times.Once); + await this.itemService.Received().DeleteItemAsync(itemId); } [Theory] @@ -115,7 +115,7 @@ public async Task UpdateItem_Updates() await this.itemController.UpdateItem(item); - this.itemService.Verify(s => s.UpdateItemAsync(item, It.IsAny(), this.token), Times.Once); + await this.itemService.UpdateItemAsync(item, Arg.Any(), this.token); } public class FakeItemController : ItemController diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/LocalizationControllerTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/LocalizationControllerTests.cs index 55f83f0..db27888 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/LocalizationControllerTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/LocalizationControllerTests.cs @@ -1,7 +1,7 @@ using DotNetNuke.Entities.Users; using $ext_rootnamespace$.Controllers; using $ext_rootnamespace$.Services.Localization; -using Moq; +using NSubstitute; using System.Web.Http.Results; using Xunit; @@ -9,21 +9,20 @@ namespace UnitTests.Controllers { public class LocalizationControllerTests { - private readonly Mock localizationService; + private readonly ILocalizationService localizationService; private readonly LocalizationController localizationController; public LocalizationControllerTests() { - this.localizationService = new Mock(); - this.localizationController = new FakeLocalizationController(this.localizationService.Object); + this.localizationService = Substitute.For(); + this.localizationController = new FakeLocalizationController(this.localizationService); } [Fact] public void GetLocalization_CallsLocalizationService() { var expectedResponse = new LocalizationViewModel(); - this.localizationService.Setup(s => s.ViewModel) - .Returns(expectedResponse); + this.localizationService.ViewModel.Returns(expectedResponse); var result = this.localizationController.GetLocalization(); diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ServiceRouteMapperTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ServiceRouteMapperTests.cs index 05463e3..ad49bed 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ServiceRouteMapperTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Controllers/ServiceRouteMapperTests.cs @@ -1,11 +1,6 @@ using $ext_rootnamespace$.Controllers; using DotNetNuke.Web.Api; -using Moq; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using NSubstitute; using Xunit; namespace UnitTests.Controllers @@ -15,12 +10,12 @@ public class ServiceRouteMapperTests [Fact] public void RegisterRoutes_RegistersAtLestOneRoute() { - var mapRouteManager = new Mock(); + var mapRouteManager = Substitute.For(); var serviceRouteMapper = new ServiceRouteMapper(); - serviceRouteMapper.RegisterRoutes(mapRouteManager.Object); + serviceRouteMapper.RegisterRoutes(mapRouteManager); - mapRouteManager.Verify(m => m.MapHttpRoute(It.IsAny(), It.IsAny(), It.IsAny(), It.IsNotNull()), Times.AtLeastOnce); + mapRouteManager.MapHttpRoute(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Is(x => x != null)); } } } \ No newline at end of file diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Data/Repositories/GenericRepositoryTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Data/Repositories/GenericRepositoryTests.cs index 80e712c..3ee08ad 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Data/Repositories/GenericRepositoryTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Data/Repositories/GenericRepositoryTests.cs @@ -1,8 +1,8 @@ using $ext_rootnamespace$.Data.Entities; using $ext_rootnamespace$.Data.Repositories; using $ext_rootnamespace$.Providers; -using Moq; using Newtonsoft.Json; +using NSubstitute; using System; using System.Linq; using System.Threading.Tasks; @@ -12,19 +12,19 @@ namespace UnitTests.Data.Repositories { public class GenericRepositoryTests : FakeDataContext { - private readonly Mock dateTimeProvider; + private readonly IDateTimeProvider dateTimeProvider; public GenericRepositoryTests() { - this.dateTimeProvider = new Mock(); - this.dateTimeProvider.Setup(p => p.GetUtcNow()).Returns(new DateTime(2022, 1, 1)); + this.dateTimeProvider = Substitute.For(); + this.dateTimeProvider.GetUtcNow().Returns(new DateTime(2022, 1, 1)); } [Fact] public void GenericRepositoryConstructs() { - var repository = new Repository(dataContext, this.dateTimeProvider.Object); - + var repository = new Repository(dataContext, this.dateTimeProvider); + Assert.NotNull(dataContext); Assert.NotNull(repository); } @@ -32,7 +32,7 @@ public void GenericRepositoryConstructs() [Fact] public async Task GenericRepositoryCreatesAndGetsById() { - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var repository = new Repository(dataContext, this.dateTimeProvider); var expectedItem = new Item() { Id = 1, Name = "Name", Description = "Description" }; await repository.CreateAsync(expectedItem); @@ -44,7 +44,7 @@ public async Task GenericRepositoryCreatesAndGetsById() [Fact] public async Task GenericRepositoryDeletes() { - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var repository = new Repository(dataContext, this.dateTimeProvider); var item = new Item() { Id = 1, Name = "Name", Description = "Description" }; await repository.CreateAsync(item); @@ -58,7 +58,7 @@ public void GenericRepositoryGet() { this.dataContext.Items.Add(new Item() { Id = 1, Name = "Name", Description = "Description" }); this.dataContext.SaveChanges(); - var repository = new Repository(this.dataContext, this.dateTimeProvider.Object); + var repository = new Repository(this.dataContext, this.dateTimeProvider); var items = repository.Get(); @@ -72,7 +72,7 @@ public void GenericRepositoryGet() [InlineData(3)] public async Task GenericRepositoryGetsAll(int iterations) { - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var repository = new Repository(dataContext, this.dateTimeProvider); for (int i = 1; i <= iterations; i++) { var item = new Item() { Id = i, Name = $"Name {i}", Description = $"Description {i}" }; @@ -89,14 +89,14 @@ public async Task GenericRepositoryGetsAll(int iterations) public async Task GenericRepositoryUpdates() { var createdTime = new DateTime(2022, 1, 1); - this.dateTimeProvider.Setup(p => p.GetUtcNow()).Returns(createdTime); - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + this.dateTimeProvider.GetUtcNow().Returns(createdTime); + var repository = new Repository(dataContext, this.dateTimeProvider); await repository.CreateAsync(new Item() { Id = 1, Name = "Original Name", Description = "Original Description" }); var entity = await repository.GetByIdAsync(1); entity.Name = "New Name"; entity.Description = "New Description"; var updatedTime = createdTime.AddDays(1); - this.dateTimeProvider.Setup(p => p.GetUtcNow()).Returns(updatedTime); + this.dateTimeProvider.GetUtcNow().Returns(updatedTime); await repository.UpdateAsync(entity); @@ -108,7 +108,7 @@ public async Task GenericRepositoryUpdates() [Fact] public async Task GenericRepositoryCreate_ThrowsWithNullEntity() { - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var repository = new Repository(dataContext, this.dateTimeProvider); Task create() => repository.CreateAsync(null); @@ -119,7 +119,7 @@ public async Task GenericRepositoryCreate_ThrowsWithNullEntity() [Fact] public async Task GenericRepositoryUpdate_ThrowsWithNullEntity() { - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var repository = new Repository(dataContext, this.dateTimeProvider); Task update() => repository.UpdateAsync(null); @@ -130,7 +130,7 @@ public async Task GenericRepositoryUpdate_ThrowsWithNullEntity() [Fact] public async Task Repository_Create_DefaultAudit() { - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var repository = new Repository(dataContext, this.dateTimeProvider); var item = new Item() { Name = "Name", Description = "Description" }; await repository.CreateAsync(item); @@ -138,14 +138,14 @@ public async Task Repository_Create_DefaultAudit() Assert.Equal(-1, item.CreatedByUserId); Assert.Equal(-1, item.UpdatedByUserId); Assert.True(item.CreatedAt == item.UpdatedAt); - Assert.Equal(item.CreatedAt, this.dateTimeProvider.Object.GetUtcNow()); - Assert.Equal(item.UpdatedAt, this.dateTimeProvider.Object.GetUtcNow()); + Assert.Equal(item.CreatedAt, this.dateTimeProvider.GetUtcNow()); + Assert.Equal(item.UpdatedAt, this.dateTimeProvider.GetUtcNow()); } [Fact] public async Task Repository_Create_UsesUserId() { - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var repository = new Repository(dataContext, this.dateTimeProvider); var item = new Item() { Name = "Name", Description = "Description" }; await repository.CreateAsync(item, 123); @@ -157,11 +157,11 @@ public async Task Repository_Create_UsesUserId() [Fact] public async Task Repository_Update_DefaultAudit() { - var currentTime = this.dateTimeProvider.Object.GetUtcNow(); - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var currentTime = this.dateTimeProvider.GetUtcNow(); + var repository = new Repository(dataContext, this.dateTimeProvider); var item = new Item() { Name = "Name", Description = "Description" }; var id = await repository.CreateAsync(item); - this.dateTimeProvider.Setup(p => p.GetUtcNow()).Returns(currentTime.AddDays(1)); + this.dateTimeProvider.GetUtcNow().Returns(currentTime.AddDays(1)); var itemToUpdate = await repository.GetByIdAsync(id); itemToUpdate.Name = "New Name"; itemToUpdate.Description = "New Description"; @@ -176,13 +176,13 @@ public async Task Repository_Update_DefaultAudit() [Fact] public async Task Repository_Update_UsesUserId() { - var now = this.dateTimeProvider.Object.GetUtcNow(); - var repository = new Repository(dataContext, this.dateTimeProvider.Object); + var now = this.dateTimeProvider.GetUtcNow(); + var repository = new Repository(dataContext, this.dateTimeProvider); var item = new Item() { Name = "Name", Description = "Description" }; await repository.CreateAsync(item); item.Name = "New Name"; item.Description = "New Description"; - this.dateTimeProvider.Setup(p => p.GetUtcNow()).Returns(now.AddDays(1)); + this.dateTimeProvider.GetUtcNow().Returns(now.AddDays(1)); await repository.UpdateAsync(item, 123); @@ -197,7 +197,7 @@ public async Task Repository_Update_UsesUserId() [Fact] public async Task Repository_DeleteMissing_DoesNotThrow() { - var repository = new Repository(this.dataContext, this.dateTimeProvider.Object); + var repository = new Repository(this.dataContext, this.dateTimeProvider); await repository.DeleteAsync(1); } @@ -213,7 +213,7 @@ public async Task GetPage_Pages( int expectedPages) { this.CreateItems(100); - var repository = new Repository(this.dataContext, this.dateTimeProvider.Object); + var repository = new Repository(this.dataContext, this.dateTimeProvider); var result = await repository.GetPageAsync( page, @@ -251,7 +251,7 @@ public async Task Pages_With_Related_Entities() } await context.SaveChangesAsync(); } - var repository = new Repository(context, this.dateTimeProvider.Object); + var repository = new Repository(context, this.dateTimeProvider); var result = await repository.GetPageAsync( 1, diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj index 8849107..c57144f 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/ProjectTemplate.csproj @@ -46,8 +46,8 @@ - + diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Providers/DateTimeProviderTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Providers/DateTimeProviderTests.cs index 69a292b..8de1dd2 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Providers/DateTimeProviderTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Providers/DateTimeProviderTests.cs @@ -1,5 +1,5 @@ using $ext_rootnamespace$.Providers; -using Moq; +using NSubstitute; using System; using Xunit; @@ -8,12 +8,12 @@ namespace UnitTests.Providers public class DateTimeProviderTests { private readonly IDateTimeProvider provider; - private readonly Mock providerMock; + private readonly IDateTimeProvider providerMock; public DateTimeProviderTests() { this.provider = new DateTimeProvider(); - this.providerMock = new Mock(); + this.providerMock = Substitute.For(); } [Fact] @@ -36,10 +36,10 @@ public void DateTimeProvider_CanBeMocked() { // Arrange var expected = new DateTime(2022, 1, 1); - this.providerMock.Setup(p => p.GetUtcNow()).Returns(expected); + this.providerMock.GetUtcNow().Returns(expected); // Act - var actual = this.providerMock.Object.GetUtcNow(); + var actual = this.providerMock.GetUtcNow(); // Assert Assert.Equal(expected, actual); diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/CreateItemDtoValidatorTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/CreateItemDtoValidatorTests.cs index b5e4c26..751a63e 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/CreateItemDtoValidatorTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/CreateItemDtoValidatorTests.cs @@ -1,7 +1,7 @@ using $ext_rootnamespace$.Services.Items; using $ext_rootnamespace$.Services.Localization; using FluentValidation; -using Moq; +using NSubstitute; using System.Threading.Tasks; using Xunit; @@ -10,7 +10,7 @@ namespace UnitTests.Services.Items public class CreateItemDtoValidatorTests { LocalizationViewModel localizationViewModel; - Mock localizationService; + ILocalizationService localizationService; private readonly IValidator validator; public CreateItemDtoValidatorTests() @@ -22,9 +22,9 @@ public CreateItemDtoValidatorTests() NameRequired = "Name is required", }, }; - this.localizationService = new Mock(); - localizationService.Setup(l => l.ViewModel).Returns(localizationViewModel); - this.validator = new CreateItemDtoValidator(localizationService.Object); + this.localizationService = Substitute.For(); + localizationService.ViewModel.Returns(localizationViewModel); + this.validator = new CreateItemDtoValidator(localizationService); } [Theory] diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/ItemServiceTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/ItemServiceTests.cs index d760d7e..cba06ff 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/ItemServiceTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/ItemServiceTests.cs @@ -3,7 +3,7 @@ using $ext_rootnamespace$.Services.Items; using FluentValidation; using FluentValidation.Results; -using Moq; +using NSubstitute; using System; using System.Collections.Generic; using System.Linq; @@ -16,21 +16,21 @@ namespace UnitTests.Services.Items public class ItemServiceTests { private CancellationToken token; - private Mock> itemRepository; + private IRepository itemRepository; private IItemService itemService; - private Mock> createItemDtoValidator; - private Mock> updateItemDtoValidator; + private IValidator createItemDtoValidator; + private IValidator updateItemDtoValidator; public ItemServiceTests() { this.token = new CancellationToken(); - this.itemRepository = new Mock>(); - this.createItemDtoValidator = new Mock>(); - this.updateItemDtoValidator = new Mock>(); + this.itemRepository = Substitute.For>(); + this.createItemDtoValidator = Substitute.For>(); + this.updateItemDtoValidator = Substitute.For>(); this.itemService = new ItemService( - this.itemRepository.Object, - this.createItemDtoValidator.Object, - this.updateItemDtoValidator.Object); + this.itemRepository, + this.createItemDtoValidator, + this.updateItemDtoValidator); } [Fact] @@ -39,7 +39,7 @@ public async Task CreateItem_ValidatesDto() // Arrange var dto = new CreateItemDTO(); var userId = 123; - this.createItemDtoValidator.Setup(v => v.ValidateAsync(It.IsAny(), this.token)) + this.createItemDtoValidator.ValidateAsync(Arg.Any(), this.token) .Returns(Task.FromResult(new ValidationResult { Errors = { new ValidationFailure("Name", "Name is required.") }, @@ -55,21 +55,24 @@ public async Task CreateItem_ValidatesDto() public async Task CreateItem_Creates() { var item = new CreateItemDTO() { Name = "Name", Description = "Description" }; - this.createItemDtoValidator.Setup(v => v.ValidateAsync(It.IsAny(), this.token)) + this.createItemDtoValidator.ValidateAsync(Arg.Any(), this.token) .Returns(Task.FromResult(new ValidationResult())); - this.itemRepository.Setup(r => r.CreateAsync(It.IsAny(), It.IsAny())) - .Callback((i, u) => + this.itemRepository.CreateAsync(Arg.Any(), Arg.Any()) + .Returns(callInfo => { + var i = callInfo.ArgAt(0); i.Id = 1; i.Name = item.Name; i.Description = item.Description; + return 1; }); + var result = await this.itemService.CreateItemAsync(item, 123); - this.itemRepository.Verify(r => - r.CreateAsync(It.Is(i => - i.Name == item.Name && - i.Description == item.Description), 123)); + await this.itemRepository.Received(1).CreateAsync( + Arg.Is(i => + i.Name == item.Name && + i.Description == item.Description), 123); result.Switch( success => { Assert.Equal(1, success.Value.Id); @@ -95,10 +98,10 @@ public async Task GetItemsPage_GetsPages(bool descending) } var returnedPage = new PagedList( returnedItems, 1, 10, 30, 3); - this.itemRepository.Setup(i => i.GetPageAsync( - It.IsAny(), - It.IsAny(), - It.IsAny, IOrderedQueryable>>())) + this.itemRepository.GetPageAsync( + Arg.Any(), + Arg.Any(), + Arg.Any, IOrderedQueryable>>()) .Returns(Task.FromResult(returnedPage)); var finalReturn = await this.itemService.GetItemsPageAsync("test", 1, 10, descending); @@ -116,7 +119,7 @@ public async Task DeleteItem_Deletes() await this.itemService.DeleteItemAsync(itemId); - this.itemRepository.Verify(i => i.DeleteAsync(123), Times.Once); + await this.itemRepository.Received().DeleteAsync(123); } [Fact] @@ -136,9 +139,9 @@ public async Task UpdateItem_ValidatesDto() Description = "New Item Description", }; var userId = 123; - this.itemRepository.Setup(r => r.GetByIdAsync(It.IsAny())) + this.itemRepository.GetByIdAsync(Arg.Any()) .Returns(Task.FromResult(originalItem)); - this.updateItemDtoValidator.Setup(v => v.ValidateAsync(It.IsAny(), this.token)) + this.updateItemDtoValidator.ValidateAsync(Arg.Any(), this.token) .Returns(Task.FromResult(new ValidationResult { Errors = { new ValidationFailure("Id", "ID must be positive") }, @@ -169,17 +172,17 @@ public async Task UpdateItem_Updates() Name = "New Item Name", Description = "New Item Description", }; - this.itemRepository.Setup(r => r.GetByIdAsync(It.IsAny())) + this.itemRepository.GetByIdAsync(Arg.Any()) .Returns(Task.FromResult(originalItem)); - this.updateItemDtoValidator.Setup(v => v.ValidateAsync(It.IsAny(), this.token)) + this.updateItemDtoValidator.ValidateAsync(Arg.Any(), this.token) .Returns(Task.FromResult(new ValidationResult())); await this.itemService.UpdateItemAsync(item, 2); - itemRepository.Verify(r => r.UpdateAsync(It.Is(i => + await itemRepository.Received().UpdateAsync(Arg.Is(i => i.Id == item.Id && i.Name == item.Name && - i.Description == item.Description), 2), Times.Once); + i.Description == item.Description), 2); } } } diff --git a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/UpdateItemDtoValidatorTests.cs b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/UpdateItemDtoValidatorTests.cs index b4651b5..7876a00 100644 --- a/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/UpdateItemDtoValidatorTests.cs +++ b/Eraware_Dnn_Spa_Ef_Di_Stencil/UnitTests/Services/Items/UpdateItemDtoValidatorTests.cs @@ -1,7 +1,7 @@ using $ext_rootnamespace$.Services.Items; using $ext_rootnamespace$.Services.Localization; using FluentValidation; -using Moq; +using NSubstitute; using System.Threading.Tasks; using Xunit; @@ -10,7 +10,7 @@ namespace UnitTests.Services.Items public class UpdateItemDtoValidatorTests { LocalizationViewModel localizationViewModel; - Mock localizationService; + ILocalizationService localizationService; private readonly IValidator validator; public UpdateItemDtoValidatorTests() @@ -23,9 +23,9 @@ public UpdateItemDtoValidatorTests() IdGreaterThanZero = "Id must be greater than zero", }, }; - this.localizationService = new Mock(); - localizationService.Setup(l => l.ViewModel).Returns(localizationViewModel); - this.validator = new UpdateItemDtoValidator(localizationService.Object); + this.localizationService = Substitute.For(); + localizationService.ViewModel.Returns(localizationViewModel); + this.validator = new UpdateItemDtoValidator(localizationService); } [Theory]