diff --git a/RapidField.SolidInstruments.sln b/RapidField.SolidInstruments.sln index a61a4743..6b06ab85 100644 --- a/RapidField.SolidInstruments.sln +++ b/RapidField.SolidInstruments.sln @@ -403,7 +403,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RapidField.SolidInstruments EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RapidField.SolidInstruments.Example.Domain.AccessControl.Service", "example\RapidField.SolidInstruments.Example.Domain.AccessControl.Service\RapidField.SolidInstruments.Example.Domain.AccessControl.Service.csproj", "{77026FD0-F0DC-48B8-A678-0E67BDCC29EB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RapidField.SolidInstruments.Example.BeaconService", "example\RapidField.SolidInstruments.Example.BeaconService\RapidField.SolidInstruments.Example.BeaconService.csproj", "{423CCBD1-0299-4C1A-BFDB-05AF2BF4847A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RapidField.SolidInstruments.Example.BeaconService", "example\RapidField.SolidInstruments.Example.BeaconService\RapidField.SolidInstruments.Example.BeaconService.csproj", "{423CCBD1-0299-4C1A-BFDB-05AF2BF4847A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi", "example\RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi\RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj", "{AC2D0816-3ABF-4458-80DB-E4BADDD9A2E0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RapidField.SolidInstruments.Example.Domain.Identity", "example\RapidField.SolidInstruments.Example.Domain.Identity\RapidField.SolidInstruments.Example.Domain.Identity.csproj", "{630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RapidField.SolidInstruments.Example.Domain.Identity.Service", "example\RapidField.SolidInstruments.Example.Domain.Identity.Service\RapidField.SolidInstruments.Example.Domain.Identity.Service.csproj", "{352E9021-1010-4A5D-8435-F8331DA63F95}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -631,6 +637,18 @@ Global {423CCBD1-0299-4C1A-BFDB-05AF2BF4847A}.Debug|Any CPU.Build.0 = Debug|Any CPU {423CCBD1-0299-4C1A-BFDB-05AF2BF4847A}.Release|Any CPU.ActiveCfg = Release|Any CPU {423CCBD1-0299-4C1A-BFDB-05AF2BF4847A}.Release|Any CPU.Build.0 = Release|Any CPU + {AC2D0816-3ABF-4458-80DB-E4BADDD9A2E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC2D0816-3ABF-4458-80DB-E4BADDD9A2E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC2D0816-3ABF-4458-80DB-E4BADDD9A2E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC2D0816-3ABF-4458-80DB-E4BADDD9A2E0}.Release|Any CPU.Build.0 = Release|Any CPU + {630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025}.Debug|Any CPU.Build.0 = Debug|Any CPU + {630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025}.Release|Any CPU.ActiveCfg = Release|Any CPU + {630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025}.Release|Any CPU.Build.0 = Release|Any CPU + {352E9021-1010-4A5D-8435-F8331DA63F95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {352E9021-1010-4A5D-8435-F8331DA63F95}.Debug|Any CPU.Build.0 = Debug|Any CPU + {352E9021-1010-4A5D-8435-F8331DA63F95}.Release|Any CPU.ActiveCfg = Release|Any CPU + {352E9021-1010-4A5D-8435-F8331DA63F95}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -707,6 +725,9 @@ Global {7B185E3A-3A26-4188-9FB4-DED7E4EF5C3D} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} {77026FD0-F0DC-48B8-A678-0E67BDCC29EB} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} {423CCBD1-0299-4C1A-BFDB-05AF2BF4847A} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} + {AC2D0816-3ABF-4458-80DB-E4BADDD9A2E0} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} + {630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} + {352E9021-1010-4A5D-8435-F8331DA63F95} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {834FCFB0-DA00-4ABD-9424-6FE1398A9F6E} diff --git a/cicd/modules/BuildAndDeployment.psm1 b/cicd/modules/BuildAndDeployment.psm1 index 4e2f3c2a..f0b92d0b 100644 --- a/cicd/modules/BuildAndDeployment.psm1 +++ b/cicd/modules/BuildAndDeployment.psm1 @@ -87,8 +87,10 @@ $SolutionConfigurationDebug = "Debug"; $SolutionConfigurationRelease = "Release"; # Namespaces +$ExampleAccessControlHttpApiApplicationNamespace = "RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi"; $ExampleAccessControlServiceApplicationNamespace = "RapidField.SolidInstruments.Example.Domain.AccessControl.Service"; $ExampleBeaconServiceApplicationNamespace = "RapidField.SolidInstruments.Example.BeaconService"; +$ExampleIdentityServiceApplicationNamespace = "RapidField.SolidInstruments.Example.Domain.Identity.Service"; # Regular expressions $ValidCommitMessageRegularExpressionPattern = "^(#[1-9][0-9]{0,4} )?[A-Z][A-Za-z0-9\,\.\!\;\:\'\""\@\#\$\%\^\&\*\-\+\=_\(\)\[\]\{\}\|\\\/\s]{8,144}$"; @@ -113,7 +115,8 @@ $RepositoryName = $env:APPVEYOR_REPO_NAME; $TagName = $env:APPVEYOR_REPO_TAG_NAME; # Other configuration values -$TargetFrameworkForExampleServiceApplication = "netcoreapp2.1"; +$TargetFrameworkForExampleHttpApiApplications = "netcoreapp3.1"; +$TargetFrameworkForExampleServiceApplications = "netcoreapp3.1"; # Modules Import-Module $FilePathForCoreModule -Force; @@ -609,7 +612,48 @@ Function SignPackages <# .Synopsis -Starts the example access control service application. +Starts the example AccessControl domain HTTP API application. +#> +Function StartExampleAccessControlHttpApiApplication +{ + Param + ( + [Parameter(Mandatory = $true, Position = 0)] + [String] $SolutionConfiguration + ) + + ComposeStart "Starting the example AccessControl domain HTTP API application using $SolutionConfiguration configuration."; + $BinaryDirectoryPath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleAccessControlHttpApiApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleHttpApiApplications"; + $BinaryFileName = "$ExampleAccessControlHttpApiApplicationNamespace.dll"; + $BinaryFilePath = Join-Path -Path "$BinaryDirectoryPath" -ChildPath "$BinaryFileName"; + ComposeNormal "Using binary path: $BinaryFilePath"; + Push-Location "$BinaryDirectoryPath"; + Start-Process -ArgumentList "$BinaryFileName" -FilePath "dotnet" -WindowStyle Minimized; + Pop-Location; + ComposeFinish "Finished starting the application."; +} + +<# +.Synopsis +Starts the example AccessControl domain HTTP API application in debug mode. +#> +Function StartExampleAccessControlHttpApiApplicationDebug +{ + StartExampleAccessControlHttpApiApplication -SolutionConfiguration $SolutionConfigurationDebug; +} + +<# +.Synopsis +Starts the example AccessControl domain HTTP API application in release mode. +#> +Function StartExampleAccessControlHttpApiApplicationRelease +{ + StartExampleAccessControlHttpApiApplication -SolutionConfiguration $SolutionConfigurationRelease; +} + +<# +.Synopsis +Starts the example AccessControl domain service application. #> Function StartExampleAccessControlServiceApplication { @@ -619,16 +663,20 @@ Function StartExampleAccessControlServiceApplication [String] $SolutionConfiguration ) - ComposeStart "Starting the example access control service application using $SolutionConfiguration configuration."; - $BinaryFilePath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleServiceApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleServiceApplication\$ExampleAccessControlServiceApplicationNamespace.dll"; + ComposeStart "Starting the example AccessControl domain service application using $SolutionConfiguration configuration."; + $BinaryDirectoryPath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleAccessControlServiceApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleServiceApplications"; + $BinaryFileName = "$ExampleAccessControlServiceApplicationNamespace.dll"; + $BinaryFilePath = Join-Path -Path "$BinaryDirectoryPath" -ChildPath "$BinaryFileName"; ComposeNormal "Using binary path: $BinaryFilePath"; - Start-Process -ArgumentList "$BinaryFilePath" -FilePath "dotnet" -WindowStyle Minimized; + Push-Location "$BinaryDirectoryPath"; + Start-Process -ArgumentList "$BinaryFileName" -FilePath "dotnet" -WindowStyle Minimized; + Pop-Location; ComposeFinish "Finished starting the application."; } <# .Synopsis -Starts the example access control service application in debug mode. +Starts the example AccessControl domain service application in debug mode. #> Function StartExampleAccessControlServiceApplicationDebug { @@ -637,7 +685,7 @@ Function StartExampleAccessControlServiceApplicationDebug <# .Synopsis -Starts the example access control service application in release mode. +Starts the example AccessControl domain service application in release mode. #> Function StartExampleAccessControlServiceApplicationRelease { @@ -646,7 +694,7 @@ Function StartExampleAccessControlServiceApplicationRelease <# .Synopsis -Starts the example beacon service application. +Starts the example Beacon service application. #> Function StartExampleBeaconServiceApplication { @@ -657,15 +705,19 @@ Function StartExampleBeaconServiceApplication ) ComposeStart "Starting the example beacon service application using $SolutionConfiguration configuration."; - $BinaryFilePath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleServiceApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleServiceApplication\$ExampleBeaconServiceApplicationNamespace.dll"; + $BinaryDirectoryPath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleBeaconServiceApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleServiceApplications"; + $BinaryFileName = "$ExampleBeaconServiceApplicationNamespace.dll"; + $BinaryFilePath = Join-Path -Path "$BinaryDirectoryPath" -ChildPath "$BinaryFileName"; ComposeNormal "Using binary path: $BinaryFilePath"; - Start-Process -ArgumentList "$BinaryFilePath" -FilePath "dotnet" -WindowStyle Minimized; + Push-Location "$BinaryDirectoryPath"; + Start-Process -ArgumentList "$BinaryFileName" -FilePath "dotnet" -WindowStyle Minimized; + Pop-Location; ComposeFinish "Finished starting the application."; } <# .Synopsis -Starts the example beacon service application in debug mode. +Starts the example Beacon service application in debug mode. #> Function StartExampleBeaconServiceApplicationDebug { @@ -674,13 +726,54 @@ Function StartExampleBeaconServiceApplicationDebug <# .Synopsis -Starts the example beacon service application in release mode. +Starts the example Beacon service application in release mode. #> Function StartExampleBeaconServiceApplicationRelease { StartExampleBeaconServiceApplication -SolutionConfiguration $SolutionConfigurationRelease; } +<# +.Synopsis +Starts the example Identity domain service application. +#> +Function StartExampleIdentityServiceApplication +{ + Param + ( + [Parameter(Mandatory = $true, Position = 0)] + [String] $SolutionConfiguration + ) + + ComposeStart "Starting the example Identity domain service application using $SolutionConfiguration configuration."; + $BinaryDirectoryPath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleIdentityServiceApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleServiceApplications"; + $BinaryFileName = "$ExampleIdentityServiceApplicationNamespace.dll"; + $BinaryFilePath = Join-Path -Path "$BinaryDirectoryPath" -ChildPath "$BinaryFileName"; + ComposeNormal "Using binary path: $BinaryFilePath"; + Push-Location "$BinaryDirectoryPath"; + Start-Process -ArgumentList "$BinaryFileName" -FilePath "dotnet" -WindowStyle Minimized; + Pop-Location; + ComposeFinish "Finished starting the application."; +} + +<# +.Synopsis +Starts the example Identity domain service application in debug mode. +#> +Function StartExampleIdentityServiceApplicationDebug +{ + StartExampleIdentityServiceApplication -SolutionConfiguration $SolutionConfigurationDebug; +} + +<# +.Synopsis +Starts the example Identity domain service application in release mode. +#> +Function StartExampleIdentityServiceApplicationRelease +{ + StartExampleIdentityServiceApplication -SolutionConfiguration $SolutionConfigurationRelease; +} + <# .Synopsis Stops all running .NET applications. diff --git a/example/README.md b/example/README.md index 5c210b9b..e0c130a1 100644 --- a/example/README.md +++ b/example/README.md @@ -15,8 +15,11 @@ This path contains sample projects that utilize the **Solid Instruments** [const - [`RapidField.SolidInstruments.Example.BeaconService`](/example/RapidField.SolidInstruments.Example.BeaconService) demonstrates a utility service that publishes scheduled heartbeat messages. - [`RapidField.SolidInstruments.Example.Domain`](/example/RapidField.SolidInstruments.Example.Domain) houses a sample collection of shared domain models that utilize the **Solid Instruments** [messaging](../src/RapidField.SolidInstruments.Messaging/README.md) constructs. -- [`RapidField.SolidInstruments.Example.Domain.AccessControl`](/example/RapidField.SolidInstruments.Example.Domain.AccessControl) demonstrates access control domain logic utilizing the **Solid Instruments** [data access](../src/RapidField.SolidInstruments.DataAccess/README.md) constructs. -- [`RapidField.SolidInstruments.Example.Domain.AccessControl.Service`](/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service) demonstrates an access control domain service utilizing the **Solid Instruments** [data access](../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../src/RapidField.SolidInstruments.Messaging/README.md) constructs. +- [`RapidField.SolidInstruments.Example.Domain.AccessControl`](/example/RapidField.SolidInstruments.Example.Domain.AccessControl) demonstrates AccessControl domain logic utilizing the **Solid Instruments** [data access](../src/RapidField.SolidInstruments.DataAccess/README.md) constructs. +- [`RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi`](/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi) demonstrates an AccessControl domain HTTP API utilizing the **Solid Instruments** [data access](../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../src/RapidField.SolidInstruments.Messaging/README.md) constructs. +- [`RapidField.SolidInstruments.Example.Domain.AccessControl.Service`](/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service) demonstrates an AccessControl domain service utilizing the **Solid Instruments** [data access](../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../src/RapidField.SolidInstruments.Messaging/README.md) constructs. +- [`RapidField.SolidInstruments.Example.Domain.Identity`](/example/RapidField.SolidInstruments.Example.Domain.Identity) demonstrates Identity domain logic utilizing the **Solid Instruments** [data access](../src/RapidField.SolidInstruments.DataAccess/README.md) constructs. +- [`RapidField.SolidInstruments.Example.Domain.Identity.Service`](/example/RapidField.SolidInstruments.Example.Domain.Identity.Service) demonstrates an Identity domain service utilizing the **Solid Instruments** [data access](../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../src/RapidField.SolidInstruments.Messaging/README.md) constructs. ## License diff --git a/example/RapidField.SolidInstruments.Example.BeaconService/RapidField.SolidInstruments.Example.BeaconService.csproj b/example/RapidField.SolidInstruments.Example.BeaconService/RapidField.SolidInstruments.Example.BeaconService.csproj index b0180320..9f36872d 100644 --- a/example/RapidField.SolidInstruments.Example.BeaconService/RapidField.SolidInstruments.Example.BeaconService.csproj +++ b/example/RapidField.SolidInstruments.Example.BeaconService/RapidField.SolidInstruments.Example.BeaconService.csproj @@ -34,7 +34,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyPackage.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyPackage.cs new file mode 100644 index 00000000..fc762217 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyPackage.cs @@ -0,0 +1,43 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using RapidField.SolidInstruments.InversionOfControl; +using RapidField.SolidInstruments.InversionOfControl.DotNetNative; +using System.Collections.Generic; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi +{ + /// + /// Encapsulates container configuration for the application. + /// + public class ApplicationDependencyPackage : DotNetNativeDependencyPackage + { + /// + /// Initializes a new instance of the class. + /// + public ApplicationDependencyPackage() + : base() + { + return; + } + + /// + /// Creates a new collection of dependency modules for the package. + /// + /// + /// Configuration information for the application. + /// + /// + /// The package's dependency modules. + /// + protected override IEnumerable> CreateModules(IConfiguration applicationConfiguration) => new IDependencyModule[] + { + new DatabaseContextDependencyModule(applicationConfiguration), + new ServiceBusDependencyModule(applicationConfiguration), + new MessageHandlerModule(applicationConfiguration) + }; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/UserController.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/UserController.cs new file mode 100644 index 00000000..eed70a41 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/UserController.cs @@ -0,0 +1,152 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Mvc; +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Example.Domain.Commands.ModelState.User; +using RapidField.SolidInstruments.Example.Domain.Messages.Command.ModelState.User; +using RapidField.SolidInstruments.Example.Domain.Models.User; +using System; +using System.Diagnostics; +using System.Net; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.Controllers +{ + /// + /// Processes HTTP requests for the ~/User endpoint. + /// + [ApiController] + [Route("[controller]")] + public sealed class UserController : ControllerBase + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + public UserController(ICommandMediator mediator) + { + Mediator = mediator.RejectIf().IsNull(nameof(mediator)).TargetArgument; + } + + /// + /// Handles DELETE requests for the endpoint. + /// + /// + /// An identifier by which to find the . + /// + /// + /// A status code result. + /// + [HttpDelete] + public IActionResult Delete([FromQuery] Guid identifier) + { + try + { + return Ok(); + } + catch (ArgumentException exception) + { + return BadRequest($"{exception.Message} {exception.StackTrace}"); + } + catch (Exception exception) + { + return StatusCode((Int32)HttpStatusCode.InternalServerError, $"{exception.Message} {exception.StackTrace}"); + } + } + + /// + /// Handles GET requests for the endpoint. + /// + /// + /// An identifier by which to find the . + /// + /// + /// A with matching , or if no matching + /// model exists. + /// + [HttpGet] + public IActionResult Get([FromQuery] Guid identifier) + { + try + { + var model = (DomainModel)null; + return new JsonResult(model); + } + catch (ArgumentException exception) + { + return BadRequest($"{exception.Message} {exception.StackTrace}"); + } + catch (Exception exception) + { + return StatusCode((Int32)HttpStatusCode.InternalServerError, $"{exception.Message} {exception.StackTrace}"); + } + } + + /// + /// Handles POST requests for the endpoint. + /// + /// + /// The to create. + /// + /// + /// A status code result. + /// + [HttpPost] + public IActionResult Post([FromBody] DomainModel model) + { + try + { + _ = Mediator.Process(new CreateDomainModelCommandMessage(new CreateDomainModelCommand(model))); + return Ok(); + } + catch (ArgumentException exception) + { + return BadRequest($"{exception.Message} {exception.StackTrace}"); + } + catch (Exception exception) + { + return StatusCode((Int32)HttpStatusCode.InternalServerError, $"{exception.Message} {exception.StackTrace}"); + } + } + + /// + /// Handles PUT requests for the endpoint. + /// + /// + /// The to create. + /// + /// + /// A status code result. + /// + [HttpPut] + public IActionResult Put([FromBody] DomainModel model) + { + try + { + _ = Mediator.Process(new UpdateDomainModelCommandMessage(new UpdateDomainModelCommand(model))); + return Ok(); + } + catch (ArgumentException exception) + { + return BadRequest($"{exception.Message} {exception.StackTrace}"); + } + catch (Exception exception) + { + return StatusCode((Int32)HttpStatusCode.InternalServerError, $"{exception.Message} {exception.StackTrace}"); + } + } + + /// + /// Represents processing intermediary that is used to process sub-commands. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly ICommandMediator Mediator; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Program.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Program.cs new file mode 100644 index 00000000..8ac60e1a --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Program.cs @@ -0,0 +1,38 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using System; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi +{ + /// + /// Houses the entry point for the application. + /// + public static class Program + { + /// + /// Configures the application hosting environment. + /// + /// + /// Command line arguments that are provided at runtime. + /// + /// + /// The resulting host configuration. + /// + public static IHostBuilder CreateHostBuilder(String[] args) => Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + + /// + /// Begins execution of the application. + /// + /// + /// Command line arguments that are provided at runtime. + /// + public static void Main(String[] args) => CreateHostBuilder(args).Build().Run(); + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Properties/launchSettings.json b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Properties/launchSettings.json new file mode 100644 index 00000000..9a6041f5 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:57484", + "sslPort": 44319 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "weatherforecast", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/README.md b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/README.md new file mode 100644 index 00000000..72ef86e3 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/README.md @@ -0,0 +1,30 @@ + + +[![Solid Instruments](../../SolidInstruments.Logo.Color.Transparent.500w.png)](../../README.md) +- - - + +# RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi + +This document describes the purpose of the [`RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi`]() project. + +## Purpose + +This project demonstrates an AccessControl domain HTTP API utilizing the **Solid Instruments** [data access](../../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../../src/RapidField.SolidInstruments.Messaging/README.md) constructs. + +## License + +[![License](https://img.shields.io/github/license/rapidfield/solid-instruments?style=flat&color=lightseagreen&label=license&logo=open-access&logoColor=lightgrey)](../../LICENSE.txt) + +**Solid Instruments** is [MIT-licensed](https://en.wikipedia.org/wiki/MIT_License). Review the [license terms](../../LICENSE.txt) for more information. + +
+ +- - - + +
+ +[![RapidField](../../RapidField.Logo.Color.Black.Transparent.200w.png)](https://www.rapidfield.com) + +###### Copyright (c) RapidField LLC. All rights reserved. "RapidField" and "Solid Instruments" are trademarks of RapidField LLC. \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj new file mode 100644 index 00000000..3ce434a5 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj @@ -0,0 +1,25 @@ + + + + + Solid Instruments contributors + RapidField + Copyright (c) RapidField LLC. All rights reserved. + Solid Instruments + This project demonstrates an AccessControl domain HTTP API application utilizing Solid Instruments constructs. + $(BuildVersion) + netcoreapp3.1 + latest + + + true + + + + + + + + \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Startup.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Startup.cs new file mode 100644 index 00000000..34859fc7 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Startup.cs @@ -0,0 +1,64 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +#pragma warning disable CA1822 // Mark members as static + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi +{ + /// + /// Encapsulates application startup configuration. + /// + public class Startup + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + /// + /// + /// + /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + /// + /// + /// + /// + /// + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseHttpsRedirection(); + app.UseRouting(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + + /// + /// + /// + /// This method gets called by the runtime. Use this method to add services to the container. + /// + /// + /// + public void ConfigureServices(IServiceCollection services) => _ = services.AddControllers(); + + /// + /// + public IConfiguration Configuration { get; } + } +} + +#pragma warning restore CA1822 // Mark members as static \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/appsettings.Development.json b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/appsettings.Development.json new file mode 100644 index 00000000..2905c113 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/appsettings.Development.json @@ -0,0 +1,13 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/appsettings.json b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/appsettings.json new file mode 100644 index 00000000..10084b9a --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/appsettings.json @@ -0,0 +1,18 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +{ + "AllowedHosts": "*", + "ConnectionStrings": { + "AccessControl": "Server=(LocalDB)\\MSSQLLocalDB;Database=AccessControl;Trusted_Connection=True;", + "ExampleServiceBus": "amqp://guest:guest@localhost:5672" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs index d76d7263..4e4fd0e9 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs @@ -55,32 +55,9 @@ protected override void AddListeners(IMessageListeningProfile listeningProfile, { try { - // Add standard listeners. - listeningProfile.AddExceptionRaisedEventListener(); - listeningProfile.AddHeartbeatListener(); - listeningProfile.AddPingRequestListener(); - - // Add command listeners. - listeningProfile.AddCommandListener(); - listeningProfile.AddCommandListener(); - listeningProfile.AddCommandListener(); - listeningProfile.AddCommandListener(); - listeningProfile.AddCommandListener(); - listeningProfile.AddCommandListener(); - listeningProfile.AddCommandListener(); - listeningProfile.AddCommandListener(); - listeningProfile.AddCommandListener(); - - // Add event listeners. - listeningProfile.AddEventListener(); - listeningProfile.AddEventListener(); - listeningProfile.AddEventListener(); - listeningProfile.AddEventListener(); - listeningProfile.AddEventListener(); - listeningProfile.AddEventListener(); - listeningProfile.AddEventListener(); - listeningProfile.AddEventListener(); - listeningProfile.AddEventListener(); + AddStandardListeners(listeningProfile, applicationConfiguration, commandLineArguments); + AddCommandListeners(listeningProfile, applicationConfiguration, commandLineArguments); + AddEventListeners(listeningProfile, applicationConfiguration, commandLineArguments); } finally { @@ -130,10 +107,9 @@ protected override void OnExecutionStarting(IDependencyScope dependencyScope, IC { try { - var mediator = dependencyScope.Resolve(); - TestServiceBusConnectivity(mediator); + TestServiceBusConnectivity(dependencyScope); MigrateDatabaseSchema(dependencyScope); - HydrateNamedEntities(mediator); + HydrateNamedDomainEntities(dependencyScope); } finally { @@ -141,36 +117,138 @@ protected override void OnExecutionStarting(IDependencyScope dependencyScope, IC } } + /// + /// Adds command message listeners to the service. + /// + /// + /// An object that is used to add listeners. + /// + /// + /// Configuration information for the service application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + [DebuggerHidden] + private static void AddCommandListeners(IMessageListeningProfile listeningProfile, IConfiguration applicationConfiguration, String[] commandLineArguments) + { + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + } + + /// + /// Adds event message listeners to the service. + /// + /// + /// An object that is used to add listeners. + /// + /// + /// Configuration information for the service application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + [DebuggerHidden] + private static void AddEventListeners(IMessageListeningProfile listeningProfile, IConfiguration applicationConfiguration, String[] commandLineArguments) + { + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + } + + /// + /// Adds standard message listeners to the service. + /// + /// + /// An object that is used to add listeners. + /// + /// + /// Configuration information for the service application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + [DebuggerHidden] + private static void AddStandardListeners(IMessageListeningProfile listeningProfile, IConfiguration applicationConfiguration, String[] commandLineArguments) => listeningProfile.AddHeartbeatListener(); + /// /// Creates or updates all named domain models. /// + /// + /// A scope that is used to resolve service dependencies. + /// + [DebuggerHidden] + private static void HydrateNamedDomainEntities(IDependencyScope dependencyScope) + { + var mediator = dependencyScope.Resolve(); + HydrateNamedUsers(mediator); + HydrateNamedUserRoles(mediator); + HydrateNamedUserRoleAssignments(mediator); + Console.WriteLine("Database entities created/updated."); + } + + /// + /// Creates or updates all named instances. + /// /// /// A mediator that is used to issue commands. /// [DebuggerHidden] - private static void HydrateNamedEntities(ICommandMediator mediator) + private static void HydrateNamedUserRoleAssignments(ICommandMediator mediator) { - foreach (var domainModel in Models.User.DomainModel.Named.All()) + foreach (var domainModel in Models.UserRoleAssignment.DomainModel.Named.All()) { - mediator.Process(new Messages.Command.ModelState.User.CreateDomainModelCommandMessage(new Commands.ModelState.User.CreateDomainModelCommand(domainModel))); + mediator.Process(new Messages.Command.ModelState.UserRoleAssignment.CreateDomainModelCommandMessage(new Commands.ModelState.UserRoleAssignment.CreateDomainModelCommand(domainModel))); } - Thread.Sleep(610); + Pause(); + } + /// + /// Creates or updates all named instances. + /// + /// + /// A mediator that is used to issue commands. + /// + [DebuggerHidden] + private static void HydrateNamedUserRoles(ICommandMediator mediator) + { foreach (var domainModel in Models.UserRole.DomainModel.Named.All()) { mediator.Process(new Messages.Command.ModelState.UserRole.CreateDomainModelCommandMessage(new Commands.ModelState.UserRole.CreateDomainModelCommand(domainModel))); } - Thread.Sleep(610); + Pause(); + } - foreach (var domainModel in Models.UserRoleAssignment.DomainModel.Named.All()) + /// + /// Creates or updates all named instances. + /// + /// + /// A mediator that is used to issue commands. + /// + [DebuggerHidden] + private static void HydrateNamedUsers(ICommandMediator mediator) + { + foreach (var domainModel in Models.User.DomainModel.Named.All()) { - mediator.Process(new Messages.Command.ModelState.UserRoleAssignment.CreateDomainModelCommandMessage(new Commands.ModelState.UserRoleAssignment.CreateDomainModelCommand(domainModel))); + mediator.Process(new Messages.Command.ModelState.User.CreateDomainModelCommandMessage(new Commands.ModelState.User.CreateDomainModelCommand(domainModel))); } - Thread.Sleep(610); - Console.WriteLine("Database entities created/updated."); + Pause(); } /// @@ -184,21 +262,31 @@ private static void MigrateDatabaseSchema(IDependencyScope dependencyScope) { var databaseContext = dependencyScope.Resolve(); databaseContext.Database.EnsureCreated(); - Thread.Sleep(610); + Pause(); Console.WriteLine("Database schema created/updated."); } + /// + /// Blocks the current thread for a short period to ensure synchronous execution of startup events. + /// + [DebuggerHidden] + private static void Pause() => Thread.Sleep(PauseDurationInMilliseconds); + /// /// Raises an exception if a service bus connection is unavailable. /// - /// - /// A mediator that is used to issue commands. + /// + /// A scope that is used to resolve service dependencies. /// + /// + /// The service was unable to verify service bus connectivity. + /// [DebuggerHidden] - private static void TestServiceBusConnectivity(ICommandMediator mediator) + private static void TestServiceBusConnectivity(IDependencyScope dependencyScope) { try { + var mediator = dependencyScope.Resolve(); var pingRequestCorrelationIdentifier = Guid.NewGuid(); var pingResponseMessage = mediator.Process(new PingRequestMessage(pingRequestCorrelationIdentifier)); @@ -226,5 +314,11 @@ private static void TestServiceBusConnectivity(ICommandMediator mediator) /// the start of service execution. /// protected override sealed String ProductName => "Solid Instruments"; + + /// + /// Represents the number of milliseconds to wait when invoking . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const Int32 PauseDurationInMilliseconds = 1597; } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/Program.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/Program.cs index baf03cb0..70cf9a02 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/Program.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/Program.cs @@ -28,6 +28,6 @@ public static void Main(String[] args) /// Represents the name of the service that is hosted by this application. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private const String ServiceName = "AccessControl Service"; + private static readonly String ServiceName = $"{nameof(AccessControl)} Service"; } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/README.md b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/README.md index 0cab6f2a..a16216b9 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/README.md +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/README.md @@ -11,7 +11,7 @@ This document describes the purpose of the [`RapidField.SolidInstruments.Example ## Purpose -This project demonstrates an access control domain service utilizing the **Solid Instruments** [data access](../../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../../src/RapidField.SolidInstruments.Messaging/README.md) constructs. +This project demonstrates an AccessControl domain service utilizing the **Solid Instruments** [data access](../../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../../src/RapidField.SolidInstruments.Messaging/README.md) constructs. ## License diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/RapidField.SolidInstruments.Example.Domain.AccessControl.Service.csproj b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/RapidField.SolidInstruments.Example.Domain.AccessControl.Service.csproj index a0a333fd..6ec75bf1 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/RapidField.SolidInstruments.Example.Domain.AccessControl.Service.csproj +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/RapidField.SolidInstruments.Example.Domain.AccessControl.Service.csproj @@ -8,7 +8,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in RapidField Copyright (c) RapidField LLC. All rights reserved. Solid Instruments - This project demonstrates an access control service application utilizing Solid Instruments constructs. + This project demonstrates an AccessControl domain service application utilizing Solid Instruments constructs. $(BuildVersion) Exe netcoreapp3.1 @@ -34,7 +34,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in
- + diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlerModule.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlerModule.cs index 457a82c4..66033f63 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlerModule.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlerModule.cs @@ -9,7 +9,7 @@ namespace RapidField.SolidInstruments.Example.Domain.AccessControl { /// - /// Encapsulates container configuration for access control domain command handlers. + /// Encapsulates container configuration for AccessControl domain command handlers. /// public sealed class CommandHandlerModule : DotNetNativeCommandHandlerModule { diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlerModule.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlerModule.cs index ea51f7c6..8d04bbed 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlerModule.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlerModule.cs @@ -9,7 +9,7 @@ namespace RapidField.SolidInstruments.Example.Domain.AccessControl { /// - /// Encapsulates container configuration for access control domain event handlers. + /// Encapsulates container configuration for AccessControl domain event handlers. /// public sealed class EventHandlerModule : DotNetNativeEventHandlerModule { diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelCreatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelCreatedEventHandler.cs index 27f11f53..3084e6e6 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelCreatedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelCreatedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelCreatedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelDeletedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelDeletedEventHandler.cs index ba74bbe1..dd50f1bf 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelDeletedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelDeletedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelDeletedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelUpdatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelUpdatedEventHandler.cs index 34875c73..4ced67f7 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelUpdatedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/User/DomainModelUpdatedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelUpdatedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelCreatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelCreatedEventHandler.cs index b3f94576..a8c0986f 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelCreatedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelCreatedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelCreatedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelDeletedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelDeletedEventHandler.cs index c657a3eb..0de0ea1b 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelDeletedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelDeletedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelDeletedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelUpdatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelUpdatedEventHandler.cs index 85d061a0..887436d3 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelUpdatedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRole/DomainModelUpdatedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelUpdatedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.cs index be30b0e9..16d0c2b9 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelCreatedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.cs index c26e6aad..d0b76947 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelDeletedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.cs index 4616d5f4..3ee32cec 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.cs @@ -59,6 +59,6 @@ public DomainModelUpdatedEventHandler(ICommandMediator mediator) /// /// A token that represents and manages contextual thread safety. /// - protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/README.md b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/README.md index 1487d585..b2e90acb 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/README.md +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/README.md @@ -11,7 +11,7 @@ This document describes the purpose of the [`RapidField.SolidInstruments.Example ## Purpose -This project demonstrates access control domain logic utilizing the **Solid Instruments** [data access](../../src/RapidField.SolidInstruments.DataAccess/README.md) constructs. +This project demonstrates AccessControl domain logic utilizing the **Solid Instruments** [data access](../../src/RapidField.SolidInstruments.DataAccess/README.md) constructs. ## License diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/RapidField.SolidInstruments.Example.Domain.AccessControl.csproj b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/RapidField.SolidInstruments.Example.Domain.AccessControl.csproj index 81c381fb..6221e904 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/RapidField.SolidInstruments.Example.Domain.AccessControl.csproj +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/RapidField.SolidInstruments.Example.Domain.AccessControl.csproj @@ -8,7 +8,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in RapidField Copyright (c) RapidField LLC. All rights reserved. Solid Instruments - This project demonstrates access control domain logic utilizing the Solid Instruments data access and messaging constructs. + This project demonstrates AccessControl domain logic utilizing the Solid Instruments data access and messaging constructs. $(BuildVersion) netstandard2.1 latest diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationDependencyPackage.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationDependencyPackage.cs new file mode 100644 index 00000000..2cdeeecd --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationDependencyPackage.cs @@ -0,0 +1,44 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using RapidField.SolidInstruments.InversionOfControl; +using RapidField.SolidInstruments.InversionOfControl.DotNetNative; +using System.Collections.Generic; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.Service +{ + /// + /// Encapsulates container configuration for the application. + /// + public class ApplicationDependencyPackage : DotNetNativeDependencyPackage + { + /// + /// Initializes a new instance of the class. + /// + public ApplicationDependencyPackage() + : base() + { + return; + } + + /// + /// Creates a new collection of dependency modules for the package. + /// + /// + /// Configuration information for the application. + /// + /// + /// The package's dependency modules. + /// + protected override IEnumerable> CreateModules(IConfiguration applicationConfiguration) => new IDependencyModule[] + { + new DatabaseContextDependencyModule(applicationConfiguration), + new ServiceBusDependencyModule(applicationConfiguration), + new EventHandlerModule(applicationConfiguration), + new MessageHandlerModule(applicationConfiguration) + }; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationServiceExecutor.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationServiceExecutor.cs new file mode 100644 index 00000000..9b1e152f --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationServiceExecutor.cs @@ -0,0 +1,251 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.Configuration; +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core; +using RapidField.SolidInstruments.InversionOfControl; +using RapidField.SolidInstruments.Messaging.DotNetNative.Service; +using RapidField.SolidInstruments.Messaging.Service; +using RapidField.SolidInstruments.Service; +using System; +using System.Diagnostics; +using System.IO; +using System.Threading; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.Service +{ + /// + /// Prepares for and performs execution of the Identity domain service. + /// + public sealed class ApplicationServiceExecutor : DotNetNativeMessagingServiceExecutor + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The name of the service. + /// + /// + /// is empty. + /// + /// + /// is . + /// + public ApplicationServiceExecutor(String serviceName) + : base(serviceName) + { + return; + } + + /// + /// Adds message listeners to the service. + /// + /// + /// An object that is used to add listeners. + /// + /// + /// Configuration information for the service application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + protected override void AddListeners(IMessageListeningProfile listeningProfile, IConfiguration applicationConfiguration, String[] commandLineArguments) + { + try + { + AddStandardListeners(listeningProfile, applicationConfiguration, commandLineArguments); + AddCommandListeners(listeningProfile, applicationConfiguration, commandLineArguments); + AddEventListeners(listeningProfile, applicationConfiguration, commandLineArguments); + } + finally + { + base.AddListeners(listeningProfile, applicationConfiguration, commandLineArguments); + } + } + + /// + /// Builds the application configuration for the service. + /// + /// + /// An object that is used to build the configuration. + /// + protected override void BuildConfiguration(IConfigurationBuilder configurationBuilder) + { + try + { + configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json"); + } + finally + { + base.BuildConfiguration(configurationBuilder); + } + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Performs startup operations for the service. + /// + /// + /// A scope that is used to resolve service dependencies. + /// + /// + /// Configuration information for the service application. + /// + /// + /// An object that provides control over execution lifetime. + /// + protected override void OnExecutionStarting(IDependencyScope dependencyScope, IConfiguration applicationConfiguration, IServiceExecutionLifetime executionLifetime) + { + try + { + TestServiceBusConnectivity(dependencyScope); + MigrateDatabaseSchema(dependencyScope); + } + finally + { + base.OnExecutionStarting(dependencyScope, applicationConfiguration, executionLifetime); + } + } + + /// + /// Adds command message listeners to the service. + /// + /// + /// An object that is used to add listeners. + /// + /// + /// Configuration information for the service application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + [DebuggerHidden] + private static void AddCommandListeners(IMessageListeningProfile listeningProfile, IConfiguration applicationConfiguration, String[] commandLineArguments) + { + return; + } + + /// + /// Adds event message listeners to the service. + /// + /// + /// An object that is used to add listeners. + /// + /// + /// Configuration information for the service application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + [DebuggerHidden] + private static void AddEventListeners(IMessageListeningProfile listeningProfile, IConfiguration applicationConfiguration, String[] commandLineArguments) + { + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + } + + /// + /// Adds standard message listeners to the service. + /// + /// + /// An object that is used to add listeners. + /// + /// + /// Configuration information for the service application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + [DebuggerHidden] + private static void AddStandardListeners(IMessageListeningProfile listeningProfile, IConfiguration applicationConfiguration, String[] commandLineArguments) + { + return; + } + + /// + /// Creates or updates the database schema. + /// + /// + /// A scope that is used to resolve service dependencies. + /// + [DebuggerHidden] + private static void MigrateDatabaseSchema(IDependencyScope dependencyScope) + { + var databaseContext = dependencyScope.Resolve(); + databaseContext.Database.EnsureCreated(); + Pause(); + Console.WriteLine("Database schema created/updated."); + } + + /// + /// Blocks the current thread for a short period to ensure synchronous execution of startup events. + /// + [DebuggerHidden] + private static void Pause() => Thread.Sleep(PauseDurationInMilliseconds); + + /// + /// Raises an exception if a service bus connection is unavailable. + /// + /// + /// A scope that is used to resolve service dependencies. + /// + /// + /// The service was unable to verify service bus connectivity. + /// + [DebuggerHidden] + private static void TestServiceBusConnectivity(IDependencyScope dependencyScope) + { + try + { + var mediator = dependencyScope.Resolve(); + var pingRequestCorrelationIdentifier = Guid.NewGuid(); + var pingResponseMessage = mediator.Process(new PingRequestMessage(pingRequestCorrelationIdentifier)); + + if (pingResponseMessage is null || pingResponseMessage.CorrelationIdentifier != pingRequestCorrelationIdentifier) + { + throw new ServiceExectuionException("The service was unable to verify service bus connectivity."); + } + } + catch (CommandHandlingException exception) + { + throw new ServiceExectuionException("The service was unable to verify service bus connectivity. See inner exception.", exception); + } + + Console.WriteLine("Service bus connectivity verified."); + } + + /// + /// When overridden by a derived class, gets a copyright notice which is written to the console at the start of service + /// execution. + /// + protected override sealed String CopyrightNotice => "Copyright (c) RapidField LLC. All rights reserved."; + + /// + /// When overridden by a derived class, gets a product name associated with the service which is written to the console at + /// the start of service execution. + /// + protected override sealed String ProductName => "Solid Instruments"; + + /// + /// Represents the number of milliseconds to wait when invoking . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const Int32 PauseDurationInMilliseconds = 1597; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/Program.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/Program.cs new file mode 100644 index 00000000..a11acdf5 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/Program.cs @@ -0,0 +1,33 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.Diagnostics; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.Service +{ + /// + /// Houses the entry point for the application. + /// + public static class Program + { + /// + /// Begins execution of the application. + /// + /// + /// Command line arguments that are provided at runtime. + /// + public static void Main(String[] args) + { + using var serviceExecutor = new ApplicationServiceExecutor(ServiceName); + serviceExecutor.Execute(args); + } + + /// + /// Represents the name of the service that is hosted by this application. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private static readonly String ServiceName = $"{nameof(Identity)} Service"; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/README.md b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/README.md new file mode 100644 index 00000000..ab99d755 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/README.md @@ -0,0 +1,30 @@ + + +[![Solid Instruments](../../SolidInstruments.Logo.Color.Transparent.500w.png)](../../README.md) +- - - + +# RapidField.SolidInstruments.Example.Domain.Identity.Service + +This document describes the purpose of the [`RapidField.SolidInstruments.Example.Domain.Identity.Service`]() project. + +## Purpose + +This project demonstrates an Identity domain service utilizing the **Solid Instruments** [data access](../../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../../src/RapidField.SolidInstruments.Messaging/README.md) constructs. + +## License + +[![License](https://img.shields.io/github/license/rapidfield/solid-instruments?style=flat&color=lightseagreen&label=license&logo=open-access&logoColor=lightgrey)](../../LICENSE.txt) + +**Solid Instruments** is [MIT-licensed](https://en.wikipedia.org/wiki/MIT_License). Review the [license terms](../../LICENSE.txt) for more information. + +
+ +- - - + +
+ +[![RapidField](../../RapidField.Logo.Color.Black.Transparent.200w.png)](https://www.rapidfield.com) + +###### Copyright (c) RapidField LLC. All rights reserved. "RapidField" and "Solid Instruments" are trademarks of RapidField LLC. \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/RapidField.SolidInstruments.Example.Domain.Identity.Service.csproj b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/RapidField.SolidInstruments.Example.Domain.Identity.Service.csproj new file mode 100644 index 00000000..7097569d --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/RapidField.SolidInstruments.Example.Domain.Identity.Service.csproj @@ -0,0 +1,42 @@ + + + + + Solid Instruments contributors + RapidField + Copyright (c) RapidField LLC. All rights reserved. + Solid Instruments + This project demonstrates an Identity domain service application utilizing Solid Instruments constructs. + $(BuildVersion) + Exe + netcoreapp3.1 + latest + + + bin\Debug\netcoreapp3.1\RapidField.SolidInstruments.Example.Domain.Identity.Service.xml + true + + + + bin\Release\netcoreapp3.1\RapidField.SolidInstruments.Example.Domain.Identity.Service.xml + true + + + + + + + + + PreserveNewest + + + + + + + + + \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/appsettings.json b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/appsettings.json new file mode 100644 index 00000000..331ee9f6 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/appsettings.json @@ -0,0 +1,16 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +{ + "ConnectionStrings": { + "ExampleServiceBus": "amqp://guest:guest@localhost:5672", + "Identity": "Server=(LocalDB)\\MSSQLLocalDB;Database=Identity;Trusted_Connection=True;" + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Warning" + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/DatabaseContext.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/DatabaseContext.cs new file mode 100644 index 00000000..da6ccc9a --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/DatabaseContext.cs @@ -0,0 +1,495 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.Azure.Cosmos.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.Extensions.Configuration; +using RapidField.SolidInstruments.Core; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Extensions; +using RapidField.SolidInstruments.DataAccess.EntityFramework; +using System; +using System.Configuration; +using System.Data.Common; +using System.Diagnostics; + +namespace RapidField.SolidInstruments.Example.Domain.Identity +{ + /// + /// Represents a connection to the Identity database. + /// + public sealed class DatabaseContext : IdentityDbContext + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + /// + /// The constructor was unable to determine the appropriate connection type by evaluating the connection string. + /// + public DatabaseContext(IConfiguration applicationConfiguration) + : this(applicationConfiguration, DefaultDatabaseType, DefaultDatabaseName) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// The database type of the backing database, or to determine the connection + /// type dynamically based on the format of the connection string. + /// + /// + /// The name of the backing database, which matches the associated connection string key in + /// . The default value is equal to the context's type name with "Context" + /// trimmed from the end, if found. + /// + /// + /// is empty. + /// + /// + /// is . + /// + /// + /// is equal to and the constructor was + /// unable to determine the appropriate connection type by evaluating the connection string. + /// + [DebuggerHidden] + private DatabaseContext(IConfiguration applicationConfiguration, ContextDatabaseType databaseType, String databaseName) + : this(applicationConfiguration, databaseType, databaseName ?? UseConventionalDatabaseNameIndicator, DefaultTrackingBehavior) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// The database type of the backing database, or to determine the connection + /// type dynamically based on the format of the connection string. + /// + /// + /// The name of the backing database, which matches the associated connection string key in + /// . The default value is equal to the context's type name with "Context" + /// trimmed from the end, if found. + /// + /// + /// The query result tracking behavior for the context. The default value is . + /// + /// + /// is empty. + /// + /// + /// is . + /// + /// + /// is equal to and the constructor was + /// unable to determine the appropriate connection type by evaluating the connection string. + /// + [DebuggerHidden] + private DatabaseContext(IConfiguration applicationConfiguration, ContextDatabaseType databaseType, String databaseName, QueryTrackingBehavior trackingBehavior) + : base() + { + ApplicationConfiguration = applicationConfiguration.RejectIf().IsNull(nameof(applicationConfiguration)).TargetArgument; + DatabaseNameReference = (databaseName ?? UseConventionalDatabaseNameIndicator).RejectIf().IsNullOrEmpty(nameof(databaseName)); + DatabaseType = databaseType == ContextDatabaseType.Unspecified ? DetermineDatabaseType(ConnectionString) : databaseType; + TrackingBehavior = trackingBehavior; + + if (DatabaseType == ContextDatabaseType.Unspecified) + { + throw new ConfigurationErrorsException($"The identity context was unable to determine the database connection type using the connection string."); + } + } + + /// + /// Configures the database to be used for this context. + /// + /// + /// A builder used to create or modify options for this context. + /// + protected sealed override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + try + { + optionsBuilder = DatabaseType switch + { + ContextDatabaseType.Cosmos => UseCosmos(optionsBuilder), + ContextDatabaseType.InMemory => UseInMemory(optionsBuilder), + ContextDatabaseType.SqlServer => UseSqlServer(optionsBuilder), + _ => throw new UnsupportedSpecificationException($"The specified database type, {DatabaseType}, is not supported.") + }; + + optionsBuilder.UseQueryTrackingBehavior(TrackingBehavior); + } + finally + { + base.OnConfiguring(optionsBuilder); + } + } + + /// + /// Configures the model that is discovered by convention from entity types exposed via + /// properties on the derived context. + /// + /// + /// A builder that is used to configure the model. + /// + protected sealed override void OnModelCreating(ModelBuilder modelBuilder) + { + try + { + OnModelCreating(ApplicationConfiguration, modelBuilder); + } + finally + { + base.OnModelCreating(modelBuilder); + } + } + + /// + /// Determines the connection type for the specified database connection string. + /// + /// + /// The connection string to evaluate. + /// + /// + /// The resulting database connection type, or if the connection type cannot + /// be determined. + /// + [DebuggerHidden] + private static ContextDatabaseType DetermineDatabaseType(String connectionString) + { + var processedConnectionString = connectionString?.Trim().ToLower(); + + if (processedConnectionString.IsNullOrEmpty()) + { + return ContextDatabaseType.Unspecified; + } + else if (processedConnectionString == InMemoryConnectionStringValue.ToLower()) + { + return ContextDatabaseType.InMemory; + } + else if (processedConnectionString.Contains(ConnectionStringKeywordForAccountEndpoint.ToLower()) && processedConnectionString.Contains(ConnectionStringKeywordForAccountKey.ToLower())) + { + return ContextDatabaseType.Cosmos; + } + else if (processedConnectionString.Contains(ConnectionStringKeywordForDatabase.ToLower()) && processedConnectionString.Contains(ConnectionStringKeywordForServer.ToLower())) + { + return ContextDatabaseType.SqlServer; + } + + return ContextDatabaseType.Unspecified; + } + + /// + /// Returns the conventional, default name of the backing database for the specified type. + /// + /// + /// The type of the derived class. + /// + /// + /// is . + /// + [DebuggerHidden] + private static String GetConventionalDatabaseName(Type contextType) + { + var contextTypeName = contextType.RejectIf().IsNull(nameof(contextType)).TargetArgument.Name; + + if (contextTypeName == ContextPostfixStringElement) + { + return contextTypeName; + } + else if (contextTypeName.EndsWith(ContextPostfixStringElement)) + { + return contextTypeName.Substring(0, contextTypeName.Length - ContextPostfixStringElement.Length); + } + + return contextTypeName; + } + + /// + /// Configures the Cosmos DB database to be used for this context. + /// + /// + /// Configuration information for the application. + /// + /// + /// A builder that is used to create or modify options for this context. + /// + [DebuggerHidden] + private static void OnConfiguringCosmos(IConfiguration applicationConfiguration, CosmosDbContextOptionsBuilder optionsBuilder) + { + return; + } + + /// + /// Configures the in-memory database to be used for this context. + /// + /// + /// Configuration information for the application. + /// + /// + /// A builder that is used to create or modify options for this context. + /// + [DebuggerHidden] + private static void OnConfiguringInMemory(IConfiguration applicationConfiguration, InMemoryDbContextOptionsBuilder optionsBuilder) + { + return; + } + + /// + /// Configures the SQL Server database to be used for this context. + /// + /// + /// Configuration information for the application. + /// + /// + /// A builder that is used to create or modify options for this context. + /// + [DebuggerHidden] + private static void OnConfiguringSqlServer(IConfiguration applicationConfiguration, SqlServerDbContextOptionsBuilder optionsBuilder) + { + return; + } + + /// + /// Returns the conventional, default name of the backing database for the current . + /// + [DebuggerHidden] + private String GetConventionalDatabaseName() => GetConventionalDatabaseName(GetType()); + + /// + /// Configures the Cosmos DB database to be used for this context. + /// + /// + /// A builder used to create or modify options for this context. + /// + [DebuggerHidden] + private void OnConfiguringCosmos(CosmosDbContextOptionsBuilder optionsBuilder) => OnConfiguringCosmos(ApplicationConfiguration, optionsBuilder); + + /// + /// Configures the in-memory database to be used for this context. + /// + /// + /// A builder used to create or modify options for this context. + /// + [DebuggerHidden] + private void OnConfiguringInMemory(InMemoryDbContextOptionsBuilder optionsBuilder) => OnConfiguringInMemory(ApplicationConfiguration, optionsBuilder); + + /// + /// Configures the SQL Server database to be used for this context. + /// + /// + /// A builder used to create or modify options for this context. + /// + [DebuggerHidden] + private void OnConfiguringSqlServer(SqlServerDbContextOptionsBuilder optionsBuilder) => OnConfiguringSqlServer(ApplicationConfiguration, optionsBuilder); + + /// + /// Configures the model that is discovered by convention from entity types exposed via + /// properties on the derived context. + /// + /// + /// Configuration information for the application. + /// + /// + /// A builder that is used to configure the model. + /// + [DebuggerHidden] + private void OnModelCreating(IConfiguration applicationConfiguration, ModelBuilder modelBuilder) + { + return; + } + + /// + /// Configures the specified options builder for a Cosmos DB database connection. + /// + /// + /// A builder used to create or modify options for this context. + /// + /// + /// The connection string is invalid. + /// + [DebuggerHidden] + private DbContextOptionsBuilder UseCosmos(DbContextOptionsBuilder optionsBuilder) + { + var connectionStringBuilder = new DbConnectionStringBuilder(); + var accountEndpoint = (String)null; + var accountKey = (String)null; + + try + { + connectionStringBuilder.ConnectionString = ConnectionString; + + if (connectionStringBuilder.TryGetValue(ConnectionStringKeywordForAccountEndpoint, out var configuredAccountEndpoint)) + { + accountEndpoint = configuredAccountEndpoint?.ToString().Trim(); + } + + if (accountEndpoint.IsNullOrEmpty()) + { + throw new ConfigurationErrorsException($"A value for the keyword \"{ConnectionStringKeywordForAccountEndpoint}\" was not found within the connection string value for \"{DatabaseName}\"."); + } + + if (connectionStringBuilder.TryGetValue(ConnectionStringKeywordForAccountKey, out var configuredAccountKey)) + { + accountKey = configuredAccountKey?.ToString().Trim(); + } + + if (accountKey.IsNullOrEmpty()) + { + throw new ConfigurationErrorsException($"A value for the keyword \"{ConnectionStringKeywordForAccountKey}\" was not found within the connection string value for \"{DatabaseName}\"."); + } + } + catch (Exception exception) + { + throw new ConfigurationErrorsException($"The connection string value for \"{DatabaseName}\" is invalid. See inner exception.", exception); + }; + + return optionsBuilder.UseCosmos(accountEndpoint, accountKey, DatabaseName, OnConfiguringCosmos); + } + + /// + /// Configures the specified options builder for an in-memory database connection. + /// + /// + /// A builder used to create or modify options for this context. + /// + [DebuggerHidden] + private DbContextOptionsBuilder UseInMemory(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseInMemoryDatabase(DatabaseName, OnConfiguringInMemory).ConfigureWarnings((warningsBuilder) => { warningsBuilder.Ignore(InMemoryEventId.TransactionIgnoredWarning); }); + + /// + /// Configures the specified options builder for a SQL Server database connection. + /// + /// + /// A builder used to create or modify options for this context. + /// + [DebuggerHidden] + private DbContextOptionsBuilder UseSqlServer(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(ConnectionString, OnConfiguringSqlServer); + + /// + /// Gets the connection string for the associated database from . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private String ConnectionString => ApplicationConfiguration.GetConnectionString(DatabaseName); + + /// + /// Gets the name of the backing database, which matches the associated connection string key in + /// . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private String DatabaseName + { + get + { + if (DatabaseNameReference == UseConventionalDatabaseNameIndicator) + { + DatabaseNameReference = GetConventionalDatabaseName(); + } + + return DatabaseNameReference; + } + } + + /// + /// Represents the connection string keyword "AccountEndpoint". + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String ConnectionStringKeywordForAccountEndpoint = "AccountEndpoint"; + + /// + /// Represents the connection string keyword "AccountKey". + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String ConnectionStringKeywordForAccountKey = "AccountKey"; + + /// + /// Represents the connection string keyword "Database". + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String ConnectionStringKeywordForDatabase = "Database"; + + /// + /// Represents the connection string keyword "Server". + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String ConnectionStringKeywordForServer = "Server"; + + /// + /// Represents the word "Context" as a string. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String ContextPostfixStringElement = "Context"; + + /// + /// Represents the database name that is used when creating and connecting to the data source. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String DefaultDatabaseName = "Identity"; + + /// + /// Represents the default database type for backing databases. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const ContextDatabaseType DefaultDatabaseType = ContextDatabaseType.Unspecified; + + /// + /// Represents the default query result tracking behavior for contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const QueryTrackingBehavior DefaultTrackingBehavior = QueryTrackingBehavior.TrackAll; + + /// + /// Represents a connection string value that instructs the context to use an in-memory database connection. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String InMemoryConnectionStringValue = "InMemory"; + + /// + /// Represents a value that indicates that the conventional, default database name should be used + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String UseConventionalDatabaseNameIndicator = "__UseConventionalDatabaseName__"; + + /// + /// Represents configuration information for the application. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly IConfiguration ApplicationConfiguration; + + /// + /// Represents the database type of the backing database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly ContextDatabaseType DatabaseType; + + /// + /// Represents the query result tracking behavior for the context. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly QueryTrackingBehavior TrackingBehavior; + + /// + /// Represents the name of the backing database, which matches the associated connection string key in + /// . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private String DatabaseNameReference; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/DatabaseContextDependencyModule.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/DatabaseContextDependencyModule.cs new file mode 100644 index 00000000..0a2bfdda --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/DatabaseContextDependencyModule.cs @@ -0,0 +1,48 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using RapidField.SolidInstruments.InversionOfControl.DotNetNative; +using RapidField.SolidInstruments.InversionOfControl.DotNetNative.Extensions; +using System; + +namespace RapidField.SolidInstruments.Example.Domain.Identity +{ + /// + /// Encapsulates container configuration for the Identity database connection and related data access dependencies. + /// + public sealed class DatabaseContextDependencyModule : DotNetNativeDependencyModule + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + public DatabaseContextDependencyModule(IConfiguration applicationConfiguration) + : base(applicationConfiguration) + { + return; + } + + /// + /// Configures the module. + /// + /// + /// An object that configures containers. + /// + /// + /// Configuration information for the application. + /// + protected override void Configure(ServiceCollection configurator, IConfiguration applicationConfiguration) + { + configurator.AddApplicationConfiguration(applicationConfiguration); + configurator.AddDbContext(); + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlerModule.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlerModule.cs new file mode 100644 index 00000000..11953b2b --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlerModule.cs @@ -0,0 +1,31 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.Configuration; +using RapidField.SolidInstruments.EventAuthoring.DotNetNative; +using System; + +namespace RapidField.SolidInstruments.Example.Domain.Identity +{ + /// + /// Encapsulates container configuration for Identity domain event handlers. + /// + public sealed class EventHandlerModule : DotNetNativeEventHandlerModule + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + public EventHandlerModule(IConfiguration applicationConfiguration) + : base(applicationConfiguration) + { + return; + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelCreatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelCreatedEventHandler.cs new file mode 100644 index 00000000..8bb86583 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelCreatedEventHandler.cs @@ -0,0 +1,95 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Identity; +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.User.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.User.DomainModelCreatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.User +{ + /// + /// Processes a single . + /// + public sealed class DomainModelCreatedEventHandler : DomainModelCreatedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelCreatedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityUser = new IdentityUser() + { + AccessFailedCount = 0, + Email = model.EmailAddress, + EmailConfirmed = false, + Id = model.Identifier.ToString(), + PasswordHash = model.PasswordHash, + TwoFactorEnabled = false, + UserName = model.Name + }; + + if (DatabaseContext.Users.Find(identityUser.Id) is null) + { + DatabaseContext.Users.Add(identityUser); + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelDeletedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelDeletedEventHandler.cs new file mode 100644 index 00000000..57137c10 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelDeletedEventHandler.cs @@ -0,0 +1,87 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.User.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.User.DomainModelDeletedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.User +{ + /// + /// Processes a single . + /// + public sealed class DomainModelDeletedEventHandler : DomainModelDeletedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelDeletedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityUser = DatabaseContext.Users.Find(model.Identifier.ToString()); + + if (identityUser is null) + { + return; + } + + DatabaseContext.Users.Remove(identityUser); + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelUpdatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelUpdatedEventHandler.cs new file mode 100644 index 00000000..e3abaf50 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/User/DomainModelUpdatedEventHandler.cs @@ -0,0 +1,104 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Identity; +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.User.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.User.DomainModelUpdatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.User +{ + /// + /// Processes a single . + /// + public sealed class DomainModelUpdatedEventHandler : DomainModelUpdatedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelUpdatedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityUser = DatabaseContext.Users.Find(model.Identifier.ToString()); + + if (identityUser is null) + { + identityUser = new IdentityUser() + { + AccessFailedCount = 0, + Email = model.EmailAddress, + EmailConfirmed = false, + Id = model.Identifier.ToString(), + PasswordHash = model.PasswordHash, + TwoFactorEnabled = false, + UserName = model.Name + }; + DatabaseContext.Users.Add(identityUser); + } + else + { + identityUser.Email = model.EmailAddress; + identityUser.PasswordHash = model.PasswordHash; + identityUser.UserName = model.Name; + DatabaseContext.Users.Update(identityUser); + } + + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelCreatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelCreatedEventHandler.cs new file mode 100644 index 00000000..957303c2 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelCreatedEventHandler.cs @@ -0,0 +1,90 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Identity; +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRole.DomainModelCreatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.UserRole +{ + /// + /// Processes a single . + /// + public sealed class DomainModelCreatedEventHandler : DomainModelCreatedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelCreatedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityRole = new IdentityRole() + { + Id = model.Identifier.ToString(), + Name = model.Name + }; + + if (DatabaseContext.Roles.Find(identityRole.Id) is null) + { + DatabaseContext.Roles.Add(identityRole); + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelDeletedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelDeletedEventHandler.cs new file mode 100644 index 00000000..e3d73597 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelDeletedEventHandler.cs @@ -0,0 +1,87 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRole.DomainModelDeletedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.UserRole +{ + /// + /// Processes a single . + /// + public sealed class DomainModelDeletedEventHandler : DomainModelDeletedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelDeletedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityRole = DatabaseContext.Roles.Find(model.Identifier.ToString()); + + if (identityRole is null) + { + return; + } + + DatabaseContext.Roles.Remove(identityRole); + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelUpdatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelUpdatedEventHandler.cs new file mode 100644 index 00000000..a0c94ba7 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRole/DomainModelUpdatedEventHandler.cs @@ -0,0 +1,97 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Identity; +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRole.DomainModelUpdatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.UserRole +{ + /// + /// Processes a single . + /// + public sealed class DomainModelUpdatedEventHandler : DomainModelUpdatedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelUpdatedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityRole = DatabaseContext.Roles.Find(model.Identifier.ToString()); + + if (identityRole is null) + { + identityRole = new IdentityRole() + { + Id = model.Identifier.ToString(), + Name = model.Name + }; + DatabaseContext.Roles.Add(identityRole); + } + else + { + identityRole.Name = model.Name; + DatabaseContext.Roles.Update(identityRole); + } + + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.cs new file mode 100644 index 00000000..5df69aac --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.cs @@ -0,0 +1,90 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Identity; +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelCreatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.UserRoleAssignment +{ + /// + /// Processes a single . + /// + public sealed class DomainModelCreatedEventHandler : DomainModelCreatedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelCreatedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityUserRole = new IdentityUserRole() + { + RoleId = model.UserRoleIdentifier.ToString(), + UserId = model.UserIdentifier.ToString() + }; + + if (DatabaseContext.UserRoles.Find(identityUserRole.UserId, identityUserRole.RoleId) is null) + { + DatabaseContext.UserRoles.Add(identityUserRole); + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.cs new file mode 100644 index 00000000..5fc0458e --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.cs @@ -0,0 +1,87 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelDeletedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.UserRoleAssignment +{ + /// + /// Processes a single . + /// + public sealed class DomainModelDeletedEventHandler : DomainModelDeletedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelDeletedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityUserRole = DatabaseContext.UserRoles.Find(model.UserIdentifier.ToString(), model.UserRoleIdentifier.ToString()); + + if (identityUserRole is null) + { + return; + } + + DatabaseContext.UserRoles.Remove(identityUserRole); + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.cs new file mode 100644 index 00000000..1e513fa8 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.cs @@ -0,0 +1,91 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Identity; +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelUpdatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Identity.EventHandlers.ModelState.UserRoleAssignment +{ + /// + /// Processes a single . + /// + public sealed class DomainModelUpdatedEventHandler : DomainModelUpdatedEventHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A connection to the Identity database. + /// + /// + /// is -or- is + /// . + /// + public DomainModelUpdatedEventHandler(ICommandMediator mediator, DatabaseContext databaseContext) + : base(mediator) + { + DatabaseContext = databaseContext.RejectIf().IsNull(nameof(databaseContext)); + } + + /// + /// Releases all resources consumed by the current . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) => base.Dispose(disposing); + + /// + /// Processes the specified domain model. + /// + /// + /// The model that was created. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier to assign to sub-commands. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + protected override void Process(DomainModel model, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var identityUserRole = DatabaseContext.UserRoles.Find(model.UserIdentifier.ToString(), model.UserRoleIdentifier.ToString()); + + if (identityUserRole is null) + { + identityUserRole = new IdentityUserRole() + { + RoleId = model.UserRoleIdentifier.ToString(), + UserId = model.UserIdentifier.ToString() + }; + DatabaseContext.UserRoles.Add(identityUserRole); + DatabaseContext.SaveChanges(); + Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model.Identifier}."); + } + } + + /// + /// Represents a connection to the Identity database. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DatabaseContext DatabaseContext; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/README.md b/example/RapidField.SolidInstruments.Example.Domain.Identity/README.md new file mode 100644 index 00000000..f9a6099d --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/README.md @@ -0,0 +1,30 @@ + + +[![Solid Instruments](../../SolidInstruments.Logo.Color.Transparent.500w.png)](../../README.md) +- - - + +# RapidField.SolidInstruments.Example.Domain.Identity + +This document describes the purpose of the [`RapidField.SolidInstruments.Example.Domain.Identity`]() project. + +## Purpose + +This project demonstrates Identity domain logic utilizing the **Solid Instruments** [data access](../../src/RapidField.SolidInstruments.DataAccess/README.md) constructs. + +## License + +[![License](https://img.shields.io/github/license/rapidfield/solid-instruments?style=flat&color=lightseagreen&label=license&logo=open-access&logoColor=lightgrey)](../../LICENSE.txt) + +**Solid Instruments** is [MIT-licensed](https://en.wikipedia.org/wiki/MIT_License). Review the [license terms](../../LICENSE.txt) for more information. + +
+ +- - - + +
+ +[![RapidField](../../RapidField.Logo.Color.Black.Transparent.200w.png)](https://www.rapidfield.com) + +###### Copyright (c) RapidField LLC. All rights reserved. "RapidField" and "Solid Instruments" are trademarks of RapidField LLC. \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.Identity/RapidField.SolidInstruments.Example.Domain.Identity.csproj b/example/RapidField.SolidInstruments.Example.Domain.Identity/RapidField.SolidInstruments.Example.Domain.Identity.csproj new file mode 100644 index 00000000..93803446 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity/RapidField.SolidInstruments.Example.Domain.Identity.csproj @@ -0,0 +1,38 @@ + + + + + Solid Instruments contributors + RapidField + Copyright (c) RapidField LLC. All rights reserved. + Solid Instruments + This project demonstrates Identity domain logic utilizing the Solid Instruments data access and messaging constructs. + $(BuildVersion) + netstandard2.1 + latest + + + bin\Debug\netstandard2.1\RapidField.SolidInstruments.Example.Domain.Identity.xml + true + + + + bin\Release\netstandard2.1\RapidField.SolidInstruments.Example.Domain.Identity.xml + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.Named.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.Named.cs index cbc96fac..7808a817 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.Named.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.Named.cs @@ -74,7 +74,7 @@ private static String GetPasswordHash(String plaintextPassword) public static DomainModel StevenCallahan => new DomainModel(Guid.Parse("a04fc5b0-1a67-43ff-89af-750128398d8a")) { EmailAddress = "steven.callahan@example.com", - Name = "Steven Callahan", + Name = nameof(StevenCallahan), PasswordHash = GetPasswordHash("My name is Steven. 321") }; @@ -84,7 +84,7 @@ private static String GetPasswordHash(String plaintextPassword) public static DomainModel TomSmith => new DomainModel(Guid.Parse("3d46470a-1c90-4e94-bc5c-3cbde44ba6ac")) { EmailAddress = "tom.smith@example.com", - Name = "Tom Smith", + Name = nameof(TomSmith), PasswordHash = GetPasswordHash("My name is Tom. 321") }; } diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.Navigation.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.Navigation.cs index 934a4626..49bf0a25 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.Navigation.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.Navigation.cs @@ -21,8 +21,8 @@ namespace RapidField.SolidInstruments.Example.Domain.Models.User /// - DO declare private standard navigation fields as concrete domain models. /// - DO declare internal inverse collection navigation properties as of concrete domain models. /// - DO decorate (public and internal) standard navigation properties with . - /// - DO decorate public inverse collection navigation properties with . - /// - DO decorate internal inverse collection navigation properties with . + /// - DO decorate public inverse collection navigation properties with . + /// - DO decorate internal inverse collection navigation properties with . /// - DO expose getters and internal setters for public standard navigation properties. /// - DO expose getters (but not setters) for (public and internal) inverse collection navigation properties. /// - DO lazily initialize inverse navigation collections. diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.Named.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.Named.cs index a071c1bb..b43e8f29 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.Named.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.Named.cs @@ -49,7 +49,7 @@ public static class Named public static DomainModel EndUser => new DomainModel(Guid.Parse("816e7126-2034-49b3-af08-d07cab150d93")) { Description = "A standard end user.", - Name = "End User" + Name = nameof(EndUser) }; /// @@ -58,7 +58,7 @@ public static class Named public static DomainModel SystemAdministrator => new DomainModel(Guid.Parse("b13c7a39-0c65-4515-a4af-2e3f60d289ba")) { Description = "A user with full administrative privileges.", - Name = "System Administrator" + Name = nameof(SystemAdministrator) }; } } diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.Navigation.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.Navigation.cs index ada87627..313a6355 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.Navigation.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.Navigation.cs @@ -19,8 +19,8 @@ namespace RapidField.SolidInstruments.Example.Domain.Models.UserRole /// - DO declare private standard navigation fields as concrete domain models. /// - DO declare internal inverse collection navigation properties as of concrete domain models. /// - DO decorate (public and internal) standard navigation properties with . - /// - DO decorate public inverse collection navigation properties with . - /// - DO decorate internal inverse collection navigation properties with . + /// - DO decorate public inverse collection navigation properties with . + /// - DO decorate internal inverse collection navigation properties with . /// - DO expose getters and internal setters for public standard navigation properties. /// - DO expose getters (but not setters) for (public and internal) inverse collection navigation properties. /// - DO lazily initialize inverse navigation collections. diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/DomainModel.Navigation.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/DomainModel.Navigation.cs index 484287b6..58afe654 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/DomainModel.Navigation.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/DomainModel.Navigation.cs @@ -24,8 +24,8 @@ namespace RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment /// - DO declare private standard navigation fields as concrete domain models. /// - DO declare internal inverse collection navigation properties as of concrete domain models. /// - DO decorate (public and internal) standard navigation properties with . - /// - DO decorate public inverse collection navigation properties with . - /// - DO decorate internal inverse collection navigation properties with . + /// - DO decorate public inverse collection navigation properties with . + /// - DO decorate internal inverse collection navigation properties with . /// - DO expose getters and internal setters for public standard navigation properties. /// - DO expose getters (but not setters) for (public and internal) inverse collection navigation properties. /// - DO lazily initialize inverse navigation collections. diff --git a/psakefile.ps1 b/psakefile.ps1 index 16c55123..ed00c38c 100644 --- a/psakefile.ps1 +++ b/psakefile.ps1 @@ -39,12 +39,16 @@ Task Clean-Debug -Alias cd -Action { CleanDebug; }; Task Clean-Release -Alias cr -Action { CleanRelease; }; Task List -Alias l -Action { psake -docs }; Task Restore-Dependencies -Alias rd -Action { RestoreDependencies; }; -Task Start-All-Debug -Alias sad -Depends Stop-All, Start-ExampleBeaconServiceApplication-Debug, Start-ExampleAccessControlServiceApplication-Debug; -Task Start-All-Release -Alias sar -Depends Stop-All, Start-ExampleBeaconServiceApplication-Release, Start-ExampleAccessControlServiceApplication-Release; +Task Start-All-Debug -Alias sad -Depends Stop-All, Start-ExampleBeaconServiceApplication-Debug, Start-ExampleIdentityServiceApplication-Debug, Start-ExampleAccessControlServiceApplication-Debug, Start-ExampleAccessControlHttpApiApplication-Debug; +Task Start-All-Release -Alias sar -Depends Stop-All, Start-ExampleBeaconServiceApplication-Release, Start-ExampleIdentityServiceApplication-Release, Start-ExampleAccessControlServiceApplication-Release, Start-ExampleAccessControlHttpApiApplication-Release; +Task Start-ExampleAccessControlHttpApiApplication-Debug -Alias seachad -Depends Build-Debug -Action { StartExampleAccessControlHttpApiApplicationDebug; }; +Task Start-ExampleAccessControlHttpApiApplication-Release -Alias seachar -Depends Build-Release -Action { StartExampleAccessControlHttpApiApplicationRelease; }; Task Start-ExampleAccessControlServiceApplication-Debug -Alias seacsad -Depends Build-Debug -Action { StartExampleAccessControlServiceApplicationDebug; }; Task Start-ExampleAccessControlServiceApplication-Release -Alias seacsar -Depends Build-Release -Action { StartExampleAccessControlServiceApplicationRelease; }; Task Start-ExampleBeaconServiceApplication-Debug -Alias sebsad -Depends Build-Debug -Action { StartExampleBeaconServiceApplicationDebug; }; Task Start-ExampleBeaconServiceApplication-Release -Alias sebsar -Depends Build-Release -Action { StartExampleBeaconServiceApplicationRelease; }; +Task Start-ExampleIdentityServiceApplication-Debug -Alias seisad -Depends Build-Debug -Action { StartExampleIdentityServiceApplicationDebug; }; +Task Start-ExampleIdentityServiceApplication-Release -Alias seisar -Depends Build-Release -Action { StartExampleIdentityServiceApplicationRelease; }; Task Stop-All -Alias sa -Action { StopAllApplications; }; Task Test-All -Alias ta -Depends Build-All, Test-Debug, Test-Release; Task Test-Debug -Alias td -Depends Build-Debug -Action { TestDebug; }; diff --git a/src/RapidField.SolidInstruments.Command.Autofac/RapidField.SolidInstruments.Command.Autofac.csproj b/src/RapidField.SolidInstruments.Command.Autofac/RapidField.SolidInstruments.Command.Autofac.csproj index 2ab3d2c4..21cad6ab 100644 --- a/src/RapidField.SolidInstruments.Command.Autofac/RapidField.SolidInstruments.Command.Autofac.csproj +++ b/src/RapidField.SolidInstruments.Command.Autofac/RapidField.SolidInstruments.Command.Autofac.csproj @@ -39,7 +39,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.Command.DotNetNative/RapidField.SolidInstruments.Command.DotNetNative.csproj b/src/RapidField.SolidInstruments.Command.DotNetNative/RapidField.SolidInstruments.Command.DotNetNative.csproj index b94ca534..3ef4aa07 100644 --- a/src/RapidField.SolidInstruments.Command.DotNetNative/RapidField.SolidInstruments.Command.DotNetNative.csproj +++ b/src/RapidField.SolidInstruments.Command.DotNetNative/RapidField.SolidInstruments.Command.DotNetNative.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.Core/RapidField.SolidInstruments.Core.csproj b/src/RapidField.SolidInstruments.Core/RapidField.SolidInstruments.Core.csproj index 04b1dde7..b52bafff 100644 --- a/src/RapidField.SolidInstruments.Core/RapidField.SolidInstruments.Core.csproj +++ b/src/RapidField.SolidInstruments.Core/RapidField.SolidInstruments.Core.csproj @@ -38,6 +38,6 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.DataAccess.Autofac.Ef/RapidField.SolidInstruments.DataAccess.Autofac.Ef.csproj b/src/RapidField.SolidInstruments.DataAccess.Autofac.Ef/RapidField.SolidInstruments.DataAccess.Autofac.Ef.csproj index d78f3911..4f3b4c02 100644 --- a/src/RapidField.SolidInstruments.DataAccess.Autofac.Ef/RapidField.SolidInstruments.DataAccess.Autofac.Ef.csproj +++ b/src/RapidField.SolidInstruments.DataAccess.Autofac.Ef/RapidField.SolidInstruments.DataAccess.Autofac.Ef.csproj @@ -39,7 +39,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.DataAccess.Autofac/RapidField.SolidInstruments.DataAccess.Autofac.csproj b/src/RapidField.SolidInstruments.DataAccess.Autofac/RapidField.SolidInstruments.DataAccess.Autofac.csproj index 1ae845f7..10e665b4 100644 --- a/src/RapidField.SolidInstruments.DataAccess.Autofac/RapidField.SolidInstruments.DataAccess.Autofac.csproj +++ b/src/RapidField.SolidInstruments.DataAccess.Autofac/RapidField.SolidInstruments.DataAccess.Autofac.csproj @@ -39,7 +39,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.DataAccess.DotNetNative.Ef/RapidField.SolidInstruments.DataAccess.DotNetNative.Ef.csproj b/src/RapidField.SolidInstruments.DataAccess.DotNetNative.Ef/RapidField.SolidInstruments.DataAccess.DotNetNative.Ef.csproj index eaee4f4b..7b34a94a 100644 --- a/src/RapidField.SolidInstruments.DataAccess.DotNetNative.Ef/RapidField.SolidInstruments.DataAccess.DotNetNative.Ef.csproj +++ b/src/RapidField.SolidInstruments.DataAccess.DotNetNative.Ef/RapidField.SolidInstruments.DataAccess.DotNetNative.Ef.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.DataAccess.DotNetNative/RapidField.SolidInstruments.DataAccess.DotNetNative.csproj b/src/RapidField.SolidInstruments.DataAccess.DotNetNative/RapidField.SolidInstruments.DataAccess.DotNetNative.csproj index fd0fa381..4ee0f159 100644 --- a/src/RapidField.SolidInstruments.DataAccess.DotNetNative/RapidField.SolidInstruments.DataAccess.DotNetNative.csproj +++ b/src/RapidField.SolidInstruments.DataAccess.DotNetNative/RapidField.SolidInstruments.DataAccess.DotNetNative.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.DataAccess.EntityFramework/RapidField.SolidInstruments.DataAccess.EntityFramework.csproj b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/RapidField.SolidInstruments.DataAccess.EntityFramework.csproj index cb99729d..13b23168 100644 --- a/src/RapidField.SolidInstruments.DataAccess.EntityFramework/RapidField.SolidInstruments.DataAccess.EntityFramework.csproj +++ b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/RapidField.SolidInstruments.DataAccess.EntityFramework.csproj @@ -37,10 +37,10 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - - + + + + diff --git a/src/RapidField.SolidInstruments.EventAuthoring.Autofac/RapidField.SolidInstruments.EventAuthoring.Autofac.csproj b/src/RapidField.SolidInstruments.EventAuthoring.Autofac/RapidField.SolidInstruments.EventAuthoring.Autofac.csproj index 06367887..b215f605 100644 --- a/src/RapidField.SolidInstruments.EventAuthoring.Autofac/RapidField.SolidInstruments.EventAuthoring.Autofac.csproj +++ b/src/RapidField.SolidInstruments.EventAuthoring.Autofac/RapidField.SolidInstruments.EventAuthoring.Autofac.csproj @@ -39,7 +39,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.EventAuthoring.DotNetNative/RapidField.SolidInstruments.EventAuthoring.DotNetNative.csproj b/src/RapidField.SolidInstruments.EventAuthoring.DotNetNative/RapidField.SolidInstruments.EventAuthoring.DotNetNative.csproj index 8625b7b7..fc2ced73 100644 --- a/src/RapidField.SolidInstruments.EventAuthoring.DotNetNative/RapidField.SolidInstruments.EventAuthoring.DotNetNative.csproj +++ b/src/RapidField.SolidInstruments.EventAuthoring.DotNetNative/RapidField.SolidInstruments.EventAuthoring.DotNetNative.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.InversionOfControl.Autofac/RapidField.SolidInstruments.InversionOfControl.Autofac.csproj b/src/RapidField.SolidInstruments.InversionOfControl.Autofac/RapidField.SolidInstruments.InversionOfControl.Autofac.csproj index 034a3234..348c2ec2 100644 --- a/src/RapidField.SolidInstruments.InversionOfControl.Autofac/RapidField.SolidInstruments.InversionOfControl.Autofac.csproj +++ b/src/RapidField.SolidInstruments.InversionOfControl.Autofac/RapidField.SolidInstruments.InversionOfControl.Autofac.csproj @@ -39,7 +39,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/RapidField.SolidInstruments.InversionOfControl.DotNetNative.csproj b/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/RapidField.SolidInstruments.InversionOfControl.DotNetNative.csproj index bbf0b460..16e3d83a 100644 --- a/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/RapidField.SolidInstruments.InversionOfControl.DotNetNative.csproj +++ b/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/RapidField.SolidInstruments.InversionOfControl.DotNetNative.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.InversionOfControl/RapidField.SolidInstruments.InversionOfControl.csproj b/src/RapidField.SolidInstruments.InversionOfControl/RapidField.SolidInstruments.InversionOfControl.csproj index 6bf95926..1c08fd88 100644 --- a/src/RapidField.SolidInstruments.InversionOfControl/RapidField.SolidInstruments.InversionOfControl.csproj +++ b/src/RapidField.SolidInstruments.InversionOfControl/RapidField.SolidInstruments.InversionOfControl.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.Messaging.Autofac.Asb/RapidField.SolidInstruments.Messaging.Autofac.Asb.csproj b/src/RapidField.SolidInstruments.Messaging.Autofac.Asb/RapidField.SolidInstruments.Messaging.Autofac.Asb.csproj index 1a0bc29d..101f9881 100644 --- a/src/RapidField.SolidInstruments.Messaging.Autofac.Asb/RapidField.SolidInstruments.Messaging.Autofac.Asb.csproj +++ b/src/RapidField.SolidInstruments.Messaging.Autofac.Asb/RapidField.SolidInstruments.Messaging.Autofac.Asb.csproj @@ -39,7 +39,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.Messaging.Autofac.Rmq/RapidField.SolidInstruments.Messaging.Autofac.Rmq.csproj b/src/RapidField.SolidInstruments.Messaging.Autofac.Rmq/RapidField.SolidInstruments.Messaging.Autofac.Rmq.csproj index 2f6d9967..a2f11b32 100644 --- a/src/RapidField.SolidInstruments.Messaging.Autofac.Rmq/RapidField.SolidInstruments.Messaging.Autofac.Rmq.csproj +++ b/src/RapidField.SolidInstruments.Messaging.Autofac.Rmq/RapidField.SolidInstruments.Messaging.Autofac.Rmq.csproj @@ -39,7 +39,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.Messaging.Autofac/RapidField.SolidInstruments.Messaging.Autofac.csproj b/src/RapidField.SolidInstruments.Messaging.Autofac/RapidField.SolidInstruments.Messaging.Autofac.csproj index a9cbd25e..58f88c7b 100644 --- a/src/RapidField.SolidInstruments.Messaging.Autofac/RapidField.SolidInstruments.Messaging.Autofac.csproj +++ b/src/RapidField.SolidInstruments.Messaging.Autofac/RapidField.SolidInstruments.Messaging.Autofac.csproj @@ -39,7 +39,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.Messaging.DotNetNative.Asb/RapidField.SolidInstruments.Messaging.DotNetNative.Asb.csproj b/src/RapidField.SolidInstruments.Messaging.DotNetNative.Asb/RapidField.SolidInstruments.Messaging.DotNetNative.Asb.csproj index c41e2956..b7e23a39 100644 --- a/src/RapidField.SolidInstruments.Messaging.DotNetNative.Asb/RapidField.SolidInstruments.Messaging.DotNetNative.Asb.csproj +++ b/src/RapidField.SolidInstruments.Messaging.DotNetNative.Asb/RapidField.SolidInstruments.Messaging.DotNetNative.Asb.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq.csproj b/src/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq.csproj index b29d014c..0411d9f6 100644 --- a/src/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq.csproj +++ b/src/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.Messaging.DotNetNative/RapidField.SolidInstruments.Messaging.DotNetNative.csproj b/src/RapidField.SolidInstruments.Messaging.DotNetNative/RapidField.SolidInstruments.Messaging.DotNetNative.csproj index aa4550b2..ff3d48d9 100644 --- a/src/RapidField.SolidInstruments.Messaging.DotNetNative/RapidField.SolidInstruments.Messaging.DotNetNative.csproj +++ b/src/RapidField.SolidInstruments.Messaging.DotNetNative/RapidField.SolidInstruments.Messaging.DotNetNative.csproj @@ -37,9 +37,9 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - + + + diff --git a/src/RapidField.SolidInstruments.ObjectComposition/RapidField.SolidInstruments.ObjectComposition.csproj b/src/RapidField.SolidInstruments.ObjectComposition/RapidField.SolidInstruments.ObjectComposition.csproj index 32b33c70..93d4ed51 100644 --- a/src/RapidField.SolidInstruments.ObjectComposition/RapidField.SolidInstruments.ObjectComposition.csproj +++ b/src/RapidField.SolidInstruments.ObjectComposition/RapidField.SolidInstruments.ObjectComposition.csproj @@ -37,7 +37,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/test/RapidField.SolidInstruments.Core.UnitTests/RapidField.SolidInstruments.Core.UnitTests.csproj b/test/RapidField.SolidInstruments.Core.UnitTests/RapidField.SolidInstruments.Core.UnitTests.csproj index ad8ec575..b7fc967a 100644 --- a/test/RapidField.SolidInstruments.Core.UnitTests/RapidField.SolidInstruments.Core.UnitTests.csproj +++ b/test/RapidField.SolidInstruments.Core.UnitTests/RapidField.SolidInstruments.Core.UnitTests.csproj @@ -19,7 +19,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/test/RapidField.SolidInstruments.InversionOfControl.Autofac.UnitTests/RapidField.SolidInstruments.InversionOfControl.Autofac.UnitTests.csproj b/test/RapidField.SolidInstruments.InversionOfControl.Autofac.UnitTests/RapidField.SolidInstruments.InversionOfControl.Autofac.UnitTests.csproj index fd6aebc6..5648795a 100644 --- a/test/RapidField.SolidInstruments.InversionOfControl.Autofac.UnitTests/RapidField.SolidInstruments.InversionOfControl.Autofac.UnitTests.csproj +++ b/test/RapidField.SolidInstruments.InversionOfControl.Autofac.UnitTests/RapidField.SolidInstruments.InversionOfControl.Autofac.UnitTests.csproj @@ -19,7 +19,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/test/RapidField.SolidInstruments.InversionOfControl.DotNetNative.UnitTests/RapidField.SolidInstruments.InversionOfControl.DotNetNative.UnitTests.csproj b/test/RapidField.SolidInstruments.InversionOfControl.DotNetNative.UnitTests/RapidField.SolidInstruments.InversionOfControl.DotNetNative.UnitTests.csproj index 36fb3bb6..57e8917f 100644 --- a/test/RapidField.SolidInstruments.InversionOfControl.DotNetNative.UnitTests/RapidField.SolidInstruments.InversionOfControl.DotNetNative.UnitTests.csproj +++ b/test/RapidField.SolidInstruments.InversionOfControl.DotNetNative.UnitTests/RapidField.SolidInstruments.InversionOfControl.DotNetNative.UnitTests.csproj @@ -19,7 +19,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/test/RapidField.SolidInstruments.InversionOfControl.UnitTests/RapidField.SolidInstruments.InversionOfControl.UnitTests.csproj b/test/RapidField.SolidInstruments.InversionOfControl.UnitTests/RapidField.SolidInstruments.InversionOfControl.UnitTests.csproj index da9e830a..41c2ffc2 100644 --- a/test/RapidField.SolidInstruments.InversionOfControl.UnitTests/RapidField.SolidInstruments.InversionOfControl.UnitTests.csproj +++ b/test/RapidField.SolidInstruments.InversionOfControl.UnitTests/RapidField.SolidInstruments.InversionOfControl.UnitTests.csproj @@ -19,7 +19,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/test/RapidField.SolidInstruments.ObjectComposition.UnitTests/RapidField.SolidInstruments.ObjectComposition.UnitTests.csproj b/test/RapidField.SolidInstruments.ObjectComposition.UnitTests/RapidField.SolidInstruments.ObjectComposition.UnitTests.csproj index 09da7cd4..43b6b478 100644 --- a/test/RapidField.SolidInstruments.ObjectComposition.UnitTests/RapidField.SolidInstruments.ObjectComposition.UnitTests.csproj +++ b/test/RapidField.SolidInstruments.ObjectComposition.UnitTests/RapidField.SolidInstruments.ObjectComposition.UnitTests.csproj @@ -19,7 +19,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - +