From 92b5ca549943ddeb5d26107bb0b511ce59c6020b Mon Sep 17 00:00:00 2001 From: adamjstone <8525409+adamjstone@users.noreply.github.com> Date: Mon, 31 Aug 2020 12:16:08 -0500 Subject: [PATCH] #371 Add UserRoleAssignment to example projects. --- cicd/modules/BuildAndDeployment.psm1 | 48 ++--- en-US_User.dic | 1 + example/README.md | 9 +- .../README.md | 30 +++ .../ApplicationServiceExecutor.cs | 107 ++++++++--- .../CreateDomainModelCommandHandler.cs | 42 ++++ .../DeleteDomainModelCommandHandler.cs | 42 ++++ .../UpdateDomainModelCommandHandler.cs | 42 ++++ .../DatabaseContext.cs | 26 ++- .../DatabaseContextDependencyModule.cs | 2 + .../DatabaseContextRepositoryFactory.cs | 1 + .../User/DomainModelCreatedEventHandler.cs | 2 +- .../User/DomainModelDeletedEventHandler.cs | 2 +- .../User/DomainModelUpdatedEventHandler.cs | 2 +- .../DomainModelCreatedEventHandler.cs | 2 +- .../DomainModelDeletedEventHandler.cs | 2 +- .../DomainModelUpdatedEventHandler.cs | 2 +- .../DomainModelCreatedEventHandler.cs | 64 +++++++ .../DomainModelDeletedEventHandler.cs | 64 +++++++ .../DomainModelUpdatedEventHandler.cs | 64 +++++++ ...uments.Example.Domain.AccessControl.csproj | 4 - .../UserRoleAssignmentRepository.cs | 32 ++++ .../CreateDomainModelCommand.cs | 129 +++++++++++++ .../DeleteDomainModelCommand.cs | 129 +++++++++++++ .../UpdateDomainModelCommand.cs | 129 +++++++++++++ .../DomainModelCreatedEvent.cs | 180 ++++++++++++++++++ .../DomainModelDeletedEvent.cs | 180 ++++++++++++++++++ .../DomainModelUpdatedEvent.cs | 180 ++++++++++++++++++ .../MessageHandlerModule.cs | 12 ++ .../CreateDomainModelCommandMessage.cs | 53 ++++++ .../DeleteDomainModelCommandMessage.cs | 53 ++++++ .../UpdateDomainModelCommandMessage.cs | 53 ++++++ .../DomainModelCreatedEventMessage.cs | 51 +++++ .../DomainModelDeletedEventMessage.cs | 51 +++++ .../DomainModelUpdatedEventMessage.cs | 51 +++++ .../Models/User/AggregateDataAccessModel.cs | 26 +++ .../Models/User/DomainModel.cs | 29 ++- .../Models/User/IAggregateDomainModel.cs | 10 + .../Models/UserRole/DomainModel.cs | 2 +- .../AggregateDataAccessModel.cs | 89 +++++++++ .../Models/UserRoleAssignment/DomainModel.cs | 125 ++++++++++++ .../IAggregateDomainModel.cs | 32 ++++ .../UserRoleAssignment/IAggregateModel.cs | 30 +++ .../UserRoleAssignment/IValueDomainModel.cs | 15 ++ .../UserRoleAssignment/IValueModel.cs.cs | 15 ++ .../ValueDataAccessModel.cs | 43 +++++ ...eld.SolidInstruments.Example.Domain.csproj | 8 - .../AggregateModelRepository.cs | 37 ++++ .../ValueModelRepository.cs | 37 ++++ psakefile.ps1 | 12 +- .../AssemblyAttributes.cs | 2 + src/RapidField.SolidInstruments.Core/Model.cs | 133 +++++++++++++ .../DataAccessModelConfiguration.cs | 119 ++++++++++++ .../EntityFrameworkDataAccessModel.cs | 48 ----- .../EntityFrameworkRepository.cs | 125 ++++++++++-- .../IDataAccessModelConfiguration.cs | 35 ++++ .../DomainModelAssociatedEvent.cs | 2 +- .../DomainModelCreatedEvent.cs | 2 +- .../DomainModelDeletedEvent.cs | 2 +- .../DomainModelUpdatedEvent.cs | 2 +- .../Service/MessagingServiceExecutor.cs | 1 + 61 files changed, 2675 insertions(+), 147 deletions(-) create mode 100644 example/RapidField.SolidInstruments.Example.BeaconService/README.md create mode 100644 example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/CreateDomainModelCommandHandler.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/DeleteDomainModelCommandHandler.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/UpdateDomainModelCommandHandler.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain.AccessControl/Repositories/UserRoleAssignmentRepository.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/CreateDomainModelCommand.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/DeleteDomainModelCommand.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/UpdateDomainModelCommand.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelCreatedEvent.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelDeletedEvent.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelUpdatedEvent.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/CreateDomainModelCommandMessage.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/DeleteDomainModelCommandMessage.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/UpdateDomainModelCommandMessage.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelCreatedEventMessage.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelDeletedEventMessage.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelUpdatedEventMessage.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/AggregateDataAccessModel.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/DomainModel.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IAggregateDomainModel.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IAggregateModel.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IValueDomainModel.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IValueModel.cs.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/ValueDataAccessModel.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Repositories/UserRoleAssignment/AggregateModelRepository.cs create mode 100644 example/RapidField.SolidInstruments.Example.Domain/Repositories/UserRoleAssignment/ValueModelRepository.cs create mode 100644 src/RapidField.SolidInstruments.DataAccess.EntityFramework/DataAccessModelConfiguration.cs create mode 100644 src/RapidField.SolidInstruments.DataAccess.EntityFramework/IDataAccessModelConfiguration.cs diff --git a/cicd/modules/BuildAndDeployment.psm1 b/cicd/modules/BuildAndDeployment.psm1 index 69d4d326..4e2f3c2a 100644 --- a/cicd/modules/BuildAndDeployment.psm1 +++ b/cicd/modules/BuildAndDeployment.psm1 @@ -87,8 +87,8 @@ $SolutionConfigurationDebug = "Debug"; $SolutionConfigurationRelease = "Release"; # Namespaces -$ExampleServiceApplicationNamespace = "RapidField.SolidInstruments.Example.ServiceApplication"; -$ExampleWebApplicationNamespace = "RapidField.SolidInstruments.Example.WebApplication"; +$ExampleAccessControlServiceApplicationNamespace = "RapidField.SolidInstruments.Example.Domain.AccessControl.Service"; +$ExampleBeaconServiceApplicationNamespace = "RapidField.SolidInstruments.Example.BeaconService"; # Regular expressions $ValidCommitMessageRegularExpressionPattern = "^(#[1-9][0-9]{0,4} )?[A-Z][A-Za-z0-9\,\.\!\;\:\'\""\@\#\$\%\^\&\*\-\+\=_\(\)\[\]\{\}\|\\\/\s]{8,144}$"; @@ -609,9 +609,9 @@ Function SignPackages <# .Synopsis -Starts the example service application. +Starts the example access control service application. #> -Function StartExampleServiceApplication +Function StartExampleAccessControlServiceApplication { Param ( @@ -619,8 +619,8 @@ Function StartExampleServiceApplication [String] $SolutionConfiguration ) - ComposeStart "Starting the example service application using $SolutionConfiguration configuration."; - $BinaryFilePath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleServiceApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleServiceApplication\$ExampleServiceApplicationNamespace.dll"; + ComposeStart "Starting the example access control service application using $SolutionConfiguration configuration."; + $BinaryFilePath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleServiceApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleServiceApplication\$ExampleAccessControlServiceApplicationNamespace.dll"; ComposeNormal "Using binary path: $BinaryFilePath"; Start-Process -ArgumentList "$BinaryFilePath" -FilePath "dotnet" -WindowStyle Minimized; ComposeFinish "Finished starting the application."; @@ -628,27 +628,27 @@ Function StartExampleServiceApplication <# .Synopsis -Starts the example service application in debug mode. +Starts the example access control service application in debug mode. #> -Function StartExampleServiceApplicationDebug +Function StartExampleAccessControlServiceApplicationDebug { - StartExampleServiceApplication -SolutionConfiguration $SolutionConfigurationDebug; + StartExampleAccessControlServiceApplication -SolutionConfiguration $SolutionConfigurationDebug; } <# .Synopsis -Starts the example service application in release mode. +Starts the example access control service application in release mode. #> -Function StartExampleServiceApplicationRelease +Function StartExampleAccessControlServiceApplicationRelease { - StartExampleServiceApplication -SolutionConfiguration $SolutionConfigurationRelease; + StartExampleAccessControlServiceApplication -SolutionConfiguration $SolutionConfigurationRelease; } <# .Synopsis -Starts the example web application. +Starts the example beacon service application. #> -Function StartExampleWebApplication +Function StartExampleBeaconServiceApplication { Param ( @@ -656,29 +656,29 @@ Function StartExampleWebApplication [String] $SolutionConfiguration ) - ComposeStart "Starting the example web application using $SolutionConfiguration configuration."; - $ProjectFilePath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleWebApplicationNamespace\$ExampleWebApplicationNamespace.csproj"; - ComposeNormal "Using project path: $ProjectFilePath"; - Start-Process -ArgumentList "run --project ""$ProjectFilePath"" --configuration $SolutionConfiguration" -FilePath "dotnet" -WindowStyle Minimized; + ComposeStart "Starting the example beacon service application using $SolutionConfiguration configuration."; + $BinaryFilePath = Join-Path -Path "$DirectoryPathForExample" -ChildPath "$ExampleServiceApplicationNamespace\bin\$SolutionConfiguration\$TargetFrameworkForExampleServiceApplication\$ExampleBeaconServiceApplicationNamespace.dll"; + ComposeNormal "Using binary path: $BinaryFilePath"; + Start-Process -ArgumentList "$BinaryFilePath" -FilePath "dotnet" -WindowStyle Minimized; ComposeFinish "Finished starting the application."; } <# .Synopsis -Starts the example web application in debug mode. +Starts the example beacon service application in debug mode. #> -Function StartExampleWebApplicationDebug +Function StartExampleBeaconServiceApplicationDebug { - StartExampleWebApplication -SolutionConfiguration $SolutionConfigurationDebug; + StartExampleBeaconServiceApplication -SolutionConfiguration $SolutionConfigurationDebug; } <# .Synopsis -Starts the example web application in release mode. +Starts the example beacon service application in release mode. #> -Function StartExampleWebApplicationRelease +Function StartExampleBeaconServiceApplicationRelease { - StartExampleWebApplication -SolutionConfiguration $SolutionConfigurationRelease; + StartExampleBeaconServiceApplication -SolutionConfiguration $SolutionConfigurationRelease; } <# diff --git a/en-US_User.dic b/en-US_User.dic index 814500ed..ad54253f 100644 --- a/en-US_User.dic +++ b/en-US_User.dic @@ -260,6 +260,7 @@ unencrypted unformatted uninstallation unmanaged +untracked uref url usings diff --git a/example/README.md b/example/README.md index 7de140fd..5c210b9b 100644 --- a/example/README.md +++ b/example/README.md @@ -13,11 +13,10 @@ This document describes the purpose of the [`example`]() directory. This path contains sample projects that utilize the **Solid Instruments** [constituent libraries](/../src). -- [`RapidField.SolidInstruments.Example.Contracts`](/example/RapidField.SolidInstruments.Example.Contracts) exposes sample contracts that are used to demonstrate the **Solid Instruments** [messaging](../src/RapidField.SolidInstruments.Messaging/README.md) constructs. -- [`RapidField.SolidInstruments.Example.DatabaseModel`](/example/RapidField.SolidInstruments.Example.DatabaseModel) serves as a sample data access API that is modeled using the **Solid Instruments** [**Entity Framework**](https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/overview) abstractions. -- [`RapidField.SolidInstruments.Example.Domain`](/example/RapidField.SolidInstruments.Example.Domain) houses sample domain machinery that utilizes the **Solid Instruments** [data access](../src/RapidField.SolidInstruments.DataAccess/README.md) and [messaging](../src/RapidField.SolidInstruments.Messaging/README.md) constructs. -- [`RapidField.SolidInstruments.Example.ServiceApplication`](/example/RapidField.SolidInstruments.Example.ServiceApplication) serves as a sample service application that employs the **Solid Instruments** [messaging](../src/RapidField.SolidInstruments.Messaging/README.md) and [dependency injection](../src/RapidField.SolidInstruments.InversionOfControl/README.md) abstractions. -- [`RapidField.SolidInstruments.Example.WebApplication`](/example/RapidField.SolidInstruments.Example.WebApplication) serves as a sample web application that employs the **Solid Instruments** [dependency injection](../src/RapidField.SolidInstruments.InversionOfControl/README.md) abstractions. +- [`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. ## License diff --git a/example/RapidField.SolidInstruments.Example.BeaconService/README.md b/example/RapidField.SolidInstruments.Example.BeaconService/README.md new file mode 100644 index 00000000..61f331ab --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.BeaconService/README.md @@ -0,0 +1,30 @@ + + +[![Solid Instruments](../../SolidInstruments.Logo.Color.Transparent.500w.png)](../../README.md) +- - - + +# RapidField.SolidInstruments.Example.BeaconService + +This document describes the purpose of the [`RapidField.SolidInstruments.Example.BeaconService`]() project. + +## Purpose + +This project demonstrates a utility service that publishes scheduled heartbeat messages. + +## 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.Service/ApplicationServiceExecutor.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs index b190bbf3..d76d7263 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs @@ -10,7 +10,9 @@ 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.AccessControl.Service { @@ -65,6 +67,9 @@ protected override void AddListeners(IMessageListeningProfile listeningProfile, listeningProfile.AddCommandListener(); listeningProfile.AddCommandListener(); listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); + listeningProfile.AddCommandListener(); // Add event listeners. listeningProfile.AddEventListener(); @@ -73,6 +78,9 @@ protected override void AddListeners(IMessageListeningProfile listeningProfile, listeningProfile.AddEventListener(); listeningProfile.AddEventListener(); listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); + listeningProfile.AddEventListener(); } finally { @@ -123,41 +131,88 @@ protected override void OnExecutionStarting(IDependencyScope dependencyScope, IC try { var mediator = dependencyScope.Resolve(); + TestServiceBusConnectivity(mediator); + MigrateDatabaseSchema(dependencyScope); + HydrateNamedEntities(mediator); + } + finally + { + base.OnExecutionStarting(dependencyScope, applicationConfiguration, executionLifetime); + } + } + + /// + /// Creates or updates all named domain models. + /// + /// + /// A mediator that is used to issue commands. + /// + [DebuggerHidden] + private static void HydrateNamedEntities(ICommandMediator mediator) + { + foreach (var domainModel in Models.User.DomainModel.Named.All()) + { + mediator.Process(new Messages.Command.ModelState.User.CreateDomainModelCommandMessage(new Commands.ModelState.User.CreateDomainModelCommand(domainModel))); + } - // Create or update the database schema. - var databaseContext = dependencyScope.Resolve(); - databaseContext.Database.EnsureCreated(); + Thread.Sleep(610); - foreach (var domainModel in Models.User.DomainModel.Named.All()) - { - mediator.Process(new Messages.Command.ModelState.User.CreateDomainModelCommandMessage(new Commands.ModelState.User.CreateDomainModelCommand(domainModel))); - } + foreach (var domainModel in Models.UserRole.DomainModel.Named.All()) + { + mediator.Process(new Messages.Command.ModelState.UserRole.CreateDomainModelCommandMessage(new Commands.ModelState.UserRole.CreateDomainModelCommand(domainModel))); + } - 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); - try - { - // Test service bus connectivity. - 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) + foreach (var domainModel in Models.UserRoleAssignment.DomainModel.Named.All()) + { + mediator.Process(new Messages.Command.ModelState.UserRoleAssignment.CreateDomainModelCommandMessage(new Commands.ModelState.UserRoleAssignment.CreateDomainModelCommand(domainModel))); + } + + Thread.Sleep(610); + Console.WriteLine("Database entities created/updated."); + } + + /// + /// 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(); + Thread.Sleep(610); + Console.WriteLine("Database schema created/updated."); + } + + /// + /// Raises an exception if a service bus connection is unavailable. + /// + /// + /// A mediator that is used to issue commands. + /// + [DebuggerHidden] + private static void TestServiceBusConnectivity(ICommandMediator mediator) + { + try + { + 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. See inner exception.", exception); + throw new ServiceExectuionException("The service was unable to verify service bus connectivity."); } } - finally + catch (CommandHandlingException exception) { - base.OnExecutionStarting(dependencyScope, applicationConfiguration, executionLifetime); + throw new ServiceExectuionException("The service was unable to verify service bus connectivity. See inner exception.", exception); } + + Console.WriteLine("Service bus connectivity verified."); } /// diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/CreateDomainModelCommandHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/CreateDomainModelCommandHandler.cs new file mode 100644 index 00000000..f907b538 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/CreateDomainModelCommandHandler.cs @@ -0,0 +1,42 @@ +// ================================================================================================================================= +// 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.DataAccess; +using System; +using DataAccessModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.AggregateDataAccessModel; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelCommand = RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment.CreateDomainModelCommand; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.CommandHandlers.ModelState.UserRoleAssignment +{ + /// + /// Processes a single . + /// + public sealed class CreateDomainModelCommandHandler : CreateDomainModelCommandHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + public CreateDomainModelCommandHandler(ICommandMediator mediator) + : base(mediator) + { + return; + } + + /// + /// 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); + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/DeleteDomainModelCommandHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/DeleteDomainModelCommandHandler.cs new file mode 100644 index 00000000..66563a5d --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/DeleteDomainModelCommandHandler.cs @@ -0,0 +1,42 @@ +// ================================================================================================================================= +// 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.DataAccess; +using System; +using DataAccessModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.AggregateDataAccessModel; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelCommand = RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment.DeleteDomainModelCommand; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.CommandHandlers.ModelState.UserRoleAssignment +{ + /// + /// Processes a single . + /// + public sealed class DeleteDomainModelCommandHandler : DeleteDomainModelCommandHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + public DeleteDomainModelCommandHandler(ICommandMediator mediator) + : base(mediator) + { + return; + } + + /// + /// 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); + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/UpdateDomainModelCommandHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/UpdateDomainModelCommandHandler.cs new file mode 100644 index 00000000..c00dcb14 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/UpdateDomainModelCommandHandler.cs @@ -0,0 +1,42 @@ +// ================================================================================================================================= +// 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.DataAccess; +using System; +using DataAccessModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.AggregateDataAccessModel; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelCommand = RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment.UpdateDomainModelCommand; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.CommandHandlers.ModelState.UserRoleAssignment +{ + /// + /// Processes a single . + /// + public sealed class UpdateDomainModelCommandHandler : UpdateDomainModelCommandHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + public UpdateDomainModelCommandHandler(ICommandMediator mediator) + : base(mediator) + { + return; + } + + /// + /// 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); + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContext.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContext.cs index b2d6ba70..8fa243e8 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContext.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContext.cs @@ -9,6 +9,7 @@ using System.Configuration; using System.Diagnostics; using UserModel = RapidField.SolidInstruments.Example.Domain.Models.User.AggregateDataAccessModel; +using UserRoleAssignmentModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.AggregateDataAccessModel; using UserRoleModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.AggregateDataAccessModel; namespace RapidField.SolidInstruments.Example.Domain.AccessControl @@ -50,8 +51,20 @@ protected override void OnModelCreating(IConfiguration applicationConfiguration, { try { - _ = modelBuilder.Entity(); - _ = modelBuilder.Entity(); + _ = modelBuilder + .Entity(entityType => + { + entityType.HasMany(entity => entity.UserRoleAssignments).WithOne(entity => entity.User); + }) + .Entity(entityType => + { + return; + }) + .Entity(entityType => + { + entityType.HasOne(entity => entity.User).WithMany(entity => entity.UserRoleAssignments).HasForeignKey(entity => entity.UserIdentifier); + entityType.HasOne(entity => entity.UserRole).WithMany().HasForeignKey(entity => entity.UserRoleIdentifier); + }); } finally { @@ -59,6 +72,15 @@ protected override void OnModelCreating(IConfiguration applicationConfiguration, } } + /// + /// Gets or sets a persistent collection of records. + /// + public DbSet UserRoleAssignments + { + get; + set; + } + /// /// Gets or sets a persistent collection of records. /// diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContextDependencyModule.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContextDependencyModule.cs index f392a553..dbe3407f 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContextDependencyModule.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContextDependencyModule.cs @@ -9,6 +9,7 @@ using RapidField.SolidInstruments.Example.Domain.AccessControl.Repositories; using System; using UserModel = RapidField.SolidInstruments.Example.Domain.Models.User.AggregateDataAccessModel; +using UserRoleAssignmentModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.AggregateDataAccessModel; using UserRoleModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.AggregateDataAccessModel; namespace RapidField.SolidInstruments.Example.Domain.AccessControl @@ -44,6 +45,7 @@ public DatabaseContextDependencyModule(IConfiguration applicationConfiguration) /// protected override void RegisterCustomComponents(ServiceCollection configurator, IConfiguration applicationConfiguration) => _ = configurator .AddStandardDataAccessModelCommandHandlers() + .AddStandardDataAccessModelCommandHandlers() .AddStandardDataAccessModelCommandHandlers(); } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContextRepositoryFactory.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContextRepositoryFactory.cs index f5a4d2c3..6b9e0174 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContextRepositoryFactory.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/DatabaseContextRepositoryFactory.cs @@ -46,6 +46,7 @@ public DatabaseContextRepositoryFactory(DatabaseContext context, IConfiguration /// protected override void Configure(ObjectFactoryConfiguration configuration, DatabaseContext context) => configuration.ProductionFunctions .Add(() => new UserRepository(context)) + .Add(() => new UserRoleAssignmentRepository(context)) .Add(() => new UserRoleRepository(context)); /// 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 83c6af65..27f11f53 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($"A user was created (identifier: {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.ToSerializedString()}."); } } \ 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 619c582a..ba74bbe1 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($"A user was deleted (identifier: {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.ToSerializedString()}."); } } \ 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 0e17abb0..34875c73 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($"A user was updated (identifier: {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.ToSerializedString()}."); } } \ 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 4ad8c129..b3f94576 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($"A user role was created (identifier: {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.ToSerializedString()}."); } } \ 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 3cdb498c..c657a3eb 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($"A user role was deleted (identifier: {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.ToSerializedString()}."); } } \ 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 1d390fce..85d061a0 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($"A user role was updated (identifier: {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.ToSerializedString()}."); } } \ 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 new file mode 100644 index 00000000..be30b0e9 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelCreatedEventHandler.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 RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.Core.Extensions; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelCreatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.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. + /// + /// + /// is . + /// + public DomainModelCreatedEventHandler(ICommandMediator mediator) + : base(mediator) + { + return; + } + + /// + /// 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) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + } +} \ 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 new file mode 100644 index 00000000..c26e6aad --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelDeletedEventHandler.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 RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.Core.Extensions; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelDeletedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.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. + /// + /// + /// is . + /// + public DomainModelDeletedEventHandler(ICommandMediator mediator) + : base(mediator) + { + return; + } + + /// + /// 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) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + } +} \ 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 new file mode 100644 index 00000000..4616d5f4 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/EventHandlers/ModelState/UserRoleAssignment/DomainModelUpdatedEventHandler.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 RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.Core.Extensions; +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelUpdatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.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. + /// + /// + /// is . + /// + public DomainModelUpdatedEventHandler(ICommandMediator mediator) + : base(mediator) + { + return; + } + + /// + /// 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) => Console.WriteLine($"{DomainModelEvent.DataContractNameVerb} {DomainModel.DataContractName} {model?.Identifier.ToSerializedString()}."); + } +} \ No newline at end of file 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 c6c75b7b..81c381fb 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 @@ -32,8 +32,4 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - - \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/Repositories/UserRoleAssignmentRepository.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/Repositories/UserRoleAssignmentRepository.cs new file mode 100644 index 00000000..cc52e4e4 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/Repositories/UserRoleAssignmentRepository.cs @@ -0,0 +1,32 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using DataAccessModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.AggregateDataAccessModel; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.Repositories +{ + using BaseRepository = Domain.Repositories.UserRoleAssignment.AggregateModelRepository; + + /// + /// Performs data access operations for the type. + /// + public sealed class UserRoleAssignmentRepository : BaseRepository + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The database session for the repository. + /// + /// + /// is . + /// + public UserRoleAssignmentRepository(DatabaseContext context) + : base(context) + { + return; + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/CreateDomainModelCommand.cs b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/CreateDomainModelCommand.cs new file mode 100644 index 00000000..3d585ed4 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/CreateDomainModelCommand.cs @@ -0,0 +1,129 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using ReportedEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelCreatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment +{ + /// + /// Represents a command to create a . + /// + [DataContract(Name = DataContractName)] + public sealed class CreateDomainModelCommand : CreateDomainModelReportableCommand + { + /// + /// Initializes a new instance of the class. + /// + public CreateDomainModelCommand() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is equal to . + /// + public CreateDomainModelCommand(Guid correlationIdentifier) + : base(correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// is . + /// + public CreateDomainModelCommand(DomainModel model) + : base(model) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is . + /// + /// + /// is equal to . + /// + public CreateDomainModelCommand(DomainModel model, Guid correlationIdentifier) + : base(model, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// is -or- is . + /// + public CreateDomainModelCommand(DomainModel model, IEnumerable labels) + : base(model, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public CreateDomainModelCommand(DomainModel model, IEnumerable labels, Guid correlationIdentifier) + : base(model, labels, correlationIdentifier) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DataContractNameVerb + DomainModel.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/DeleteDomainModelCommand.cs b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/DeleteDomainModelCommand.cs new file mode 100644 index 00000000..7cf2e0aa --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/DeleteDomainModelCommand.cs @@ -0,0 +1,129 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using ReportedEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelDeletedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment +{ + /// + /// Represents a command to delete a . + /// + [DataContract(Name = DataContractName)] + public sealed class DeleteDomainModelCommand : DeleteDomainModelReportableCommand + { + /// + /// Initializes a new instance of the class. + /// + public DeleteDomainModelCommand() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is equal to . + /// + public DeleteDomainModelCommand(Guid correlationIdentifier) + : base(correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// is . + /// + public DeleteDomainModelCommand(DomainModel model) + : base(model) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is . + /// + /// + /// is equal to . + /// + public DeleteDomainModelCommand(DomainModel model, Guid correlationIdentifier) + : base(model, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// is -or- is . + /// + public DeleteDomainModelCommand(DomainModel model, IEnumerable labels) + : base(model, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public DeleteDomainModelCommand(DomainModel model, IEnumerable labels, Guid correlationIdentifier) + : base(model, labels, correlationIdentifier) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DataContractNameVerb + DomainModel.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/UpdateDomainModelCommand.cs b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/UpdateDomainModelCommand.cs new file mode 100644 index 00000000..1e75e070 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/UpdateDomainModelCommand.cs @@ -0,0 +1,129 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using ReportedEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelUpdatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment +{ + /// + /// Represents a command to update a . + /// + [DataContract(Name = DataContractName)] + public sealed class UpdateDomainModelCommand : UpdateDomainModelReportableCommand + { + /// + /// Initializes a new instance of the class. + /// + public UpdateDomainModelCommand() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is equal to . + /// + public UpdateDomainModelCommand(Guid correlationIdentifier) + : base(correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// is . + /// + public UpdateDomainModelCommand(DomainModel model) + : base(model) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is . + /// + /// + /// is equal to . + /// + public UpdateDomainModelCommand(DomainModel model, Guid correlationIdentifier) + : base(model, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// is -or- is . + /// + public UpdateDomainModelCommand(DomainModel model, IEnumerable labels) + : base(model, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The desired state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public UpdateDomainModelCommand(DomainModel model, IEnumerable labels, Guid correlationIdentifier) + : base(model, labels, correlationIdentifier) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DataContractNameVerb + DomainModel.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelCreatedEvent.cs b/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelCreatedEvent.cs new file mode 100644 index 00000000..c11dcb78 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelCreatedEvent.cs @@ -0,0 +1,180 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment +{ + /// + /// Represents information about the creation of a . + /// + [DataContract(Name = DataContractName)] + public sealed class DomainModelCreatedEvent : DomainModelCreatedEvent + { + /// + /// Initializes a new instance of the class. + /// + public DomainModelCreatedEvent() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is equal to . + /// + public DomainModelCreatedEvent(Guid correlationIdentifier) + : base(correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// is . + /// + public DomainModelCreatedEvent(DomainModel model) + : base(model) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is . + /// + /// + /// is equal to . + /// + public DomainModelCreatedEvent(DomainModel model, Guid correlationIdentifier) + : base(model, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// is -or- is . + /// + public DomainModelCreatedEvent(DomainModel model, IEnumerable labels) + : base(model, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public DomainModelCreatedEvent(DomainModel model, IEnumerable labels, Guid correlationIdentifier) + : base(model, labels, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// The verbosity level of the event. The default value is + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public DomainModelCreatedEvent(DomainModel model, IEnumerable labels, EventVerbosity verbosity) + : base(model, labels, verbosity) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// The verbosity level of the event. The default value is + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is -or- is . + /// + /// + /// is equal to -or- + /// is equal to . + /// + public DomainModelCreatedEvent(DomainModel model, IEnumerable labels, EventVerbosity verbosity, Guid correlationIdentifier) + : base(model, labels, verbosity, correlationIdentifier) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModel.DataContractName + DataContractNameVerb + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelDeletedEvent.cs b/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelDeletedEvent.cs new file mode 100644 index 00000000..04e19d24 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelDeletedEvent.cs @@ -0,0 +1,180 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment +{ + /// + /// Represents information about the deletion of a . + /// + [DataContract(Name = DataContractName)] + public sealed class DomainModelDeletedEvent : DomainModelDeletedEvent + { + /// + /// Initializes a new instance of the class. + /// + public DomainModelDeletedEvent() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is equal to . + /// + public DomainModelDeletedEvent(Guid correlationIdentifier) + : base(correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// is . + /// + public DomainModelDeletedEvent(DomainModel model) + : base(model) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is . + /// + /// + /// is equal to . + /// + public DomainModelDeletedEvent(DomainModel model, Guid correlationIdentifier) + : base(model, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// is -or- is . + /// + public DomainModelDeletedEvent(DomainModel model, IEnumerable labels) + : base(model, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public DomainModelDeletedEvent(DomainModel model, IEnumerable labels, Guid correlationIdentifier) + : base(model, labels, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// The verbosity level of the event. The default value is + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public DomainModelDeletedEvent(DomainModel model, IEnumerable labels, EventVerbosity verbosity) + : base(model, labels, verbosity) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// The verbosity level of the event. The default value is + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is -or- is . + /// + /// + /// is equal to -or- + /// is equal to . + /// + public DomainModelDeletedEvent(DomainModel model, IEnumerable labels, EventVerbosity verbosity, Guid correlationIdentifier) + : base(model, labels, verbosity, correlationIdentifier) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModel.DataContractName + DataContractNameVerb + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelUpdatedEvent.cs b/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelUpdatedEvent.cs new file mode 100644 index 00000000..4ae7edd0 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Events/ModelState/UserRoleAssignment/DomainModelUpdatedEvent.cs @@ -0,0 +1,180 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.EventAuthoring; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment +{ + /// + /// Represents information about an update to a . + /// + [DataContract(Name = DataContractName)] + public sealed class DomainModelUpdatedEvent : DomainModelUpdatedEvent + { + /// + /// Initializes a new instance of the class. + /// + public DomainModelUpdatedEvent() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is equal to . + /// + public DomainModelUpdatedEvent(Guid correlationIdentifier) + : base(correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// is . + /// + public DomainModelUpdatedEvent(DomainModel model) + : base(model) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is . + /// + /// + /// is equal to . + /// + public DomainModelUpdatedEvent(DomainModel model, Guid correlationIdentifier) + : base(model, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// is -or- is . + /// + public DomainModelUpdatedEvent(DomainModel model, IEnumerable labels) + : base(model, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public DomainModelUpdatedEvent(DomainModel model, IEnumerable labels, Guid correlationIdentifier) + : base(model, labels, correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// The verbosity level of the event. The default value is + /// + /// + /// is -or- is . + /// + /// + /// is equal to . + /// + public DomainModelUpdatedEvent(DomainModel model, IEnumerable labels, EventVerbosity verbosity) + : base(model, labels, verbosity) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The resulting state of the associated domain model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// + /// + /// The verbosity level of the event. The default value is + /// + /// + /// A unique identifier that is assigned to related events. + /// + /// + /// is -or- is . + /// + /// + /// is equal to -or- + /// is equal to . + /// + public DomainModelUpdatedEvent(DomainModel model, IEnumerable labels, EventVerbosity verbosity, Guid correlationIdentifier) + : base(model, labels, verbosity, correlationIdentifier) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModel.DataContractName + DataContractNameVerb + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/MessageHandlerModule.cs b/example/RapidField.SolidInstruments.Example.Domain/MessageHandlerModule.cs index 31bdcd40..f80c6181 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/MessageHandlerModule.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/MessageHandlerModule.cs @@ -48,6 +48,9 @@ protected override void Configure(ServiceCollection configurator, IConfiguration configurator.AddCommandMessageListener(); configurator.AddCommandMessageListener(); configurator.AddCommandMessageListener(); + configurator.AddCommandMessageListener(); + configurator.AddCommandMessageListener(); + configurator.AddCommandMessageListener(); // Register command message transmitters. configurator.AddCommandMessageTransmitter(); @@ -56,6 +59,9 @@ protected override void Configure(ServiceCollection configurator, IConfiguration configurator.AddCommandMessageTransmitter(); configurator.AddCommandMessageTransmitter(); configurator.AddCommandMessageTransmitter(); + configurator.AddCommandMessageTransmitter(); + configurator.AddCommandMessageTransmitter(); + configurator.AddCommandMessageTransmitter(); // Register event message listeners. configurator.AddEventMessageListener(); @@ -64,6 +70,9 @@ protected override void Configure(ServiceCollection configurator, IConfiguration configurator.AddEventMessageListener(); configurator.AddEventMessageListener(); configurator.AddEventMessageListener(); + configurator.AddEventMessageListener(); + configurator.AddEventMessageListener(); + configurator.AddEventMessageListener(); // Register event message transmitters. configurator.AddEventMessageTransmitter(); @@ -72,6 +81,9 @@ protected override void Configure(ServiceCollection configurator, IConfiguration configurator.AddEventMessageTransmitter(); configurator.AddEventMessageTransmitter(); configurator.AddEventMessageTransmitter(); + configurator.AddEventMessageTransmitter(); + configurator.AddEventMessageTransmitter(); + configurator.AddEventMessageTransmitter(); // Register request message listeners. configurator.AddPingRequestMessageListener(); diff --git a/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/CreateDomainModelCommandMessage.cs b/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/CreateDomainModelCommandMessage.cs new file mode 100644 index 00000000..f127ac7c --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/CreateDomainModelCommandMessage.cs @@ -0,0 +1,53 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelCommand = RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment.CreateDomainModelCommand; +using ReportedEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelCreatedEvent; +using ReportedEventMessage = RapidField.SolidInstruments.Example.Domain.Messages.Event.ModelState.UserRoleAssignment.DomainModelCreatedEventMessage; + +namespace RapidField.SolidInstruments.Example.Domain.Messages.Command.ModelState.UserRoleAssignment +{ + using DomainModelCommandMessage = Messaging.CommandMessages.CreateDomainModelCommandMessage; + + /// + /// Represents a message that contains a command to create a . + /// + [DataContract(Name = DataContractName)] + public sealed class CreateDomainModelCommandMessage : DomainModelCommandMessage + { + /// + /// Initializes a new instance of the class. + /// + public CreateDomainModelCommandMessage() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The associated command. + /// + /// + /// is . + /// + public CreateDomainModelCommandMessage(DomainModelCommand commandObject) + : base(commandObject) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModelCommand.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/DeleteDomainModelCommandMessage.cs b/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/DeleteDomainModelCommandMessage.cs new file mode 100644 index 00000000..caa34339 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/DeleteDomainModelCommandMessage.cs @@ -0,0 +1,53 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelCommand = RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment.DeleteDomainModelCommand; +using ReportedEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelDeletedEvent; +using ReportedEventMessage = RapidField.SolidInstruments.Example.Domain.Messages.Event.ModelState.UserRoleAssignment.DomainModelDeletedEventMessage; + +namespace RapidField.SolidInstruments.Example.Domain.Messages.Command.ModelState.UserRoleAssignment +{ + using DomainModelCommandMessage = Messaging.CommandMessages.DeleteDomainModelCommandMessage; + + /// + /// Represents a message that contains a command to delete a . + /// + [DataContract(Name = DataContractName)] + public sealed class DeleteDomainModelCommandMessage : DomainModelCommandMessage + { + /// + /// Initializes a new instance of the class. + /// + public DeleteDomainModelCommandMessage() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The associated command. + /// + /// + /// is . + /// + public DeleteDomainModelCommandMessage(DomainModelCommand commandObject) + : base(commandObject) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModelCommand.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/UpdateDomainModelCommandMessage.cs b/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/UpdateDomainModelCommandMessage.cs new file mode 100644 index 00000000..8238e423 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Messages/Command/ModelState/UserRoleAssignment/UpdateDomainModelCommandMessage.cs @@ -0,0 +1,53 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelCommand = RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRoleAssignment.UpdateDomainModelCommand; +using ReportedEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelUpdatedEvent; +using ReportedEventMessage = RapidField.SolidInstruments.Example.Domain.Messages.Event.ModelState.UserRoleAssignment.DomainModelUpdatedEventMessage; + +namespace RapidField.SolidInstruments.Example.Domain.Messages.Command.ModelState.UserRoleAssignment +{ + using DomainModelCommandMessage = Messaging.CommandMessages.UpdateDomainModelCommandMessage; + + /// + /// Represents a message that contains a command to update a . + /// + [DataContract(Name = DataContractName)] + public sealed class UpdateDomainModelCommandMessage : DomainModelCommandMessage + { + /// + /// Initializes a new instance of the class. + /// + public UpdateDomainModelCommandMessage() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The associated command. + /// + /// + /// is . + /// + public UpdateDomainModelCommandMessage(DomainModelCommand commandObject) + : base(commandObject) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModelCommand.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelCreatedEventMessage.cs b/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelCreatedEventMessage.cs new file mode 100644 index 00000000..8e36cd21 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelCreatedEventMessage.cs @@ -0,0 +1,51 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelCreatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Messages.Event.ModelState.UserRoleAssignment +{ + using DomainModelEventMessage = Messaging.EventMessages.DomainModelCreatedEventMessage; + + /// + /// Represents a message that provides notification about the creation of a . + /// + [DataContract(Name = DataContractName)] + public sealed class DomainModelCreatedEventMessage : DomainModelEventMessage + { + /// + /// Initializes a new instance of the class. + /// + public DomainModelCreatedEventMessage() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The associated event. + /// + /// + /// is . + /// + public DomainModelCreatedEventMessage(DomainModelEvent eventObject) + : base(eventObject) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModelEvent.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelDeletedEventMessage.cs b/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelDeletedEventMessage.cs new file mode 100644 index 00000000..38ed025d --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelDeletedEventMessage.cs @@ -0,0 +1,51 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelDeletedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Messages.Event.ModelState.UserRoleAssignment +{ + using DomainModelEventMessage = Messaging.EventMessages.DomainModelDeletedEventMessage; + + /// + /// Represents a message that provides notification about the deletion of a . + /// + [DataContract(Name = DataContractName)] + public sealed class DomainModelDeletedEventMessage : DomainModelEventMessage + { + /// + /// Initializes a new instance of the class. + /// + public DomainModelDeletedEventMessage() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The associated event. + /// + /// + /// is . + /// + public DomainModelDeletedEventMessage(DomainModelEvent eventObject) + : base(eventObject) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModelEvent.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelUpdatedEventMessage.cs b/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelUpdatedEventMessage.cs new file mode 100644 index 00000000..7d03da9d --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Messages/Event/ModelState/UserRoleAssignment/DomainModelUpdatedEventMessage.cs @@ -0,0 +1,51 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; +using DomainModelEvent = RapidField.SolidInstruments.Example.Domain.Events.ModelState.UserRoleAssignment.DomainModelUpdatedEvent; + +namespace RapidField.SolidInstruments.Example.Domain.Messages.Event.ModelState.UserRoleAssignment +{ + using DomainModelEventMessage = Messaging.EventMessages.DomainModelUpdatedEventMessage; + + /// + /// Represents a message that provides notification about an update to a . + /// + [DataContract(Name = DataContractName)] + public sealed class DomainModelUpdatedEventMessage : DomainModelEventMessage + { + /// + /// Initializes a new instance of the class. + /// + public DomainModelUpdatedEventMessage() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The associated event. + /// + /// + /// is . + /// + public DomainModelUpdatedEventMessage(DomainModelEvent eventObject) + : base(eventObject) + { + return; + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String DataContractName = DomainModelEvent.DataContractName + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/User/AggregateDataAccessModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/User/AggregateDataAccessModel.cs index ab9fe597..4dfac9ff 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/User/AggregateDataAccessModel.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/User/AggregateDataAccessModel.cs @@ -3,11 +3,13 @@ // ================================================================================================================================= using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Diagnostics; using System.Runtime.Serialization; using AssociatedDomainModel = RapidField.SolidInstruments.Example.Domain.Models.User.DomainModel; +using UserRoleAssignmentModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.AggregateDataAccessModel; namespace RapidField.SolidInstruments.Example.Domain.Models.User { @@ -40,6 +42,23 @@ public String PasswordHash set; } + /// + /// Gets a collection of user roles which are assigned to the current . + /// + [DataMember] + public ICollection UserRoleAssignments + { + get + { + if (UserRoleAssignmentsValue is null) + { + UserRoleAssignmentsValue = new List(); + } + + return UserRoleAssignmentsValue; + } + } + /// /// Represents the name that is used when representing this type as a database entity. /// @@ -51,5 +70,12 @@ public String PasswordHash /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] private const String DataContractName = TableName + nameof(AggregateDataAccessModel); + + /// + /// Represents a collection of user roles which are assigned to the current . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [IgnoreDataMember] + private List UserRoleAssignmentsValue; } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.cs index 78c649f9..3d626f8d 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/User/DomainModel.cs @@ -10,6 +10,7 @@ using System.Diagnostics; using System.Runtime.Serialization; using BaseDomainModel = RapidField.SolidInstruments.Core.Domain.GlobalIdentityDomainModel; +using UserRoleAssignmentModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; namespace RapidField.SolidInstruments.Example.Domain.Models.User { @@ -98,11 +99,28 @@ public String PasswordHash set => PasswordHashValue = value.RejectIf().IsNullOrEmpty(nameof(PasswordHash)).OrIf().LengthIsGreaterThan(PasswordHashValueMaximumLength, nameof(PasswordHash)); } + /// + /// Gets a collection of user roles which are assigned to the current . + /// + [DataMember] + public ICollection UserRoleAssignments + { + get + { + if (UserRoleAssignmentsValue is null) + { + UserRoleAssignmentsValue = new List(); + } + + return UserRoleAssignmentsValue; + } + } + /// /// Represents the name that is used when representing this type in serialization and transport contexts. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - internal const String DataContractName = nameof(User); + public const String DataContractName = nameof(User); /// /// Represents the maximum email address string length for instances. @@ -143,6 +161,13 @@ public String PasswordHash [IgnoreDataMember] private String PasswordHashValue; + /// + /// Represents a collection of user roles which are assigned to the current . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [IgnoreDataMember] + private List UserRoleAssignmentsValue; + /// /// Contains a collection of known instances. /// @@ -195,7 +220,7 @@ private static String GetPasswordHash(String plaintextPassword) /// /// Gets the Tom Smith user. /// - public static DomainModel TomSmith => new DomainModel(Guid.Parse("01b7e51c-95e1-4eb1-aba6-1db0657a0fa3")) + public static DomainModel TomSmith => new DomainModel(Guid.Parse("3d46470a-1c90-4e94-bc5c-3cbde44ba6ac")) { EmailAddress = "tom.smith@example.com", Name = "Tom Smith", diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/User/IAggregateDomainModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/User/IAggregateDomainModel.cs index 47505b49..545c52e3 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/User/IAggregateDomainModel.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/User/IAggregateDomainModel.cs @@ -4,7 +4,9 @@ using RapidField.SolidInstruments.Core; using System; +using System.Collections.Generic; using IBaseDomainModel = RapidField.SolidInstruments.Core.Domain.IGlobalIdentityAggregateDomainModel; +using UserRoleAssignmentModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; namespace RapidField.SolidInstruments.Example.Domain.Models.User { @@ -66,5 +68,13 @@ public interface IAggregateDomainModel : IAggregateModel, IBaseDomainModel, IVal get; set; } + + /// + /// Gets a collection of user roles which are assigned to the current . + /// + public ICollection UserRoleAssignments + { + get; + } } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.cs index c714c64f..b10fe6c2 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.cs +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRole/DomainModel.cs @@ -82,7 +82,7 @@ public String Name /// Represents the name that is used when representing this type in serialization and transport contexts. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - internal const String DataContractName = nameof(UserRole); + public const String DataContractName = nameof(UserRole); /// /// Represents the maximum description string length for instances. diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/AggregateDataAccessModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/AggregateDataAccessModel.cs new file mode 100644 index 00000000..90451b25 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/AggregateDataAccessModel.cs @@ -0,0 +1,89 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics; +using System.Runtime.Serialization; +using UserModel = RapidField.SolidInstruments.Example.Domain.Models.User.AggregateDataAccessModel; +using UserRoleModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.AggregateDataAccessModel; + +namespace RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment +{ + /// + /// Represents the assignment of a single user role to a single user. + /// + [DataContract(Name = DataContractName)] + [Table(TableName)] + public sealed class AggregateDataAccessModel : ValueDataAccessModel, IAggregateModel + { + /// + /// Initializes a new instance of the class. + /// + public AggregateDataAccessModel() + : base() + { + return; + } + + /// + /// Gets or sets the user to which a user role is assigned. + /// + [ForeignKey(nameof(UserIdentifier))] + [IgnoreDataMember] + public UserModel User + { + get; + set; + } + + /// + /// Gets or sets a value that uniquely identifies the user to which a user role is assigned. + /// + [Column] + [DataMember] + [Required] + public Guid UserIdentifier + { + get; + set; + } + + /// + /// Gets or sets the user role that is a assigned to a user. + /// + [ForeignKey(nameof(UserRoleIdentifier))] + [IgnoreDataMember] + public UserRoleModel UserRole + { + get; + set; + } + + /// + /// Gets or sets a value that uniquely identifies the user role that is assigned to a user. + /// + [Column] + [DataMember] + [Required] + public Guid UserRoleIdentifier + { + get; + set; + } + + /// + /// Represents the name that is used when representing this type as a database entity. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal new const String TableName = ValueDataAccessModel.TableName; + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String DataContractName = TableName + nameof(AggregateDataAccessModel); + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/DomainModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/DomainModel.cs new file mode 100644 index 00000000..9c890b6a --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/DomainModel.cs @@ -0,0 +1,125 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using BaseDomainModel = RapidField.SolidInstruments.Core.Domain.GlobalIdentityDomainModel; +using UserModel = RapidField.SolidInstruments.Example.Domain.Models.User.DomainModel; +using UserRoleModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment +{ + /// + /// Represents the assignment of a single user role to a single user. + /// + [DataContract(Name = DataContractName)] + public sealed class DomainModel : BaseDomainModel, IAggregateDomainModel + { + /// + /// Initializes a new instance of the class. + /// + public DomainModel() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the domain model. + /// + [DebuggerHidden] + internal DomainModel(Guid identifier) + : base(identifier) + { + return; + } + + /// + /// Gets the user to which a user role is assigned. + /// + [IgnoreDataMember] + public UserModel User + { + get; + internal set; + } + + /// + /// Gets or sets a value that uniquely identifies the user to which a user role is assigned. + /// + [DataMember] + public Guid UserIdentifier + { + get => User?.Identifier ?? Guid.Empty; + set => User = new UserModel(value); + } + + /// + /// Gets the user role that is a assigned to a user. + /// + [IgnoreDataMember] + public UserRoleModel UserRole + { + get; + internal set; + } + + /// + /// Gets or sets a value that uniquely identifies the user role that is assigned to a user. + /// + [DataMember] + public Guid UserRoleIdentifier + { + get => UserRole?.Identifier ?? Guid.Empty; + set => UserRole = new UserRoleModel(value); + } + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public const String DataContractName = nameof(UserRoleAssignment); + + /// + /// Contains a collection of known instances. + /// + public static class Named + { + /// + /// Returns a collection of all known instances. + /// + /// + /// A collection of all known instances. + /// + public static IEnumerable All() => new DomainModel[] + { + StevenCallahanSystemAdministrator, + TomSmithEndUser + }; + + /// + /// Gets the system administrator role assignment for Steven Callahan. + /// + public static DomainModel StevenCallahanSystemAdministrator => new DomainModel(Guid.Parse("3af59674-efe9-46ad-b8b3-847e1a74c53c")) + { + User = UserModel.Named.StevenCallahan, + UserRole = UserRoleModel.Named.SystemAdministrator + }; + + /// + /// Gets the end user role assignment for Tom Smith. + /// + public static DomainModel TomSmithEndUser => new DomainModel(Guid.Parse("472ceca5-e06b-4ae7-8022-ecb160822137")) + { + User = UserModel.Named.TomSmith, + UserRole = UserRoleModel.Named.EndUser + }; + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IAggregateDomainModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IAggregateDomainModel.cs new file mode 100644 index 00000000..da8c7451 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IAggregateDomainModel.cs @@ -0,0 +1,32 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using IBaseDomainModel = RapidField.SolidInstruments.Core.Domain.IGlobalIdentityAggregateDomainModel; +using UserModel = RapidField.SolidInstruments.Example.Domain.Models.User.DomainModel; +using UserRoleModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment +{ + /// + /// Represents the assignment of a single user role to a single user. + /// + public interface IAggregateDomainModel : IAggregateModel, IBaseDomainModel, IValueDomainModel + { + /// + /// Gets the user to which a user role is assigned. + /// + public UserModel User + { + get; + } + + /// + /// Gets the user role that is a assigned to a user. + /// + public UserRoleModel UserRole + { + get; + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IAggregateModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IAggregateModel.cs new file mode 100644 index 00000000..965ad447 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IAggregateModel.cs @@ -0,0 +1,30 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; + +namespace RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment +{ + /// + /// Represents the assignment of a single user role to a single user. + /// + public interface IAggregateModel : IValueModel + { + /// + /// Gets a value that uniquely identifies the user to which a user role is assigned. + /// + public Guid UserIdentifier + { + get; + } + + /// + /// Gets a value that uniquely identifies the user role that is assigned to a user. + /// + public Guid UserRoleIdentifier + { + get; + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IValueDomainModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IValueDomainModel.cs new file mode 100644 index 00000000..20cff252 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IValueDomainModel.cs @@ -0,0 +1,15 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using IBaseDomainModel = RapidField.SolidInstruments.Core.Domain.IGlobalIdentityValueDomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment +{ + /// + /// Represents the assignment of a single user role to a single user. + /// + public interface IValueDomainModel : IBaseDomainModel, IValueModel + { + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IValueModel.cs.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IValueModel.cs.cs new file mode 100644 index 00000000..2220f4df --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/IValueModel.cs.cs @@ -0,0 +1,15 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Core; + +namespace RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment +{ + /// + /// Represents the assignment of a single user role to a single user. + /// + public interface IValueModel : IGlobalIdentityModel + { + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/ValueDataAccessModel.cs b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/ValueDataAccessModel.cs new file mode 100644 index 00000000..43dab289 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Models/UserRoleAssignment/ValueDataAccessModel.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 System; +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics; +using System.Runtime.Serialization; +using AssociatedDomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment +{ + using BaseDataAccessModel = DataAccess.EntityFramework.EntityFrameworkGlobalIdentityDataAccessModel; + + /// + /// Represents the assignment of a single user role to a single user. + /// + [DataContract(Name = DataContractName)] + [Table(TableName)] + public class ValueDataAccessModel : BaseDataAccessModel, IValueModel + { + /// + /// Initializes a new instance of the class. + /// + public ValueDataAccessModel() + : base() + { + return; + } + + /// + /// Represents the name that is used when representing this type as a database entity. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal const String TableName = AssociatedDomainModel.DataContractName; + + /// + /// Represents the name that is used when representing this type in serialization and transport contexts. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String DataContractName = TableName + nameof(ValueDataAccessModel); + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/RapidField.SolidInstruments.Example.Domain.csproj b/example/RapidField.SolidInstruments.Example.Domain/RapidField.SolidInstruments.Example.Domain.csproj index f1908787..4ebef701 100644 --- a/example/RapidField.SolidInstruments.Example.Domain/RapidField.SolidInstruments.Example.Domain.csproj +++ b/example/RapidField.SolidInstruments.Example.Domain/RapidField.SolidInstruments.Example.Domain.csproj @@ -32,12 +32,4 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - - - - - - - - \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Repositories/UserRoleAssignment/AggregateModelRepository.cs b/example/RapidField.SolidInstruments.Example.Domain/Repositories/UserRoleAssignment/AggregateModelRepository.cs new file mode 100644 index 00000000..8be935aa --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Repositories/UserRoleAssignment/AggregateModelRepository.cs @@ -0,0 +1,37 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.EntityFrameworkCore; +using RapidField.SolidInstruments.DataAccess.EntityFramework; +using System; +using DataAccessModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.AggregateDataAccessModel; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Repositories.UserRoleAssignment +{ + /// + /// Performs data access operations for the type. + /// + /// + /// The type of the database session for the repository. + /// + public class AggregateModelRepository : EntityFrameworkGlobalIdentityRepository + where TContext : DbContext + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The database session for the repository. + /// + /// + /// is . + /// + public AggregateModelRepository(TContext context) + : base(context) + { + return; + } + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Repositories/UserRoleAssignment/ValueModelRepository.cs b/example/RapidField.SolidInstruments.Example.Domain/Repositories/UserRoleAssignment/ValueModelRepository.cs new file mode 100644 index 00000000..0ea6ff0d --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Repositories/UserRoleAssignment/ValueModelRepository.cs @@ -0,0 +1,37 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.EntityFrameworkCore; +using RapidField.SolidInstruments.DataAccess.EntityFramework; +using System; +using DataAccessModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.ValueDataAccessModel; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRoleAssignment.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Repositories.UserRoleAssignment +{ + /// + /// Performs data access operations for the type. + /// + /// + /// The type of the database session for the repository. + /// + public class ValueModelRepository : EntityFrameworkGlobalIdentityRepository + where TContext : DbContext + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The database session for the repository. + /// + /// + /// is . + /// + public ValueModelRepository(TContext context) + : base(context) + { + return; + } + } +} \ No newline at end of file diff --git a/psakefile.ps1 b/psakefile.ps1 index 8ede2e1b..16c55123 100644 --- a/psakefile.ps1 +++ b/psakefile.ps1 @@ -39,12 +39,12 @@ 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-ExampleServiceApplication-Debug, Start-ExampleWebApplication-Debug; -Task Start-All-Release -Alias sar -Depends Stop-All, Start-ExampleServiceApplication-Release, Start-ExampleWebApplication-Release; -Task Start-ExampleServiceApplication-Debug -Alias sesad -Depends Build-Debug -Action { StartExampleServiceApplicationDebug; }; -Task Start-ExampleServiceApplication-Release -Alias sesar -Depends Build-Release -Action { StartExampleServiceApplicationRelease; }; -Task Start-ExampleWebApplication-Debug -Alias sewad -Depends Build-Debug -Action { StartExampleWebApplicationDebug; }; -Task Start-ExampleWebApplication-Release -Alias sewar -Depends Build-Release -Action { StartExampleWebApplicationRelease; }; +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-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 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.Core/AssemblyAttributes.cs b/src/RapidField.SolidInstruments.Core/AssemblyAttributes.cs index bb5a51ec..8e2e88ce 100644 --- a/src/RapidField.SolidInstruments.Core/AssemblyAttributes.cs +++ b/src/RapidField.SolidInstruments.Core/AssemblyAttributes.cs @@ -8,4 +8,6 @@ [assembly: InternalsVisibleTo("RapidField.SolidInstruments.Collections.UnitTests")] [assembly: InternalsVisibleTo("RapidField.SolidInstruments.Core.UnitTests")] [assembly: InternalsVisibleTo("RapidField.SolidInstruments.Cryptography")] +[assembly: InternalsVisibleTo("RapidField.SolidInstruments.DataAccess")] +[assembly: InternalsVisibleTo("RapidField.SolidInstruments.DataAccess.EntityFramework")] [assembly: InternalsVisibleTo("RapidField.SolidInstruments.ObjectComposition")] \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Core/Model.cs b/src/RapidField.SolidInstruments.Core/Model.cs index e1f387d9..2ca6546c 100644 --- a/src/RapidField.SolidInstruments.Core/Model.cs +++ b/src/RapidField.SolidInstruments.Core/Model.cs @@ -2,8 +2,14 @@ // Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ================================================================================================================================= +using RapidField.SolidInstruments.Core.ArgumentValidation; using RapidField.SolidInstruments.Core.Extensions; using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; using System.Runtime.Serialization; namespace RapidField.SolidInstruments.Core @@ -322,5 +328,132 @@ public Boolean Equals(IModel other) /// A string representation of the current . /// public override String ToString() => Convert.ToBase64String(GetHashCode().ToByteArray()); + + /// + /// Copies the state of the specified source model to the specified target model. + /// + /// + /// The model from which state is derived. + /// + /// + /// The model to which state is copied. + /// + /// + /// is -or- is + /// . + /// + [DebuggerHidden] + internal static void HydrateModel(IModel sourceModel, IModel targetModel) + { + var sourceModelType = sourceModel.RejectIf().IsNull(nameof(sourceModel)).TargetArgument.GetType(); + var targetModelType = targetModel.RejectIf().IsNull(nameof(targetModel)).TargetArgument.GetType(); + var sourceModelProperties = sourceModelType.GetProperties(PropertyBindingFlags).ToDictionary(property => property.Name, property => property); + var targetModelProperties = targetModelType.GetProperties(PropertyBindingFlags).ToDictionary(property => property.Name, property => property); + + foreach (var sourcePropertyElement in sourceModelProperties) + { + var propertyName = sourcePropertyElement.Key; + var sourceProperty = sourcePropertyElement.Value; + var sourcePropertyValue = sourceProperty.CanRead ? sourceProperty.GetValue(sourceModel) : null; + var sourcePropertyValueType = sourcePropertyValue?.GetType() ?? sourceProperty.PropertyType; + + if (targetModelProperties.ContainsKey(propertyName)) + { + var targetProperty = targetModelProperties[propertyName]; + var targetPropertyValue = targetProperty.CanRead ? targetProperty.GetValue(targetModel) : null; + var targetPropertyValueType = targetPropertyValue?.GetType() ?? targetProperty.PropertyType; + + if (targetProperty.CanWrite && targetPropertyValueType == sourcePropertyValueType && targetPropertyValue != sourcePropertyValue) + { + targetProperty.SetValue(targetModel, sourcePropertyValue); + } + else if (sourcePropertyValue is null) + { + continue; + } + else if (ModelInterfaceType.IsAssignableFrom(sourcePropertyValueType) && ModelInterfaceType.IsAssignableFrom(targetPropertyValueType)) + { + if (targetPropertyValue is null) + { + targetPropertyValue = targetPropertyValueType.GetConstructor(Array.Empty())?.Invoke(Array.Empty()); + } + + if (sourcePropertyValue is IModel sourcePropertyModel && targetPropertyValue is IModel targetPropertyModel) + { + HydrateModel(sourcePropertyModel, targetPropertyModel); + + if (targetProperty.CanWrite) + { + targetProperty.SetValue(targetModel, targetPropertyModel); + } + } + } + else if (CollectionInterfaceType.IsAssignableFrom(sourcePropertyValueType) && CollectionInterfaceType.IsAssignableFrom(targetPropertyValueType)) + { + var sourceCollectionGenericInterfaceType = sourcePropertyValueType.GetInterfaces().FirstOrDefault(interfaceType => interfaceType.Name == CollectionGenericInterfaceType.Name && interfaceType.IsGenericType); + var sourceCollectionElementType = sourceCollectionGenericInterfaceType?.GetGenericArguments()[0]; + var targetCollectionGenericInterfaceType = targetPropertyValueType.GetInterfaces().FirstOrDefault(interfaceType => interfaceType.Name == CollectionGenericInterfaceType.Name && interfaceType.IsGenericType); + var targetCollectionElementType = targetCollectionGenericInterfaceType?.GetGenericArguments()[0]; + + if (sourceCollectionElementType is null || targetCollectionElementType is null) + { + continue; + } + else if (ModelInterfaceType.IsAssignableFrom(sourceCollectionElementType) && ModelInterfaceType.IsAssignableFrom(targetCollectionElementType)) + { + var sourceCollection = sourcePropertyValue as ICollection; + var targetCollection = targetPropertyValue as ICollection ?? targetPropertyValueType.GetConstructor(Array.Empty())?.Invoke(Array.Empty()) as ICollection; + + if (sourceCollection.IsNullOrEmpty() || targetCollection is null) + { + continue; + } + + foreach (var sourceCollectionElement in sourceCollection) + { + if (sourceCollectionElement is null) + { + continue; + } + else if (targetCollectionElementType.GetConstructor(Array.Empty())?.Invoke(Array.Empty()) is IModel targetCollectionElement) + { + HydrateModel(sourceCollectionElement, targetCollectionElement); + targetCollection.Add(targetCollectionElement); + } + } + + if (targetProperty.CanWrite) + { + targetProperty.SetValue(targetModel, targetCollection); + } + } + } + } + } + } + + /// + /// Represents binding flags that are used to find public instance properties of a model. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const BindingFlags PropertyBindingFlags = BindingFlags.Instance | BindingFlags.Public; + + /// + /// Represents the type. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private static readonly Type CollectionGenericInterfaceType = typeof(ICollection<>); + + /// + /// Represents the type. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private static readonly Type CollectionInterfaceType = typeof(ICollection); + + /// + /// Represents the type. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private static readonly Type ModelInterfaceType = typeof(IModel); } } \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.DataAccess.EntityFramework/DataAccessModelConfiguration.cs b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/DataAccessModelConfiguration.cs new file mode 100644 index 00000000..d7b7f9d8 --- /dev/null +++ b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/DataAccessModelConfiguration.cs @@ -0,0 +1,119 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.Extensions.Configuration; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using System; +using System.Diagnostics; + +namespace RapidField.SolidInstruments.DataAccess.EntityFramework +{ + /// + /// Encapsulates entity type configuration for an . + /// + /// + /// is the default implementation of + /// . + /// + /// + /// The type of the unique primary identifier for the model. + /// + /// + /// The type of the data access model. + /// + public abstract class DataAccessModelConfiguration : DataAccessModelConfiguration, IDataAccessModelConfiguration + where TIdentifier : IComparable, IComparable, IEquatable + where TDataAccessModel : class, IDataAccessModel + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + protected DataAccessModelConfiguration(IConfiguration applicationConfiguration) + : base(applicationConfiguration) + { + return; + } + + /// + /// Configures the entity. + /// + /// + /// The builder that is used to configure the entity. + /// + /// + /// Configuration information for the application. + /// + protected override void Configure(EntityTypeBuilder builder, IConfiguration applicationConfiguration) => builder.HasKey(model => model.Identifier); + + /// + /// Represents the type of the value that uniquely identifies the data access model. + /// + protected static Type DataAccessModelIdentifierType = typeof(TIdentifier); + } + + /// + /// Encapsulates entity type configuration for an . + /// + /// + /// is the default implementation of + /// . + /// + /// + /// The type of the data access model. + /// + public abstract class DataAccessModelConfiguration : IDataAccessModelConfiguration + where TDataAccessModel : class, IDataAccessModel + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + protected DataAccessModelConfiguration(IConfiguration applicationConfiguration) + { + ApplicationConfiguration = applicationConfiguration.RejectIf().IsNull(nameof(applicationConfiguration)).TargetArgument; + } + + /// + /// Configures the entity. + /// + /// + /// The builder that is used to configure the entity. + /// + public void Configure(EntityTypeBuilder builder) => Configure(builder, ApplicationConfiguration); + + /// + /// Configures the entity. + /// + /// + /// The builder that is used to configure the entity. + /// + /// + /// Configuration information for the application. + /// + protected abstract void Configure(EntityTypeBuilder builder, IConfiguration applicationConfiguration); + + /// + /// Represents the type of the data access model. + /// + protected static Type DataAccessModelType = typeof(TDataAccessModel); + + /// + /// Represents configuration information for the application. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly IConfiguration ApplicationConfiguration; + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.DataAccess.EntityFramework/EntityFrameworkDataAccessModel.cs b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/EntityFrameworkDataAccessModel.cs index c033b760..dbb40554 100644 --- a/src/RapidField.SolidInstruments.DataAccess.EntityFramework/EntityFrameworkDataAccessModel.cs +++ b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/EntityFrameworkDataAccessModel.cs @@ -8,9 +8,6 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Diagnostics; -using System.Linq; -using System.Reflection; using System.Runtime.Serialization; namespace RapidField.SolidInstruments.DataAccess.EntityFramework @@ -101,51 +98,6 @@ public TDomainModel ToDomainModel() throw new TypeInitializationException(typeof(TDomainModel).FullName, exception); } } - - /// - /// Copies the state of the specified source model to the specified target model. - /// - /// - /// The model from which state is derived. - /// - /// - /// The model to which state is copied. - /// - /// - /// is -or- is - /// . - /// - [DebuggerHidden] - private static void HydrateModel(IModel sourceModel, IModel targetModel) - { - var sourceModelType = sourceModel.RejectIf().IsNull(nameof(sourceModel)).TargetArgument.GetType(); - var targetModelType = targetModel.RejectIf().IsNull(nameof(targetModel)).TargetArgument.GetType(); - var sourceModelProperties = sourceModelType.GetProperties(PropertyBindingFlags).ToDictionary(property => property.Name, property => property); - var targetModelProperties = targetModelType.GetProperties(PropertyBindingFlags).ToDictionary(property => property.Name, property => property); - - foreach (var sourcePropertyElement in sourceModelProperties) - { - var propertyName = sourcePropertyElement.Key; - var sourcePropertyValue = sourcePropertyElement.Value.CanRead ? sourcePropertyElement.Value.GetValue(sourceModel) : null; - - if (targetModelProperties.ContainsKey(propertyName) && (sourcePropertyValue is null) == false) - { - var targetProperty = targetModelProperties[propertyName]; - var sourcePropertyValueType = sourcePropertyValue.GetType(); - - if (targetProperty.CanWrite && targetProperty.PropertyType == sourcePropertyValueType) - { - targetProperty.SetValue(targetModel, sourcePropertyValue); - } - } - } - } - - /// - /// Represents binding flags that are used to find public instance properties of a model. - /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private const BindingFlags PropertyBindingFlags = BindingFlags.Instance | BindingFlags.Public; } /// diff --git a/src/RapidField.SolidInstruments.DataAccess.EntityFramework/EntityFrameworkRepository.cs b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/EntityFrameworkRepository.cs index 7d3a4aba..f6fee607 100644 --- a/src/RapidField.SolidInstruments.DataAccess.EntityFramework/EntityFrameworkRepository.cs +++ b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/EntityFrameworkRepository.cs @@ -136,7 +136,11 @@ public EntityFrameworkRepository(TContext context) /// /// A token that represents and manages contextual thread safety. /// - protected override void Add(TEntity entity, IConcurrencyControlToken controlToken) => Set.Add(entity); + protected override void Add(TEntity entity, IConcurrencyControlToken controlToken) + { + Set.Attach(entity); + Set.Add(entity); + } /// /// Adds the specified entities to the current . @@ -147,7 +151,11 @@ public EntityFrameworkRepository(TContext context) /// /// A token that represents and manages contextual thread safety. /// - protected override void AddRange(IEnumerable entities, IConcurrencyControlToken controlToken) => Set.AddRange(entities); + protected override void AddRange(IEnumerable entities, IConcurrencyControlToken controlToken) + { + Set.AttachRange(entities); + Set.AddRange(entities); + } /// /// Returns all entities from the current . @@ -158,7 +166,7 @@ public EntityFrameworkRepository(TContext context) /// /// All entities within the current . /// - protected override IQueryable All(IConcurrencyControlToken controlToken) => Set.AsQueryable(); + protected override IQueryable All(IConcurrencyControlToken controlToken) => ReadQuery; /// /// Determines whether or not any entities matching the specified predicate exist in the current @@ -174,7 +182,22 @@ public EntityFrameworkRepository(TContext context) /// if any entities matching the specified predicate exist in the current /// , otherwise . /// - protected override Boolean AnyWhere(Expression> predicate, IConcurrencyControlToken controlToken) => Set.AsNoTracking().Any(predicate); + protected override Boolean AnyWhere(Expression> predicate, IConcurrencyControlToken controlToken) => UntrackedQuery.Any(predicate); + + /// + /// Configures the specified read query for eager loading. + /// + /// + /// When not overridden by a derived class, no eager loading is performed. Explicit loading must be configured by consuming + /// classes. + /// + /// + /// The query to configure. + /// + /// + /// The resulting query. + /// + protected virtual IQueryable ConfigureEagerLoading(IQueryable query) => TrackedQuery; /// /// Determines whether or not the specified entity exists in the current @@ -228,7 +251,7 @@ protected override Boolean Contains(TEntity entity, IConcurrencyControlToken con /// /// The number of entities in the current . /// - protected override Int64 Count(IConcurrencyControlToken controlToken) => Set.AsNoTracking().Count(); + protected override Int64 Count(IConcurrencyControlToken controlToken) => UntrackedQuery.Count(); /// /// Returns the number of entities matching the specified predicate in the current @@ -244,7 +267,7 @@ protected override Boolean Contains(TEntity entity, IConcurrencyControlToken con /// The number of entities matching the specified predicate in the current /// . /// - protected override Int64 CountWhere(Expression> predicate, IConcurrencyControlToken controlToken) => Set.AsNoTracking().Count(predicate); + protected override Int64 CountWhere(Expression> predicate, IConcurrencyControlToken controlToken) => UntrackedQuery.Count(predicate); /// /// Releases all resources consumed by the current . @@ -268,7 +291,7 @@ protected override Boolean Contains(TEntity entity, IConcurrencyControlToken con /// All entities matching the specified predicate within the current /// . /// - protected override IQueryable FindWhere(Expression> predicate, IConcurrencyControlToken controlToken) => Set.Where(predicate); + protected override IQueryable FindWhere(Expression> predicate, IConcurrencyControlToken controlToken) => ReadQuery.Where(predicate); /// /// Removes the specified entity from the current . @@ -279,7 +302,11 @@ protected override Boolean Contains(TEntity entity, IConcurrencyControlToken con /// /// A token that represents and manages contextual thread safety. /// - protected override void Remove(TEntity entity, IConcurrencyControlToken controlToken) => Set.Remove(entity); + protected override void Remove(TEntity entity, IConcurrencyControlToken controlToken) + { + Set.Attach(entity); + Set.Remove(entity); + } /// /// Removes the specified entities from the current . @@ -290,7 +317,11 @@ protected override Boolean Contains(TEntity entity, IConcurrencyControlToken con /// /// A token that represents and manages contextual thread safety. /// - protected override void RemoveRange(IEnumerable entities, IConcurrencyControlToken controlToken) => Set.RemoveRange(entities); + protected override void RemoveRange(IEnumerable entities, IConcurrencyControlToken controlToken) + { + Set.AttachRange(entities); + Set.RemoveRange(entities); + } /// /// Updates the specified entity in the current . @@ -301,7 +332,11 @@ protected override Boolean Contains(TEntity entity, IConcurrencyControlToken con /// /// A token that represents and manages contextual thread safety. /// - protected override void Update(TEntity entity, IConcurrencyControlToken controlToken) => Set.Update(entity); + protected override void Update(TEntity entity, IConcurrencyControlToken controlToken) + { + Set.Attach(entity); + Set.Update(entity); + } /// /// Updates the specified entities in the current . @@ -312,13 +347,81 @@ protected override Boolean Contains(TEntity entity, IConcurrencyControlToken con /// /// A token that represents and manages contextual thread safety. /// - protected override void UpdateRange(IEnumerable entities, IConcurrencyControlToken controlToken) => Set.UpdateRange(entities); + protected override void UpdateRange(IEnumerable entities, IConcurrencyControlToken controlToken) + { + Set.AttachRange(entities); + Set.UpdateRange(entities); + } + + /// + /// Configures the specified read query for full eager loading. + /// + /// + /// The query to configure. + /// + /// + /// The resulting query. + /// + [DebuggerHidden] + private IQueryable ConfigureFullEagerLoading(IQueryable query) + { + var navigationProperties = Context.Model.FindEntityType(EntityType).GetDerivedTypesInclusive().SelectMany(type => type.GetNavigations()).Distinct(); + + foreach (var navigationProperty in navigationProperties) + { + query = query.Include(navigationProperty.Name); + } + + return query.AsTracking(); + } + + /// + /// Configures the specified read query. + /// + /// + /// The query to configure. + /// + /// + /// The resulting query. + /// + [DebuggerHidden] + private IQueryable ConfigureReadQuery(IQueryable query) => PerformsConfiguredEagerLoading ? ConfigureEagerLoading(query) : ConfigureFullEagerLoading(query); /// /// Gets the database session type of the current . /// public Type ContextType => typeof(TContext); + /// + /// Gets a value indicating whether or not the current invokes + /// for all read queries. When , all + /// queries are configured for full eager loading. The default value is . + /// + protected virtual Boolean PerformsConfiguredEagerLoading => DefaultPerformsConfiguredEagerLoadingValue; + + /// + /// Gets a configured query that can be used for read operations. + /// + protected IQueryable ReadQuery => ConfigureReadQuery(TrackedQuery); + + /// + /// Gets a tracked query that can be used for read or write operations. + /// + protected IQueryable TrackedQuery => Set.AsTracking(); + + /// + /// Gets an untracked query that can be used for read operations. + /// + protected IQueryable UntrackedQuery => Set.AsNoTracking(); + + /// + /// Represents the default value indicating whether or not the current + /// invokes + /// for all read queries. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const Boolean DefaultPerformsConfiguredEagerLoadingValue = false; + /// /// Represents the database session for the current . /// diff --git a/src/RapidField.SolidInstruments.DataAccess.EntityFramework/IDataAccessModelConfiguration.cs b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/IDataAccessModelConfiguration.cs new file mode 100644 index 00000000..3054279d --- /dev/null +++ b/src/RapidField.SolidInstruments.DataAccess.EntityFramework/IDataAccessModelConfiguration.cs @@ -0,0 +1,35 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.EntityFrameworkCore; +using System; + +namespace RapidField.SolidInstruments.DataAccess.EntityFramework +{ + /// + /// Encapsulates entity type configuration for an . + /// + /// + /// The type of the unique primary identifier for the model. + /// + /// + /// The type of the data access model. + /// + public interface IDataAccessModelConfiguration : IDataAccessModelConfiguration + where TIdentifier : IComparable, IComparable, IEquatable + where TDataAccessModel : class, IDataAccessModel + { + } + + /// + /// Encapsulates entity type configuration for an . + /// + /// + /// The type of the data access model. + /// + public interface IDataAccessModelConfiguration : IEntityTypeConfiguration + where TDataAccessModel : class, IDataAccessModel + { + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.EventAuthoring/DomainModelAssociatedEvent.cs b/src/RapidField.SolidInstruments.EventAuthoring/DomainModelAssociatedEvent.cs index 192c0baf..bb19d709 100644 --- a/src/RapidField.SolidInstruments.EventAuthoring/DomainModelAssociatedEvent.cs +++ b/src/RapidField.SolidInstruments.EventAuthoring/DomainModelAssociatedEvent.cs @@ -181,6 +181,6 @@ public DomainModelAssociatedEvent(TModel model, IEnumerable labels, Even /// Represents the standard verb which is appended to the name that is used when representing this type in serialization and /// transport contexts. /// - protected internal const String DataContractNameVerb = "Associated"; + public const String DataContractNameVerb = "Associated"; } } \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.EventAuthoring/DomainModelCreatedEvent.cs b/src/RapidField.SolidInstruments.EventAuthoring/DomainModelCreatedEvent.cs index ce9dd6ad..d66bdd73 100644 --- a/src/RapidField.SolidInstruments.EventAuthoring/DomainModelCreatedEvent.cs +++ b/src/RapidField.SolidInstruments.EventAuthoring/DomainModelCreatedEvent.cs @@ -181,6 +181,6 @@ public DomainModelCreatedEvent(TModel model, IEnumerable labels, EventVe /// Represents the standard verb which is appended to the name that is used when representing this type in serialization and /// transport contexts. /// - protected internal const String DataContractNameVerb = "Created"; + public const String DataContractNameVerb = "Created"; } } \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.EventAuthoring/DomainModelDeletedEvent.cs b/src/RapidField.SolidInstruments.EventAuthoring/DomainModelDeletedEvent.cs index effedf98..31bb1bfb 100644 --- a/src/RapidField.SolidInstruments.EventAuthoring/DomainModelDeletedEvent.cs +++ b/src/RapidField.SolidInstruments.EventAuthoring/DomainModelDeletedEvent.cs @@ -181,6 +181,6 @@ public DomainModelDeletedEvent(TModel model, IEnumerable labels, EventVe /// Represents the standard verb which is appended to the name that is used when representing this type in serialization and /// transport contexts. /// - protected internal const String DataContractNameVerb = "Deleted"; + public const String DataContractNameVerb = "Deleted"; } } \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.EventAuthoring/DomainModelUpdatedEvent.cs b/src/RapidField.SolidInstruments.EventAuthoring/DomainModelUpdatedEvent.cs index 54094bd9..a2d6074a 100644 --- a/src/RapidField.SolidInstruments.EventAuthoring/DomainModelUpdatedEvent.cs +++ b/src/RapidField.SolidInstruments.EventAuthoring/DomainModelUpdatedEvent.cs @@ -181,6 +181,6 @@ public DomainModelUpdatedEvent(TModel model, IEnumerable labels, EventVe /// Represents the standard verb which is appended to the name that is used when representing this type in serialization and /// transport contexts. /// - protected internal const String DataContractNameVerb = "Updated"; + public const String DataContractNameVerb = "Updated"; } } \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Messaging/Service/MessagingServiceExecutor.cs b/src/RapidField.SolidInstruments.Messaging/Service/MessagingServiceExecutor.cs index 5b3cd71b..e0692402 100644 --- a/src/RapidField.SolidInstruments.Messaging/Service/MessagingServiceExecutor.cs +++ b/src/RapidField.SolidInstruments.Messaging/Service/MessagingServiceExecutor.cs @@ -207,6 +207,7 @@ protected sealed override void Execute(IDependencyScope dependencyScope, IConfig { if (RunsContinuously) { + Console.WriteLine("The service is running in continuous mode."); Console.CancelKeyPress += (sender, eventArguments) => { executionLifetime.End();