diff --git a/README.md b/README.md index 18d74de8..76331634 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ The **Solid Instruments** constituent libraries expose a wide variety of powerfu [![Service](doc/images/Label.Service.300w.png)](src/RapidField.SolidInstruments.Service/README.md) [![Signal Processing](doc/images/Label.SignalProcessing.300w.png)](src/RapidField.SolidInstruments.SignalProcessing/README.md) [![Text Encoding](doc/images/Label.TextEncoding.300w.png)](src/RapidField.SolidInstruments.TextEncoding/README.md) +[![Web](doc/images/Label.Web.300w.png)](src/RapidField.SolidInstruments.Web/README.md) ## License diff --git a/RapidField.SolidInstruments.sln b/RapidField.SolidInstruments.sln index 6b06ab85..e267d24a 100644 --- a/RapidField.SolidInstruments.sln +++ b/RapidField.SolidInstruments.sln @@ -165,6 +165,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "images", "images", "{3A9700 doc\images\Icon.Service.128w.png = doc\images\Icon.Service.128w.png doc\images\Icon.SignalProcessing.128w.png = doc\images\Icon.SignalProcessing.128w.png doc\images\Icon.TextEncoding.128w.png = doc\images\Icon.TextEncoding.128w.png + doc\images\Icon.Web.128w.png = doc\images\Icon.Web.128w.png doc\images\Label.Collections.300w.png = doc\images\Label.Collections.300w.png doc\images\Label.Command.300w.png = doc\images\Label.Command.300w.png doc\images\Label.Core.300w.png = doc\images\Label.Core.300w.png @@ -179,6 +180,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "images", "images", "{3A9700 doc\images\Label.Service.300w.png = doc\images\Label.Service.300w.png doc\images\Label.SignalProcessing.300w.png = doc\images\Label.SignalProcessing.300w.png doc\images\Label.TextEncoding.300w.png = doc\images\Label.TextEncoding.300w.png + doc\images\Label.Web.300w.png = doc\images\Label.Web.300w.png doc\images\RapidField.Logo.Color.White.Transparent.227w.png = doc\images\RapidField.Logo.Color.White.Transparent.227w.png doc\images\SolidInstruments.Logo.Color.Black.Transparent.500w.png = doc\images\SolidInstruments.Logo.Color.Black.Transparent.500w.png EndProjectSection @@ -260,6 +262,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "namespaces", "namespaces", doc\namespaces\RapidField.SolidInstruments.SignalProcessing.md = doc\namespaces\RapidField.SolidInstruments.SignalProcessing.md doc\namespaces\RapidField.SolidInstruments.TextEncoding.Extensions.md = doc\namespaces\RapidField.SolidInstruments.TextEncoding.Extensions.md doc\namespaces\RapidField.SolidInstruments.TextEncoding.md = doc\namespaces\RapidField.SolidInstruments.TextEncoding.md + doc\namespaces\RapidField.SolidInstruments.Web.Autofac.Extensions.md = doc\namespaces\RapidField.SolidInstruments.Web.Autofac.Extensions.md + doc\namespaces\RapidField.SolidInstruments.Web.Autofac.md = doc\namespaces\RapidField.SolidInstruments.Web.Autofac.md + doc\namespaces\RapidField.SolidInstruments.Web.DotNetNative.Extensions.md = doc\namespaces\RapidField.SolidInstruments.Web.DotNetNative.Extensions.md + doc\namespaces\RapidField.SolidInstruments.Web.DotNetNative.md = doc\namespaces\RapidField.SolidInstruments.Web.DotNetNative.md + doc\namespaces\RapidField.SolidInstruments.Web.md = doc\namespaces\RapidField.SolidInstruments.Web.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "templates", "templates", "{5D1D074E-456F-4CA1-A4C5-45074EDCFDA8}" @@ -407,9 +414,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RapidField.SolidInstruments EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi", "example\RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi\RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj", "{AC2D0816-3ABF-4458-80DB-E4BADDD9A2E0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RapidField.SolidInstruments.Example.Domain.Identity", "example\RapidField.SolidInstruments.Example.Domain.Identity\RapidField.SolidInstruments.Example.Domain.Identity.csproj", "{630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RapidField.SolidInstruments.Example.Domain.Identity", "example\RapidField.SolidInstruments.Example.Domain.Identity\RapidField.SolidInstruments.Example.Domain.Identity.csproj", "{630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RapidField.SolidInstruments.Example.Domain.Identity.Service", "example\RapidField.SolidInstruments.Example.Domain.Identity.Service\RapidField.SolidInstruments.Example.Domain.Identity.Service.csproj", "{352E9021-1010-4A5D-8435-F8331DA63F95}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RapidField.SolidInstruments.Example.Domain.Identity.Service", "example\RapidField.SolidInstruments.Example.Domain.Identity.Service\RapidField.SolidInstruments.Example.Domain.Identity.Service.csproj", "{352E9021-1010-4A5D-8435-F8331DA63F95}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RapidField.SolidInstruments.Web", "src\RapidField.SolidInstruments.Web\RapidField.SolidInstruments.Web.csproj", "{3F1A6F2B-B84F-44C5-9E7D-5763C82CA926}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RapidField.SolidInstruments.Web.Autofac", "src\RapidField.SolidInstruments.Web.Autofac\RapidField.SolidInstruments.Web.Autofac.csproj", "{20452BD4-3C2F-44EC-8DEB-14FD9FE8AA84}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RapidField.SolidInstruments.Web.DotNetNative", "src\RapidField.SolidInstruments.Web.DotNetNative\RapidField.SolidInstruments.Web.DotNetNative.csproj", "{6A53C072-71C8-42F1-90D9-9AE64F2848B2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -649,6 +662,18 @@ Global {352E9021-1010-4A5D-8435-F8331DA63F95}.Debug|Any CPU.Build.0 = Debug|Any CPU {352E9021-1010-4A5D-8435-F8331DA63F95}.Release|Any CPU.ActiveCfg = Release|Any CPU {352E9021-1010-4A5D-8435-F8331DA63F95}.Release|Any CPU.Build.0 = Release|Any CPU + {3F1A6F2B-B84F-44C5-9E7D-5763C82CA926}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F1A6F2B-B84F-44C5-9E7D-5763C82CA926}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F1A6F2B-B84F-44C5-9E7D-5763C82CA926}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F1A6F2B-B84F-44C5-9E7D-5763C82CA926}.Release|Any CPU.Build.0 = Release|Any CPU + {20452BD4-3C2F-44EC-8DEB-14FD9FE8AA84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {20452BD4-3C2F-44EC-8DEB-14FD9FE8AA84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {20452BD4-3C2F-44EC-8DEB-14FD9FE8AA84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {20452BD4-3C2F-44EC-8DEB-14FD9FE8AA84}.Release|Any CPU.Build.0 = Release|Any CPU + {6A53C072-71C8-42F1-90D9-9AE64F2848B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A53C072-71C8-42F1-90D9-9AE64F2848B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A53C072-71C8-42F1-90D9-9AE64F2848B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A53C072-71C8-42F1-90D9-9AE64F2848B2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -728,6 +753,9 @@ Global {AC2D0816-3ABF-4458-80DB-E4BADDD9A2E0} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} {630F6AC9-3A4C-4B8A-B55D-D44A7BFBB025} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} {352E9021-1010-4A5D-8435-F8331DA63F95} = {BEB60D41-11BB-4C6E-8F5D-1E7990A27C34} + {3F1A6F2B-B84F-44C5-9E7D-5763C82CA926} = {F58E05BE-9DC6-41B4-8324-C006F6CE7CC7} + {20452BD4-3C2F-44EC-8DEB-14FD9FE8AA84} = {F58E05BE-9DC6-41B4-8324-C006F6CE7CC7} + {6A53C072-71C8-42F1-90D9-9AE64F2848B2} = {F58E05BE-9DC6-41B4-8324-C006F6CE7CC7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {834FCFB0-DA00-4ABD-9424-6FE1398A9F6E} diff --git a/doc/images/Icon.Web.128w.png b/doc/images/Icon.Web.128w.png new file mode 100644 index 00000000..200a4778 Binary files /dev/null and b/doc/images/Icon.Web.128w.png differ diff --git a/doc/images/Label.Web.300w.png b/doc/images/Label.Web.300w.png new file mode 100644 index 00000000..5d6835ff Binary files /dev/null and b/doc/images/Label.Web.300w.png differ diff --git a/doc/namespaces/RapidField.SolidInstruments.Web.Autofac.Extensions.md b/doc/namespaces/RapidField.SolidInstruments.Web.Autofac.Extensions.md new file mode 100644 index 00000000..fbd7eb31 --- /dev/null +++ b/doc/namespaces/RapidField.SolidInstruments.Web.Autofac.Extensions.md @@ -0,0 +1,31 @@ +--- +uid: RapidField.SolidInstruments.Web.Autofac.Extensions +summary: *content +--- + + + +Exposes extensions that support the [**Autofac**](https://autofac.org/) integration for the **Solid Instruments** web application abstractions. + +
+ +![Web label](../images/Label.Web.300w.png) +- - - + +### Installation + +This library is available via [**NuGet**](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio). Use one of the commands below to download and install the library and all of its dependencies. + +###### .NET CLI + +```shell +dotnet add package RapidField.SolidInstruments.Web.Autofac +``` + +###### NuGet Package Manager + +```shell +Install-Package RapidField.SolidInstruments.Web.Autofac +``` \ No newline at end of file diff --git a/doc/namespaces/RapidField.SolidInstruments.Web.Autofac.md b/doc/namespaces/RapidField.SolidInstruments.Web.Autofac.md new file mode 100644 index 00000000..e31ecabb --- /dev/null +++ b/doc/namespaces/RapidField.SolidInstruments.Web.Autofac.md @@ -0,0 +1,39 @@ +--- +uid: RapidField.SolidInstruments.Web.Autofac +summary: *content +--- + + + +Exposes the [**Autofac**](https://autofac.org/) integration for the **Solid Instruments** web application abstractions. + +
+ +![Web label](../images/Label.Web.300w.png) +- - - + +### Installation + +This library is available via [**NuGet**](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio). Use one of the commands below to download and install the library and all of its dependencies. + +###### .NET CLI + +```shell +dotnet add package RapidField.SolidInstruments.Web.Autofac +``` + +###### NuGet Package Manager + +```shell +Install-Package RapidField.SolidInstruments.Web.Autofac +``` + +### Namespaces + +#### [RapidField.SolidInstruments.Web.Autofac.Extensions](https://www.solidinstruments.com/api/RapidField.SolidInstruments.Web.Autofac.Extensions.html) + +
+Exposes extensions that support the Autofac integration for the Solid Instruments web application abstractions. +
\ No newline at end of file diff --git a/doc/namespaces/RapidField.SolidInstruments.Web.DotNetNative.Extensions.md b/doc/namespaces/RapidField.SolidInstruments.Web.DotNetNative.Extensions.md new file mode 100644 index 00000000..ada4bad5 --- /dev/null +++ b/doc/namespaces/RapidField.SolidInstruments.Web.DotNetNative.Extensions.md @@ -0,0 +1,31 @@ +--- +uid: RapidField.SolidInstruments.Web.DotNetNative.Extensions +summary: *content +--- + + + +Exposes extensions that support the native .NET IoC integration for the **Solid Instruments** web application abstractions. + +
+ +![Web label](../images/Label.Web.300w.png) +- - - + +### Installation + +This library is available via [**NuGet**](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio). Use one of the commands below to download and install the library and all of its dependencies. + +###### .NET CLI + +```shell +dotnet add package RapidField.SolidInstruments.Web.DotNetNative +``` + +###### NuGet Package Manager + +```shell +Install-Package RapidField.SolidInstruments.Web.DotNetNative +``` \ No newline at end of file diff --git a/doc/namespaces/RapidField.SolidInstruments.Web.DotNetNative.md b/doc/namespaces/RapidField.SolidInstruments.Web.DotNetNative.md new file mode 100644 index 00000000..94886f85 --- /dev/null +++ b/doc/namespaces/RapidField.SolidInstruments.Web.DotNetNative.md @@ -0,0 +1,39 @@ +--- +uid: RapidField.SolidInstruments.Web.DotNetNative +summary: *content +--- + + + +Exposes the native .NET IoC integration for the **Solid Instruments** web application abstractions. + +
+ +![Web label](../images/Label.Web.300w.png) +- - - + +### Installation + +This library is available via [**NuGet**](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio). Use one of the commands below to download and install the library and all of its dependencies. + +###### .NET CLI + +```shell +dotnet add package RapidField.SolidInstruments.Web.DotNetNative +``` + +###### NuGet Package Manager + +```shell +Install-Package RapidField.SolidInstruments.Web.DotNetNative +``` + +### Namespaces + +#### [RapidField.SolidInstruments.Web.DotNetNative.Extensions](https://www.solidinstruments.com/api/RapidField.SolidInstruments.Web.DotNetNative.Extensions.html) + +
+Exposes extensions that support the native .NET IoC integration for the Solid Instruments web application abstractions. +
\ No newline at end of file diff --git a/doc/namespaces/RapidField.SolidInstruments.Web.md b/doc/namespaces/RapidField.SolidInstruments.Web.md new file mode 100644 index 00000000..22f5ef6b --- /dev/null +++ b/doc/namespaces/RapidField.SolidInstruments.Web.md @@ -0,0 +1,31 @@ +--- +uid: RapidField.SolidInstruments.Web +summary: *content +--- + + + +Exposes types that simplify web application design. + +
+ +![Web label](../images/Label.Web.300w.png) +- - - + +### Installation + +This library is available via [**NuGet**](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio). Use one of the commands below to download and install the library and all of its dependencies. + +###### .NET CLI + +```shell +dotnet add package RapidField.SolidInstruments.Web +``` + +###### NuGet Package Manager + +```shell +Install-Package RapidField.SolidInstruments.Web +``` \ No newline at end of file diff --git a/en-US_User.dic b/en-US_User.dic index 3b802546..87c905a9 100644 --- a/en-US_User.dic +++ b/en-US_User.dic @@ -113,6 +113,7 @@ foundational getters Gitter Glyphicons +guid Halflings hh hotfix diff --git a/example/RapidField.SolidInstruments.Example.BeaconService/ApplicationServiceExecutor.cs b/example/RapidField.SolidInstruments.Example.BeaconService/ApplicationServiceExecutor.cs index 6f6628de..739ac61d 100644 --- a/example/RapidField.SolidInstruments.Example.BeaconService/ApplicationServiceExecutor.cs +++ b/example/RapidField.SolidInstruments.Example.BeaconService/ApplicationServiceExecutor.cs @@ -2,10 +2,8 @@ // Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ================================================================================================================================= -using Microsoft.Extensions.Configuration; using RapidField.SolidInstruments.Messaging.DotNetNative.Service; using System; -using System.IO; namespace RapidField.SolidInstruments.Example.BeaconService { @@ -23,24 +21,6 @@ public ApplicationServiceExecutor() return; } - /// - /// Builds the application configuration for the service. - /// - /// - /// An object that is used to build the configuration. - /// - protected override void BuildConfiguration(IConfigurationBuilder configurationBuilder) - { - try - { - configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json"); - } - finally - { - base.BuildConfiguration(configurationBuilder); - } - } - /// /// Releases all resources consumed by the current . /// diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyModule.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyModule.cs new file mode 100644 index 00000000..f8c70c60 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyModule.cs @@ -0,0 +1,43 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using RapidField.SolidInstruments.InversionOfControl.DotNetNative; +using System; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi +{ + /// + /// Encapsulates container configuration for application dependencies. + /// + public sealed class ApplicationDependencyModule : DotNetNativeDependencyModule + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + public ApplicationDependencyModule(IConfiguration applicationConfiguration) + : base(applicationConfiguration) + { + return; + } + + /// + /// Configures the module. + /// + /// + /// An object that configures containers. + /// + /// + /// Configuration information for the application. + /// + protected override void Configure(ServiceCollection configurator, IConfiguration applicationConfiguration) => _ = configurator.AddControllers(); + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyPackage.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyPackage.cs index fc762217..1a8202e0 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyPackage.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationDependencyPackage.cs @@ -35,6 +35,7 @@ public ApplicationDependencyPackage() /// protected override IEnumerable> CreateModules(IConfiguration applicationConfiguration) => new IDependencyModule[] { + new ApplicationDependencyModule(applicationConfiguration), new DatabaseContextDependencyModule(applicationConfiguration), new ServiceBusDependencyModule(applicationConfiguration), new MessageHandlerModule(applicationConfiguration) diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationWebExecutor.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationWebExecutor.cs new file mode 100644 index 00000000..b5ea7ff2 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/ApplicationWebExecutor.cs @@ -0,0 +1,84 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using RapidField.SolidInstruments.Web.DotNetNative; +using System; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi +{ + /// + /// Prepares for and performs execution of the HTTP API application. + /// + public sealed class ApplicationWebExecutor : DotNetNativeWebExecutor + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The name of the web application. + /// + /// + /// is empty. + /// + /// + /// is . + /// + public ApplicationWebExecutor(String applicationName) + : base(applicationName) + { + return; + } + + /// + /// Configures the application's request pipeline. + /// + /// + /// An object that configures the application's request pipeline. + /// + /// + /// Configuration information for the web application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + protected override void ConfigureApplication(IApplicationBuilder application, IConfiguration applicationConfiguration, String[] commandLineArguments) + { + try + { + application.UseAuthorization(); + application.UseRouting(); + application.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + finally + { + base.ConfigureApplication(application, applicationConfiguration, commandLineArguments); + } + } + + /// + /// 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); + + /// + /// When overridden by a derived class, gets a copyright notice which is written to the console at the start of application + /// execution. + /// + protected override sealed String CopyrightNotice => "Copyright (c) RapidField LLC. All rights reserved."; + + /// + /// When overridden by a derived class, gets a product name associated with the application which is written to the console + /// at the start of application execution. + /// + protected override sealed String ProductName => "Solid Instruments"; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/TestController.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/TestController.cs new file mode 100644 index 00000000..2af80642 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/TestController.cs @@ -0,0 +1,34 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Mvc; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.Controllers +{ + /// + /// Processes HTTP requests for the ~/Test endpoint. + /// + [Route("[controller]")] + [ApiController] + public sealed class TestController : ControllerBase + { + /// + /// Initializes a new instance of the class. + /// + public TestController() + : base() + { + return; + } + + /// + /// Handles GET requests for the endpoint. + /// + /// + /// A status code result. + /// + [HttpGet] + public IActionResult Get() => Ok(); + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/UserController.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/UserController.cs index eed70a41..ed09cf8b 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/UserController.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Controllers/UserController.cs @@ -31,6 +31,7 @@ public sealed class UserController : ControllerBase /// is . /// public UserController(ICommandMediator mediator) + : base() { Mediator = mediator.RejectIf().IsNull(nameof(mediator)).TargetArgument; } @@ -45,10 +46,18 @@ public UserController(ICommandMediator mediator) /// A status code result. /// [HttpDelete] - public IActionResult Delete([FromQuery] Guid identifier) + public IActionResult Delete([FromRoute] Guid identifier) { try { + var model = Mediator.Process(new FindDomainModelByIdentifierCommand(identifier)); + + if (model is null) + { + return NotFound(identifier); + } + + _ = Mediator.Process(new DeleteDomainModelCommandMessage(new DeleteDomainModelCommand(model))); return Ok(); } catch (ArgumentException exception) @@ -76,7 +85,13 @@ public IActionResult Get([FromQuery] Guid identifier) { try { - var model = (DomainModel)null; + var model = Mediator.Process(new FindDomainModelByIdentifierCommand(identifier)); + + if (model is null) + { + return NotFound(identifier); + } + return new JsonResult(model); } catch (ArgumentException exception) diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Program.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Program.cs index 8ac60e1a..a9a6a45b 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Program.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Program.cs @@ -2,9 +2,8 @@ // Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ================================================================================================================================= -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; using System; +using System.Diagnostics; namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi { @@ -14,25 +13,21 @@ namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi public static class Program { /// - /// Configures the application hosting environment. + /// Begins execution of the application. /// /// /// Command line arguments that are provided at runtime. /// - /// - /// The resulting host configuration. - /// - public static IHostBuilder CreateHostBuilder(String[] args) => Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => + public static void Main(String[] args) { - webBuilder.UseStartup(); - }); + using var webExecutor = new ApplicationWebExecutor(ApplicationName); + webExecutor.Execute(args); + } /// - /// Begins execution of the application. + /// Represents the name of this application. /// - /// - /// Command line arguments that are provided at runtime. - /// - public static void Main(String[] args) => CreateHostBuilder(args).Build().Run(); + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private static readonly String ApplicationName = $"{nameof(AccessControl)} HTTP API"; } } \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Properties/launchSettings.json b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Properties/launchSettings.json index 9a6041f5..a9af1982 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Properties/launchSettings.json +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Properties/launchSettings.json @@ -4,7 +4,7 @@ "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:57484", - "sslPort": 44319 + "sslPort": 0 } }, "$schema": "http://json.schemastore.org/launchsettings.json", diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj index 3ce434a5..53217fc8 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi.csproj @@ -20,6 +20,7 @@ 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.HttpApi/Startup.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Startup.cs deleted file mode 100644 index 34859fc7..00000000 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi/Startup.cs +++ /dev/null @@ -1,64 +0,0 @@ -// ================================================================================================================================= -// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. -// ================================================================================================================================= - -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -#pragma warning disable CA1822 // Mark members as static - -namespace RapidField.SolidInstruments.Example.Domain.AccessControl.HttpApi -{ - /// - /// Encapsulates application startup configuration. - /// - public class Startup - { - /// - /// Initializes a new instance of the class. - /// - /// - /// - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - /// - /// - /// - /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - /// - /// - /// - /// - /// - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - app.UseHttpsRedirection(); - app.UseRouting(); - app.UseAuthorization(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - }); - } - - /// - /// - /// - /// This method gets called by the runtime. Use this method to add services to the container. - /// - /// - /// - public void ConfigureServices(IServiceCollection services) => _ = services.AddControllers(); - - /// - /// - public IConfiguration Configuration { get; } - } -} - -#pragma warning restore CA1822 // Mark members as static \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs index 772b293b..5ec18659 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl.Service/ApplicationServiceExecutor.cs @@ -11,7 +11,6 @@ using RapidField.SolidInstruments.Service; using System; using System.Diagnostics; -using System.IO; using System.Threading; namespace RapidField.SolidInstruments.Example.Domain.AccessControl.Service @@ -65,24 +64,6 @@ protected override void AddListeners(IMessageListeningProfile listeningProfile, } } - /// - /// Builds the application configuration for the service. - /// - /// - /// An object that is used to build the configuration. - /// - protected override void BuildConfiguration(IConfigurationBuilder configurationBuilder) - { - try - { - configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json"); - } - finally - { - base.BuildConfiguration(configurationBuilder); - } - } - /// /// Releases all resources consumed by the current . /// diff --git a/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/User/FindDomainModelByIdentifierCommandHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/User/FindDomainModelByIdentifierCommandHandler.cs new file mode 100644 index 00000000..a3800db0 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/User/FindDomainModelByIdentifierCommandHandler.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.User.AggregateDataAccessModel; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.User.DomainModel; +using DomainModelCommand = RapidField.SolidInstruments.Example.Domain.Commands.ModelState.User.FindDomainModelByIdentifierCommand; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.CommandHandlers.ModelState.User +{ + /// + /// Processes a single . + /// + public sealed class FindDomainModelByIdentifierCommandHandler : FindDomainModelByIdentifierCommandHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + public FindDomainModelByIdentifierCommandHandler(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/UserRole/FindDomainModelByIdentifierCommandHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRole/FindDomainModelByIdentifierCommandHandler.cs new file mode 100644 index 00000000..72672d7d --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRole/FindDomainModelByIdentifierCommandHandler.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.UserRole.AggregateDataAccessModel; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.DomainModel; +using DomainModelCommand = RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRole.FindDomainModelByIdentifierCommand; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.CommandHandlers.ModelState.UserRole +{ + /// + /// Processes a single . + /// + public sealed class FindDomainModelByIdentifierCommandHandler : FindDomainModelByIdentifierCommandHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + public FindDomainModelByIdentifierCommandHandler(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/FindDomainModelByIdentifierCommandHandler.cs b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/FindDomainModelByIdentifierCommandHandler.cs new file mode 100644 index 00000000..f1673fb6 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain.AccessControl/CommandHandlers/ModelState/UserRoleAssignment/FindDomainModelByIdentifierCommandHandler.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.FindDomainModelByIdentifierCommand; + +namespace RapidField.SolidInstruments.Example.Domain.AccessControl.CommandHandlers.ModelState.UserRoleAssignment +{ + /// + /// Processes a single . + /// + public sealed class FindDomainModelByIdentifierCommandHandler : FindDomainModelByIdentifierCommandHandler + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + public FindDomainModelByIdentifierCommandHandler(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.Identity.Service/ApplicationServiceExecutor.cs b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationServiceExecutor.cs index c5d1f9e3..06f084f8 100644 --- a/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationServiceExecutor.cs +++ b/example/RapidField.SolidInstruments.Example.Domain.Identity.Service/ApplicationServiceExecutor.cs @@ -11,7 +11,6 @@ using RapidField.SolidInstruments.Service; using System; using System.Diagnostics; -using System.IO; using System.Threading; namespace RapidField.SolidInstruments.Example.Domain.Identity.Service @@ -65,24 +64,6 @@ protected override void AddListeners(IMessageListeningProfile listeningProfile, } } - /// - /// Builds the application configuration for the service. - /// - /// - /// An object that is used to build the configuration. - /// - protected override void BuildConfiguration(IConfigurationBuilder configurationBuilder) - { - try - { - configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json"); - } - finally - { - base.BuildConfiguration(configurationBuilder); - } - } - /// /// Releases all resources consumed by the current . /// diff --git a/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/User/FindDomainModelByIdentifierCommand.cs b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/User/FindDomainModelByIdentifierCommand.cs new file mode 100644 index 00000000..b6bdbaf6 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/User/FindDomainModelByIdentifierCommand.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 RapidField.SolidInstruments.Command; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.User.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Commands.ModelState.User +{ + /// + /// Represents a command to find and return a by its primary identifier. + /// + [DataContract(Name = DataContractName)] + public sealed class FindDomainModelByIdentifierCommand : FindDomainModelByIdentifierCommand + { + /// + /// Initializes a new instance of the class. + /// + public FindDomainModelByIdentifierCommand() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier) + : base(modelIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// is . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier, IEnumerable labels) + : base(modelIdentifier, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + /// + /// 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 . + /// + /// + /// is equal to . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier, IEnumerable labels, Guid correlationIdentifier) + : base(modelIdentifier, 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 + DataContractNamePreposition + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRole/FindDomainModelByIdentifierCommand.cs b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRole/FindDomainModelByIdentifierCommand.cs new file mode 100644 index 00000000..1d4f0ebf --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRole/FindDomainModelByIdentifierCommand.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 RapidField.SolidInstruments.Command; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using DomainModel = RapidField.SolidInstruments.Example.Domain.Models.UserRole.DomainModel; + +namespace RapidField.SolidInstruments.Example.Domain.Commands.ModelState.UserRole +{ + /// + /// Represents a command to find and return a by its primary identifier. + /// + [DataContract(Name = DataContractName)] + public sealed class FindDomainModelByIdentifierCommand : FindDomainModelByIdentifierCommand + { + /// + /// Initializes a new instance of the class. + /// + public FindDomainModelByIdentifierCommand() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier) + : base(modelIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// is . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier, IEnumerable labels) + : base(modelIdentifier, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + /// + /// 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 . + /// + /// + /// is equal to . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier, IEnumerable labels, Guid correlationIdentifier) + : base(modelIdentifier, 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 + DataContractNamePreposition + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/FindDomainModelByIdentifierCommand.cs b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/FindDomainModelByIdentifierCommand.cs new file mode 100644 index 00000000..81f42322 --- /dev/null +++ b/example/RapidField.SolidInstruments.Example.Domain/Commands/ModelState/UserRoleAssignment/FindDomainModelByIdentifierCommand.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 RapidField.SolidInstruments.Command; +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.Commands.ModelState.UserRoleAssignment +{ + /// + /// Represents a command to find and return a by its primary identifier. + /// + [DataContract(Name = DataContractName)] + public sealed class FindDomainModelByIdentifierCommand : FindDomainModelByIdentifierCommand + { + /// + /// Initializes a new instance of the class. + /// + public FindDomainModelByIdentifierCommand() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier) + : base(modelIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// is . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier, IEnumerable labels) + : base(modelIdentifier, labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + /// + /// 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 . + /// + /// + /// is equal to . + /// + public FindDomainModelByIdentifierCommand(Guid modelIdentifier, IEnumerable labels, Guid correlationIdentifier) + : base(modelIdentifier, 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 + DataContractNamePreposition + DataContractNameSuffix; + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Command/DomainCommand.cs b/src/RapidField.SolidInstruments.Command/DomainCommand.cs index f6cf555c..eafb0f0b 100644 --- a/src/RapidField.SolidInstruments.Command/DomainCommand.cs +++ b/src/RapidField.SolidInstruments.Command/DomainCommand.cs @@ -46,7 +46,7 @@ public DomainCommand(Guid correlationIdentifier) /// Initializes a new instance of the class. /// /// - /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// A collection of textual labels that provide categorical and/or contextual information about the command. /// /// /// is . @@ -61,7 +61,7 @@ public DomainCommand(IEnumerable labels) /// Initializes a new instance of the class. /// /// - /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// A collection of textual labels that provide categorical and/or contextual information about the command. /// /// /// A unique identifier that is assigned to related commands. @@ -130,7 +130,7 @@ public DomainCommand(Guid correlationIdentifier) /// Initializes a new instance of the class. /// /// - /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// A collection of textual labels that provide categorical and/or contextual information about the command. /// /// /// is . @@ -145,7 +145,7 @@ public DomainCommand(IEnumerable labels) /// Initializes a new instance of the class. /// /// - /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// A collection of textual labels that provide categorical and/or contextual information about the command. /// /// /// A unique identifier that is assigned to related commands. diff --git a/src/RapidField.SolidInstruments.Command/DomainModelCommand.cs b/src/RapidField.SolidInstruments.Command/DomainModelCommand.cs index eec75bcd..c2a9559b 100644 --- a/src/RapidField.SolidInstruments.Command/DomainModelCommand.cs +++ b/src/RapidField.SolidInstruments.Command/DomainModelCommand.cs @@ -54,7 +54,7 @@ public DomainModelCommand(Guid correlationIdentifier) /// The desired state of the associated domain model. /// /// - /// A classification that describes the effect of a the event upon . + /// A classification that describes the effect of a the command upon . /// /// /// is . @@ -75,7 +75,7 @@ public DomainModelCommand(TModel model, DomainModelCommandClassification classif /// The desired state of the associated domain model. /// /// - /// A classification that describes the effect of a the event upon . + /// A classification that describes the effect of a the command upon . /// /// /// A unique identifier that is assigned to related commands. @@ -100,10 +100,10 @@ public DomainModelCommand(TModel model, DomainModelCommandClassification classif /// The desired state of the associated domain model. /// /// - /// A classification that describes the effect of a the event upon . + /// A classification that describes the effect of a the command upon . /// /// - /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// A collection of textual labels that provide categorical and/or contextual information about the command. /// /// /// is -or- is . @@ -125,10 +125,10 @@ public DomainModelCommand(TModel model, DomainModelCommandClassification classif /// The desired state of the associated domain model. /// /// - /// A classification that describes the effect of a the event upon . + /// A classification that describes the effect of a the command upon . /// /// - /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// A collection of textual labels that provide categorical and/or contextual information about the command. /// /// /// A unique identifier that is assigned to related commands. diff --git a/src/RapidField.SolidInstruments.Command/FindDomainModelByIdentifierCommand.cs b/src/RapidField.SolidInstruments.Command/FindDomainModelByIdentifierCommand.cs new file mode 100644 index 00000000..0ad5161b --- /dev/null +++ b/src/RapidField.SolidInstruments.Command/FindDomainModelByIdentifierCommand.cs @@ -0,0 +1,109 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Core.Domain; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace RapidField.SolidInstruments.Command +{ + /// + /// Represents a command to find and return an object that models a domain construct by its primary identifier. + /// + /// + /// is the default implementation of + /// . + /// + /// + /// The type of the unique primary identifier for the model. + /// + /// + /// The type of the associated domain model. + /// + [DataContract] + public class FindDomainModelByIdentifierCommand : FindDomainModelCommand, IFindDomainModelByIdentifierCommand + where TIdentifier : IComparable, IComparable, IEquatable + where TModel : class, IDomainModel + { + /// + /// Initializes a new instance of the class. + /// + public FindDomainModelByIdentifierCommand() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + public FindDomainModelByIdentifierCommand(TIdentifier modelIdentifier) + : base() + { + ModelIdentifier = modelIdentifier; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// is . + /// + public FindDomainModelByIdentifierCommand(TIdentifier modelIdentifier, IEnumerable labels) + : base(labels) + { + ModelIdentifier = modelIdentifier; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A value that uniquely identifies the associated . + /// + /// + /// 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 . + /// + /// + /// is equal to . + /// + public FindDomainModelByIdentifierCommand(TIdentifier modelIdentifier, IEnumerable labels, Guid correlationIdentifier) + : base(labels, correlationIdentifier) + { + ModelIdentifier = modelIdentifier; + } + + /// + /// Gets or sets a value that uniquely identifies the associated . + /// + [DataMember] + public TIdentifier ModelIdentifier + { + get; + set; + } + + /// + /// Represents the standard preposition which is included in the name that is used when representing this type in + /// serialization and transport contexts. + /// + protected internal const String DataContractNamePreposition = "ByIdentifier"; + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Command/FindDomainModelByIdentifierCommandHandler.cs b/src/RapidField.SolidInstruments.Command/FindDomainModelByIdentifierCommandHandler.cs new file mode 100644 index 00000000..5c2a15e7 --- /dev/null +++ b/src/RapidField.SolidInstruments.Command/FindDomainModelByIdentifierCommandHandler.cs @@ -0,0 +1,99 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.Core.Domain; +using System; +using System.Collections.Generic; + +namespace RapidField.SolidInstruments.Command +{ + /// + /// Processes a single . + /// + /// + /// The type of the unique primary identifier for the model. + /// + /// + /// The type of the associated domain model. + /// + /// + /// The type of the command that is processed by the handler. + /// + public abstract class FindDomainModelByIdentifierCommandHandler : FindDomainModelCommandHandler + where TIdentifier : IComparable, IComparable, IEquatable + where TModel : class, IDomainModel + where TCommand : class, IFindDomainModelByIdentifierCommand + { + /// + /// Initializes a new instance of the + /// class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + protected FindDomainModelByIdentifierCommandHandler(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); + + /// + /// Searches for and returns the specified domain model. + /// + /// + /// The unique primary identifier for the model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// 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. + /// + /// + /// The specified model, or if no matching model is found. + /// + protected abstract TModel FindDomainModel(TIdentifier modelIdentifier, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken); + + /// + /// Processes the specified command. + /// + /// + /// Do not process using , as doing so will generally result in + /// infinite-looping; is exposed to this method to facilitate sub-command processing. + /// + /// + /// The command to process. + /// + /// + /// A processing intermediary that is used to process sub-commands. Do not process using + /// , as doing so will generally result in infinite-looping. + /// + /// + /// A token that represents and manages contextual thread safety. + /// + /// + /// The result that is emitted when processing the command. + /// + protected sealed override TModel Process(TCommand command, ICommandMediator mediator, IConcurrencyControlToken controlToken) => FindDomainModel(command.ModelIdentifier, command.Labels, command.CorrelationIdentifier, mediator, controlToken); + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Command/FindDomainModelCommand.cs b/src/RapidField.SolidInstruments.Command/FindDomainModelCommand.cs new file mode 100644 index 00000000..970febb7 --- /dev/null +++ b/src/RapidField.SolidInstruments.Command/FindDomainModelCommand.cs @@ -0,0 +1,92 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Core.Domain; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace RapidField.SolidInstruments.Command +{ + /// + /// Represents a command to find and return an object that models a domain construct. + /// + /// + /// is the default implementation of + /// . + /// + /// + /// The type of the associated domain model. + /// + [DataContract] + public class FindDomainModelCommand : DomainCommand, IFindDomainModelCommand + where TModel : class, IDomainModel + { + /// + /// Initializes a new instance of the class. + /// + public FindDomainModelCommand() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A unique identifier that is assigned to related commands. + /// + /// + /// is equal to . + /// + public FindDomainModelCommand(Guid correlationIdentifier) + : base(correlationIdentifier) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// is . + /// + public FindDomainModelCommand(IEnumerable labels) + : base(labels) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// 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 . + /// + /// + /// is equal to . + /// + public FindDomainModelCommand(IEnumerable labels, Guid correlationIdentifier) + : base(labels, correlationIdentifier) + { + return; + } + + /// + /// Represents the standard verb which is prefixed to the name that is used when representing this type in serialization and + /// transport contexts. + /// + protected internal const String DataContractNameVerb = "Find"; + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Command/FindDomainModelCommandHandler.cs b/src/RapidField.SolidInstruments.Command/FindDomainModelCommandHandler.cs new file mode 100644 index 00000000..a66f2cb3 --- /dev/null +++ b/src/RapidField.SolidInstruments.Command/FindDomainModelCommandHandler.cs @@ -0,0 +1,46 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Core.Domain; +using System; + +namespace RapidField.SolidInstruments.Command +{ + /// + /// Processes a single . + /// + /// + /// The type of the associated domain model. + /// + /// + /// The type of the command that is processed by the handler. + /// + public abstract class FindDomainModelCommandHandler : DomainCommandHandler + where TModel : class, IDomainModel + where TCommand : class, IFindDomainModelCommand + { + /// + /// Initializes a new instance of the class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + protected FindDomainModelCommandHandler(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/src/RapidField.SolidInstruments.Command/IFindDomainModelByIdentifierCommand.cs b/src/RapidField.SolidInstruments.Command/IFindDomainModelByIdentifierCommand.cs new file mode 100644 index 00000000..a2be732f --- /dev/null +++ b/src/RapidField.SolidInstruments.Command/IFindDomainModelByIdentifierCommand.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 RapidField.SolidInstruments.Core.Domain; +using System; + +namespace RapidField.SolidInstruments.Command +{ + /// + /// Represents a command to find and return an object that models a domain construct by its primary identifier. + /// + /// + /// The type of the unique primary identifier for the model. + /// + /// + /// The type of the associated domain model. + /// + public interface IFindDomainModelByIdentifierCommand : IFindDomainModelCommand + where TIdentifier : IComparable, IComparable, IEquatable + where TModel : class, IDomainModel + { + /// + /// Gets or sets a value that uniquely identifies the associated . + /// + public TIdentifier ModelIdentifier + { + get; + set; + } + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Command/IFindDomainModelCommand.cs b/src/RapidField.SolidInstruments.Command/IFindDomainModelCommand.cs new file mode 100644 index 00000000..da23eb70 --- /dev/null +++ b/src/RapidField.SolidInstruments.Command/IFindDomainModelCommand.cs @@ -0,0 +1,19 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Core.Domain; + +namespace RapidField.SolidInstruments.Command +{ + /// + /// Represents a command to find and return an object that models a domain construct. + /// + /// + /// The type of the associated domain model. + /// + public interface IFindDomainModelCommand : IDomainCommand + where TModel : class, IDomainModel + { + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Core/ReferenceManager.cs b/src/RapidField.SolidInstruments.Core/ReferenceManager.cs index 56ab6ddc..d4afce35 100644 --- a/src/RapidField.SolidInstruments.Core/ReferenceManager.cs +++ b/src/RapidField.SolidInstruments.Core/ReferenceManager.cs @@ -45,11 +45,12 @@ public void AddObject(T reference) using (var controlToken = StateControl.Enter()) { RejectIfDisposed(); + Prune(); var managedReference = new ManagedReference(reference); if (References.Contains(managedReference) == false) { - References.Enqueue(managedReference); + References.Add(managedReference); } } } @@ -74,33 +75,29 @@ protected override void Dispose(Boolean disposing) { if (disposing) { - try + while (References.Any()) { - var disposeTasks = new List(); - - while (References.Count > 0) + try { - IAsyncDisposable reference; + var disposeTasks = new List(); - using (var controlToken = StateControl.Enter()) + foreach (var reference in References.ToArray()) { - reference = References.Dequeue(); + disposeTasks.Add(reference?.DisposeAsync().AsTask()); } - disposeTasks.Add(reference?.DisposeAsync().AsTask()); - } - - var disposeTaskArray = disposeTasks.Where(task => (task is null) == false).ToArray(); + var disposeTaskArray = disposeTasks.Where(task => (task is null) == false).ToArray(); - if (disposeTaskArray.Any()) + if (disposeTaskArray.Any()) + { + Task.WaitAll(disposeTaskArray); + } + } + finally { - Task.WaitAll(disposeTaskArray); + References.Clear(); } } - finally - { - References.Clear(); - } } } finally @@ -109,6 +106,28 @@ protected override void Dispose(Boolean disposing) } } + /// + /// Removes dead references from the current . + /// + [DebuggerHidden] + private void Prune() + { + if (References.Any()) + { + foreach (var reference in References) + { + reference.Poll(); + } + + var deadReferences = References.Where(reference => reference.IsDead); + + foreach (var deadReference in deadReferences) + { + References.Remove(deadReference); + } + } + } + /// /// Gets the number of objects that are managed by the current . /// @@ -118,15 +137,18 @@ protected override void Dispose(Boolean disposing) /// Represents the objects that are managed by the current . /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private readonly Queue References = new Queue(); + private readonly IList References = new List(); /// /// Represents an object that is managed by a . /// + /// + /// is the default implementation of . + /// /// /// The type of the managed object. /// - private class ManagedReference : IAsyncDisposable, IDisposable, IEquatable> + private class ManagedReference : IEquatable>, IManagedReference where T : class { /// @@ -138,6 +160,7 @@ private class ManagedReference : IAsyncDisposable, IDisposable, IEquatable other) /// /// A 32-bit signed integer hash code. /// - public override Int32 GetHashCode() => Target.GetHashCode(); + public override Int32 GetHashCode() => Target?.GetHashCode() ?? 0; + + /// + /// Destroys the strong reference to the managed object if its lifespan is expired. + /// + public void Poll() + { + if (StrongReferenceIsExpired) + { + StrongReference = null; + } + } /// /// Releases all resources consumed by the current . @@ -290,10 +324,93 @@ protected void Dispose(Boolean disposing) } /// - /// Represents the managed object. + /// Gets a value indicating whether or not the managed object has live references. + /// + public Boolean IsDead => Target is null; + + /// + /// Gets the length of time that the current has existed. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private TimeSpan Age => TimeStamp.Current - CreationTimeStamp; + + /// + /// Gets a value indicating whether or not the strong reference is expired. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private Boolean StrongReferenceIsExpired => StrongReference is null || Age > StrongReferenceMinimumLifeSpan; + + /// + /// Gets or sets the managed object. /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private T Target; + private T Target + { + [DebuggerHidden] + get + { + if ((StrongReference is null) == false) + { + return StrongReference; + } + else if ((WeakReference is null) == false && WeakReference.TryGetTarget(out var target)) + { + return target; + } + + return null; + } + [DebuggerHidden] + set + { + StrongReference = value; + WeakReference = value is null ? null : new WeakReference(value); + } + } + + /// + /// Represents the minimum length of time to preserve a strong reference to the managed object. The observed length of + /// time may be shorter if the reference manager is disposed. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private static readonly TimeSpan StrongReferenceMinimumLifeSpan = TimeSpan.FromSeconds(233); + + /// + /// Represents the date and time when the current was created. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly DateTime CreationTimeStamp; + + /// + /// Represents a strong reference to the managed object. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private T StrongReference; + + /// + /// Represents a weak reference to the managed object. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private WeakReference WeakReference; + } + + /// + /// Represents an object that is managed by a . + /// + private interface IManagedReference : IAsyncDisposable, IDisposable + { + /// + /// Destroys the strong reference to the managed object if its lifespan is expired. + /// + public void Poll(); + + /// + /// Gets a value indicating whether or not the managed object has live references. + /// + public Boolean IsDead + { + get; + } } } } \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.DataAccess/FindDomainModelByIdentifierCommandHandler.cs b/src/RapidField.SolidInstruments.DataAccess/FindDomainModelByIdentifierCommandHandler.cs new file mode 100644 index 00000000..ae88051d --- /dev/null +++ b/src/RapidField.SolidInstruments.DataAccess/FindDomainModelByIdentifierCommandHandler.cs @@ -0,0 +1,87 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using RapidField.SolidInstruments.Command; +using RapidField.SolidInstruments.Core.Concurrency; +using RapidField.SolidInstruments.Core.Domain; +using System; +using System.Collections.Generic; + +namespace RapidField.SolidInstruments.DataAccess +{ + /// + /// Processes a single . + /// + /// + /// The type of the unique primary identifier for the model. + /// + /// + /// The type of the domain model to which the data access model is mapped. + /// + /// + /// The type of the data access model. + /// + /// + /// The type of the command that is processed by the handler. + /// + public class FindDomainModelByIdentifierCommandHandler : FindDomainModelByIdentifierCommandHandler + where TIdentifier : IComparable, IComparable, IEquatable + where TDomainModel : class, IDomainModel, new() + where TDataAccessModel : class, IDataAccessModel, new() + where TCommand : class, IFindDomainModelByIdentifierCommand + { + /// + /// Initializes a new instance of the + /// class. + /// + /// + /// A processing intermediary that is used to process sub-commands. + /// + /// + /// is . + /// + public FindDomainModelByIdentifierCommandHandler(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); + + /// + /// Searches for and returns the specified domain model. + /// + /// + /// The unique primary identifier for the model. + /// + /// + /// A collection of textual labels that provide categorical and/or contextual information about the command. + /// + /// + /// 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. + /// + /// + /// The specified model, or if no matching model is found. + /// + protected override TDomainModel FindDomainModel(TIdentifier modelIdentifier, IEnumerable labels, Guid correlationIdentifier, ICommandMediator mediator, IConcurrencyControlToken controlToken) + { + var dataAccessModelCommand = new FindDataAccessModelByIdentifierCommand(modelIdentifier); + var dataAccessModel = mediator.Process(dataAccessModelCommand); + return dataAccessModel?.ToDomainModel(); + } + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.EventAuthoring/DomainReportableCommand.cs b/src/RapidField.SolidInstruments.EventAuthoring/DomainReportableCommand.cs index 3096c228..d90b61f4 100644 --- a/src/RapidField.SolidInstruments.EventAuthoring/DomainReportableCommand.cs +++ b/src/RapidField.SolidInstruments.EventAuthoring/DomainReportableCommand.cs @@ -52,7 +52,7 @@ public DomainReportableCommand(Guid correlationIdentifier) /// Initializes a new instance of the class. /// /// - /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// A collection of textual labels that provide categorical and/or contextual information about the command. /// /// /// is . @@ -67,7 +67,7 @@ public DomainReportableCommand(IEnumerable labels) /// Initializes a new instance of the class. /// /// - /// A collection of textual labels that provide categorical and/or contextual information about the event. + /// A collection of textual labels that provide categorical and/or contextual information about the command. /// /// /// A unique identifier that is assigned to related commands. diff --git a/src/RapidField.SolidInstruments.InversionOfControl.Autofac/AutofacServiceInjector.cs b/src/RapidField.SolidInstruments.InversionOfControl.Autofac/AutofacServiceInjector.cs index f4ac67f5..4032edda 100644 --- a/src/RapidField.SolidInstruments.InversionOfControl.Autofac/AutofacServiceInjector.cs +++ b/src/RapidField.SolidInstruments.InversionOfControl.Autofac/AutofacServiceInjector.cs @@ -40,7 +40,7 @@ internal AutofacServiceInjector(IServiceCollection serviceDescriptors) /// The object that configures a container. /// /// - /// a collection of service descriptors that are added to the configurator. + /// A collection of service descriptors that are added to the configurator. /// protected sealed override void Inject(ContainerBuilder configurator, IServiceCollection serviceDescriptors) { diff --git a/src/RapidField.SolidInstruments.InversionOfControl.Autofac/AutofacServiceProviderFactory.cs b/src/RapidField.SolidInstruments.InversionOfControl.Autofac/AutofacServiceProviderFactory.cs new file mode 100644 index 00000000..a25becdc --- /dev/null +++ b/src/RapidField.SolidInstruments.InversionOfControl.Autofac/AutofacServiceProviderFactory.cs @@ -0,0 +1,72 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using RapidField.SolidInstruments.InversionOfControl.Autofac.Extensions; +using System; + +namespace RapidField.SolidInstruments.InversionOfControl.Autofac +{ + /// + /// Provides an extension point for creating an Autofac container builder and an . + /// + /// + /// The package that configures the engine. + /// + public class AutofacServiceProviderFactory : ServiceProviderFactory + where TPackage : AutofacDependencyPackage, new() + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + public AutofacServiceProviderFactory(IConfiguration applicationConfiguration) + : base(applicationConfiguration) + { + return; + } + + /// + /// Creates an . + /// + /// + /// A source configurator. + /// + /// + /// Configuration information for the application. + /// + /// + /// An . + /// + protected override IServiceProvider CreateServiceProvider(ContainerBuilder configurator, IConfiguration applicationConfiguration) + { + var container = configurator.Build(); + return new AutofacServiceProvider(container); + } + + /// + /// Prepares a newly-created instance. + /// + /// + /// The configurator to prepare. + /// + /// + /// A collection of services. + /// + protected override void PrepareConfigurator(ContainerBuilder configurator, IServiceCollection services) + { + services.AddDependencyPackage(ApplicationConfiguration); + var serviceInjector = new AutofacServiceInjector(services); + serviceInjector.Inject(configurator); + } + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/DotNetNativeServiceInjector.cs b/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/DotNetNativeServiceInjector.cs index 679a10f6..761c3cc2 100644 --- a/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/DotNetNativeServiceInjector.cs +++ b/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/DotNetNativeServiceInjector.cs @@ -37,8 +37,14 @@ internal DotNetNativeServiceInjector(IServiceCollection serviceDescriptors) /// The object that configures a container. /// /// - /// a collection of service descriptors that are added to the configurator. + /// A collection of service descriptors that are added to the configurator. /// - protected sealed override void Inject(ServiceCollection configurator, IServiceCollection serviceDescriptors) => configurator.Add(serviceDescriptors); + protected sealed override void Inject(ServiceCollection configurator, IServiceCollection serviceDescriptors) + { + foreach (var serviceDescriptor in serviceDescriptors) + { + configurator.TryAdd(serviceDescriptor); + } + } } } \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/DotNetNativeServiceProviderFactory.cs b/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/DotNetNativeServiceProviderFactory.cs new file mode 100644 index 00000000..585f9433 --- /dev/null +++ b/src/RapidField.SolidInstruments.InversionOfControl.DotNetNative/DotNetNativeServiceProviderFactory.cs @@ -0,0 +1,69 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using RapidField.SolidInstruments.InversionOfControl.DotNetNative.Extensions; +using System; + +namespace RapidField.SolidInstruments.InversionOfControl.DotNetNative +{ + /// + /// Provides an extension point for creating a native .NET container builder and an . + /// + /// + /// The package that configures the engine. + /// + public class DotNetNativeServiceProviderFactory : ServiceProviderFactory + where TPackage : DotNetNativeDependencyPackage, new() + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + public DotNetNativeServiceProviderFactory(IConfiguration applicationConfiguration) + : base(applicationConfiguration) + { + return; + } + + /// + /// Creates an . + /// + /// + /// A source configurator. + /// + /// + /// Configuration information for the application. + /// + /// + /// An . + /// + protected override IServiceProvider CreateServiceProvider(ServiceCollection configurator, IConfiguration applicationConfiguration) + { + _ = configurator.AddDependencyPackage(applicationConfiguration, out var serviceProvider); + return serviceProvider; + } + + /// + /// Prepares a newly-created instance. + /// + /// + /// The configurator to prepare. + /// + /// + /// A collection of services. + /// + protected override void PrepareConfigurator(ServiceCollection configurator, IServiceCollection services) + { + var serviceInjector = new DotNetNativeServiceInjector(services); + serviceInjector.Inject(configurator); + } + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.InversionOfControl/Extensions/IServiceCollectionExtensions.cs b/src/RapidField.SolidInstruments.InversionOfControl/Extensions/IServiceCollectionExtensions.cs index d3d12480..bf3176c1 100644 --- a/src/RapidField.SolidInstruments.InversionOfControl/Extensions/IServiceCollectionExtensions.cs +++ b/src/RapidField.SolidInstruments.InversionOfControl/Extensions/IServiceCollectionExtensions.cs @@ -96,7 +96,6 @@ internal static IServiceCollection AddDependencyPackage(applicationConfiguration, target); ReferenceManager.AddObject(engine); serviceProvider = engine.Provider; diff --git a/src/RapidField.SolidInstruments.InversionOfControl/ServiceProviderFactory.cs b/src/RapidField.SolidInstruments.InversionOfControl/ServiceProviderFactory.cs index 13a18b96..5153c1d1 100644 --- a/src/RapidField.SolidInstruments.InversionOfControl/ServiceProviderFactory.cs +++ b/src/RapidField.SolidInstruments.InversionOfControl/ServiceProviderFactory.cs @@ -2,6 +2,7 @@ // Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. // ================================================================================================================================= +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using RapidField.SolidInstruments.Core; using RapidField.SolidInstruments.Core.ArgumentValidation; @@ -10,6 +11,93 @@ namespace RapidField.SolidInstruments.InversionOfControl { + /// + /// Provides an extension point for creating a container specific builder and an . + /// + /// + /// The type of the object that configures containers. + /// + public abstract class ServiceProviderFactory : IServiceProviderFactory + where TConfigurator : class, new() + { + /// + /// Initializes a new instance of the class. + /// + /// + /// Configuration information for the application. + /// + /// + /// is . + /// + protected ServiceProviderFactory(IConfiguration applicationConfiguration) + { + ApplicationConfiguration = applicationConfiguration.RejectIf().IsNull(nameof(applicationConfiguration)).TargetArgument; + } + + /// + /// Returns a new instance. + /// + /// + /// The collection of services. + /// + /// + /// A new instance. + /// + /// + /// is . + /// + public TConfigurator CreateBuilder(IServiceCollection services) + { + var configurator = new TConfigurator(); + PrepareConfigurator(configurator, services.RejectIf().IsNull(nameof(services)).TargetArgument); + return configurator; + } + + /// + /// Creates an . + /// + /// + /// A source configurator. + /// + /// + /// An . + /// + /// + /// is . + /// + public IServiceProvider CreateServiceProvider(TConfigurator containerBuilder) => CreateServiceProvider(containerBuilder.RejectIf().IsNull(nameof(containerBuilder)), ApplicationConfiguration); + + /// + /// Creates an . + /// + /// + /// A source configurator. + /// + /// + /// Configuration information for the application. + /// + /// + /// An . + /// + protected abstract IServiceProvider CreateServiceProvider(TConfigurator configurator, IConfiguration applicationConfiguration); + + /// + /// Prepares a newly-created instance. + /// + /// + /// The configurator to prepare. + /// + /// + /// A collection of services. + /// + protected abstract void PrepareConfigurator(TConfigurator configurator, IServiceCollection services); + + /// + /// Represents configuration information for the application. + /// + protected readonly IConfiguration ApplicationConfiguration; + } + /// /// Provides an extension point for creating a container specific builder and an . /// diff --git a/src/RapidField.SolidInstruments.Messaging.Autofac.Asb/Extensions/ContainerBuilderExtensions.cs b/src/RapidField.SolidInstruments.Messaging.Autofac.Asb/Extensions/ContainerBuilderExtensions.cs index 49fa90c8..21df5488 100644 --- a/src/RapidField.SolidInstruments.Messaging.Autofac.Asb/Extensions/ContainerBuilderExtensions.cs +++ b/src/RapidField.SolidInstruments.Messaging.Autofac.Asb/Extensions/ContainerBuilderExtensions.cs @@ -56,11 +56,11 @@ public static void RegisterSupportingTypesForAzureServiceBusMessaging(this Conta } return new ServiceBusConnection(serviceBusConnectionString); - }).IfNotRegistered(typeof(ServiceBusConnection)).AsSelf().InstancePerLifetimeScope(); + }).IfNotRegistered(typeof(ServiceBusConnection)).AsSelf().SingleInstance(); - target.RegisterType().IfNotRegistered(typeof(AzureServiceBusMessageAdapter)).As>().AsSelf().InstancePerLifetimeScope(); - target.RegisterType().IfNotRegistered(typeof(AzureServiceBusClientFactory)).As>().AsSelf().InstancePerLifetimeScope(); - target.RegisterType().IfNotRegistered(typeof(AzureServiceBusTransmittingFacade)).As().AsSelf().InstancePerLifetimeScope(); + target.RegisterType().IfNotRegistered(typeof(AzureServiceBusMessageAdapter)).As>().AsSelf().SingleInstance(); + target.RegisterType().IfNotRegistered(typeof(AzureServiceBusClientFactory)).As>().AsSelf().SingleInstance(); + target.RegisterType().IfNotRegistered(typeof(AzureServiceBusTransmittingFacade)).As().AsSelf().SingleInstance(); target.RegisterType().IfNotRegistered(typeof(AzureServiceBusListeningFacade)).As().AsSelf().SingleInstance(); target.RegisterType().IfNotRegistered(typeof(AzureServiceBusRequestingFacade)).As().AsSelf().SingleInstance(); } diff --git a/src/RapidField.SolidInstruments.Messaging.Autofac.Rmq/Extensions/ContainerBuilderExtensions.cs b/src/RapidField.SolidInstruments.Messaging.Autofac.Rmq/Extensions/ContainerBuilderExtensions.cs index 14ef4e14..ee63f715 100644 --- a/src/RapidField.SolidInstruments.Messaging.Autofac.Rmq/Extensions/ContainerBuilderExtensions.cs +++ b/src/RapidField.SolidInstruments.Messaging.Autofac.Rmq/Extensions/ContainerBuilderExtensions.cs @@ -222,9 +222,9 @@ private static void RegisterSupportingTypesForRabbitMqMessaging(this ContainerBu target.RegisterApplicationConfiguration(applicationConfiguration); target.RegisterInstance(transport).IfNotRegistered(typeof(RabbitMqMessageTransport)).AsSelf().SingleInstance(); target.RegisterInstance(transport.CreateConnection()).IfNotRegistered(typeof(IMessageTransportConnection)).AsSelf().SingleInstance(); - target.RegisterType().IfNotRegistered(typeof(RabbitMqMessageAdapter)).As>().AsSelf().InstancePerLifetimeScope(); - target.RegisterType().IfNotRegistered(typeof(RabbitMqClientFactory)).As>().AsSelf().InstancePerLifetimeScope(); - target.RegisterType().IfNotRegistered(typeof(RabbitMqTransmittingFacade)).As().AsSelf().InstancePerLifetimeScope(); + target.RegisterType().IfNotRegistered(typeof(RabbitMqMessageAdapter)).As>().AsSelf().SingleInstance(); + target.RegisterType().IfNotRegistered(typeof(RabbitMqClientFactory)).As>().AsSelf().SingleInstance(); + target.RegisterType().IfNotRegistered(typeof(RabbitMqTransmittingFacade)).As().AsSelf().SingleInstance(); target.RegisterType().IfNotRegistered(typeof(RabbitMqListeningFacade)).As().AsSelf().SingleInstance(); target.RegisterType().IfNotRegistered(typeof(RabbitMqRequestingFacade)).As().AsSelf().SingleInstance(); } diff --git a/src/RapidField.SolidInstruments.Messaging.Autofac/Extensions/ContainerBuilderExtensions.cs b/src/RapidField.SolidInstruments.Messaging.Autofac/Extensions/ContainerBuilderExtensions.cs index 788d6527..cc82ff40 100644 --- a/src/RapidField.SolidInstruments.Messaging.Autofac/Extensions/ContainerBuilderExtensions.cs +++ b/src/RapidField.SolidInstruments.Messaging.Autofac/Extensions/ContainerBuilderExtensions.cs @@ -587,9 +587,9 @@ public static void RegisterSupportingTypesForInMemoryMessaging(this ContainerBui { target.RegisterInstance(MessageTransport.Instance).IfNotRegistered(typeof(IMessageTransport)).SingleInstance(); target.RegisterInstance(MessageTransport.Instance.CreateConnection()).IfNotRegistered(typeof(IMessageTransportConnection)).SingleInstance(); - target.RegisterType().IfNotRegistered(typeof(InMemoryMessageAdapter)).As>().AsSelf().InstancePerLifetimeScope(); - target.RegisterType().IfNotRegistered(typeof(InMemoryClientFactory)).As>().AsSelf().InstancePerLifetimeScope(); - target.RegisterType().IfNotRegistered(typeof(InMemoryTransmittingFacade)).As().AsSelf().InstancePerLifetimeScope(); + target.RegisterType().IfNotRegistered(typeof(InMemoryMessageAdapter)).As>().AsSelf().SingleInstance(); + target.RegisterType().IfNotRegistered(typeof(InMemoryClientFactory)).As>().AsSelf().SingleInstance(); + target.RegisterType().IfNotRegistered(typeof(InMemoryTransmittingFacade)).As().AsSelf().SingleInstance(); target.RegisterType().IfNotRegistered(typeof(InMemoryListeningFacade)).As().AsSelf().SingleInstance(); target.RegisterType().IfNotRegistered(typeof(InMemoryRequestingFacade)).As().AsSelf().SingleInstance(); } diff --git a/src/RapidField.SolidInstruments.Messaging.AzureServiceBus/RapidField.SolidInstruments.Messaging.AzureServiceBus.csproj b/src/RapidField.SolidInstruments.Messaging.AzureServiceBus/RapidField.SolidInstruments.Messaging.AzureServiceBus.csproj index 46e5ba56..396c6763 100644 --- a/src/RapidField.SolidInstruments.Messaging.AzureServiceBus/RapidField.SolidInstruments.Messaging.AzureServiceBus.csproj +++ b/src/RapidField.SolidInstruments.Messaging.AzureServiceBus/RapidField.SolidInstruments.Messaging.AzureServiceBus.csproj @@ -37,7 +37,7 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in - + diff --git a/src/RapidField.SolidInstruments.Messaging.DotNetNative.Asb/Extensions/IServiceCollectionExtensions.cs b/src/RapidField.SolidInstruments.Messaging.DotNetNative.Asb/Extensions/IServiceCollectionExtensions.cs index b20e33b9..f68f4d6a 100644 --- a/src/RapidField.SolidInstruments.Messaging.DotNetNative.Asb/Extensions/IServiceCollectionExtensions.cs +++ b/src/RapidField.SolidInstruments.Messaging.DotNetNative.Asb/Extensions/IServiceCollectionExtensions.cs @@ -51,7 +51,7 @@ public static IServiceCollection AddSupportingTypesForAzureServiceBusMessaging(t target.AddApplicationConfiguration(applicationConfiguration); _ = connectionStringConfigurationKeyName.RejectIf().IsNullOrEmpty(nameof(connectionStringConfigurationKeyName)); - target.TryAddScoped((serviceProvider) => + target.TryAddSingleton((serviceProvider) => { var configuration = serviceProvider.GetService(); var serviceBusConnectionString = configuration.GetConnectionString(connectionStringConfigurationKeyName)?.Trim(); @@ -64,12 +64,12 @@ public static IServiceCollection AddSupportingTypesForAzureServiceBusMessaging(t return new ServiceBusConnection(serviceBusConnectionString); }); - target.TryAddScoped(); - target.TryAddScoped>((serviceProvider) => serviceProvider.GetService()); - target.TryAddScoped(); - target.TryAddScoped>((serviceProvider) => serviceProvider.GetService()); - target.TryAddScoped(); - target.TryAddScoped((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton>((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton>((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton((serviceProvider) => serviceProvider.GetService()); target.TryAddSingleton(); target.TryAddSingleton((serviceProvider) => serviceProvider.GetService()); target.TryAddSingleton(); diff --git a/src/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq/Extensions/IServiceCollectionExtensions.cs b/src/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq/Extensions/IServiceCollectionExtensions.cs index 3980db06..2b432e84 100644 --- a/src/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq/Extensions/IServiceCollectionExtensions.cs +++ b/src/RapidField.SolidInstruments.Messaging.DotNetNative.Rmq/Extensions/IServiceCollectionExtensions.cs @@ -245,12 +245,12 @@ private static IServiceCollection AddSupportingTypesForRabbitMqMessaging(this IS target.AddApplicationConfiguration(applicationConfiguration); target.TryAddSingleton(transport); target.TryAddSingleton(transport.CreateConnection()); - target.TryAddScoped(); - target.TryAddScoped>((serviceProvider) => serviceProvider.GetService()); - target.TryAddScoped(); - target.TryAddScoped>((serviceProvider) => serviceProvider.GetService()); - target.TryAddScoped(); - target.TryAddScoped((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton>((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton>((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton((serviceProvider) => serviceProvider.GetService()); target.TryAddSingleton(); target.TryAddSingleton((serviceProvider) => serviceProvider.GetService()); target.TryAddSingleton(); diff --git a/src/RapidField.SolidInstruments.Messaging.DotNetNative/Extensions/IServiceCollectionExtensions.cs b/src/RapidField.SolidInstruments.Messaging.DotNetNative/Extensions/IServiceCollectionExtensions.cs index 5a0852f3..fdfc1bbb 100644 --- a/src/RapidField.SolidInstruments.Messaging.DotNetNative/Extensions/IServiceCollectionExtensions.cs +++ b/src/RapidField.SolidInstruments.Messaging.DotNetNative/Extensions/IServiceCollectionExtensions.cs @@ -673,12 +673,12 @@ public static IServiceCollection AddSupportingTypesForInMemoryMessaging(this ISe { target.TryAddSingleton(MessageTransport.Instance); target.TryAddSingleton(MessageTransport.Instance.CreateConnection()); - target.TryAddScoped(); - target.TryAddScoped>((serviceProvider) => serviceProvider.GetService()); - target.TryAddScoped(); - target.TryAddScoped>((serviceProvider) => serviceProvider.GetService()); - target.TryAddScoped(); - target.TryAddScoped((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton>((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton>((serviceProvider) => serviceProvider.GetService()); + target.TryAddSingleton(); + target.TryAddSingleton((serviceProvider) => serviceProvider.GetService()); target.TryAddSingleton(); target.TryAddSingleton((serviceProvider) => serviceProvider.GetService()); target.TryAddSingleton(); diff --git a/src/RapidField.SolidInstruments.Service/RapidField.SolidInstruments.Service.csproj b/src/RapidField.SolidInstruments.Service/RapidField.SolidInstruments.Service.csproj index 051f33c0..aa42eb1b 100644 --- a/src/RapidField.SolidInstruments.Service/RapidField.SolidInstruments.Service.csproj +++ b/src/RapidField.SolidInstruments.Service/RapidField.SolidInstruments.Service.csproj @@ -36,6 +36,12 @@ Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in + + + + + + diff --git a/src/RapidField.SolidInstruments.Service/ServiceExecutor.cs b/src/RapidField.SolidInstruments.Service/ServiceExecutor.cs index 1312c513..0a12fe11 100644 --- a/src/RapidField.SolidInstruments.Service/ServiceExecutor.cs +++ b/src/RapidField.SolidInstruments.Service/ServiceExecutor.cs @@ -8,7 +8,9 @@ using RapidField.SolidInstruments.Core.Extensions; using RapidField.SolidInstruments.InversionOfControl; using System; +using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Threading; namespace RapidField.SolidInstruments.Service @@ -151,12 +153,28 @@ public void Execute(String[] commandLineArguments) /// /// Builds the application configuration for the service. /// + /// + /// The default implementation of the this method adds: + /// - environment variables with prefixes matching any of , + /// - all command line arguments supplied to and + /// - the appsettings.json file in the root application path. + /// /// /// An object that is used to build the configuration. /// protected virtual void BuildConfiguration(IConfigurationBuilder configurationBuilder) { - return; + foreach (var prefix in EnvironmentVariableConfigurationPrefixes) + { + _ = configurationBuilder.AddEnvironmentVariables(prefix); + } + + if (CommandLineArguments.IsNullOrEmpty() == false) + { + _ = configurationBuilder.AddCommandLine(CommandLineArguments); + } + + _ = configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile(DefaultAppSettingsJsonFileName); } /// @@ -275,6 +293,13 @@ internal IServiceExecutionLifetime ExecutionLifetime /// protected virtual String CopyrightNotice => null; + /// + /// When overridden by a derived class, gets a collection of textual prefixes which are used by + /// to find and add environment variables to + /// . + /// + protected virtual IEnumerable EnvironmentVariableConfigurationPrefixes => Array.Empty(); + /// /// When overridden by a derived class, gets a product name associated with the service which is written to the console at /// the start of service execution. @@ -308,6 +333,13 @@ protected IReferenceManager ReferenceManager [DebuggerBrowsable(DebuggerBrowsableState.Never)] internal String[] CommandLineArguments; + /// + /// Represents the default JSON settings file name which is used by + /// to add file-based configuration to . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String DefaultAppSettingsJsonFileName = "appsettings.json"; + /// /// Represents lazily-initialized configuration information for the service. /// diff --git a/src/RapidField.SolidInstruments.Web.Autofac/AssemblyAttributes.cs b/src/RapidField.SolidInstruments.Web.Autofac/AssemblyAttributes.cs new file mode 100644 index 00000000..a32e4acd --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.Autofac/AssemblyAttributes.cs @@ -0,0 +1,7 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System.Runtime.CompilerServices; + +[assembly: DisablePrivateReflection()] \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web.Autofac/AutofacWebExecutor.cs b/src/RapidField.SolidInstruments.Web.Autofac/AutofacWebExecutor.cs new file mode 100644 index 00000000..949a409c --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.Autofac/AutofacWebExecutor.cs @@ -0,0 +1,48 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Autofac; +using RapidField.SolidInstruments.Core; +using RapidField.SolidInstruments.InversionOfControl; +using RapidField.SolidInstruments.InversionOfControl.Autofac; +using System; + +namespace RapidField.SolidInstruments.Web.Autofac +{ + /// + /// Prepares for and performs execution of a web application using Autofac IoC tooling. + /// + /// + /// The type of the package that configures the dependency engine. + /// + public abstract class AutofacWebExecutor : WebExecutor + where TDependencyPackage : class, IDependencyPackage, new() + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The name of the web application. + /// + /// + /// is empty. + /// + /// + /// is . + /// + protected AutofacWebExecutor(String applicationName) + : base(applicationName) + { + 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/src/RapidField.SolidInstruments.Web.Autofac/Extensions/ContainerBuilderExtensions.cs b/src/RapidField.SolidInstruments.Web.Autofac/Extensions/ContainerBuilderExtensions.cs new file mode 100644 index 00000000..dbe79916 --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.Autofac/Extensions/ContainerBuilderExtensions.cs @@ -0,0 +1,16 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Autofac; + +namespace RapidField.SolidInstruments.Web.Autofac.Extensions +{ + /// + /// Extends the class with inversion of control features to support web application + /// abstractions. + /// + public static class ContainerBuilderExtensions + { + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web.Autofac/README.md b/src/RapidField.SolidInstruments.Web.Autofac/README.md new file mode 100644 index 00000000..afb2636d --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.Autofac/README.md @@ -0,0 +1,57 @@ + + +[![Solid Instruments](../../SolidInstruments.Logo.Color.Transparent.500w.png)](../../README.md) +
     +![Web](../../doc/images/Label.Web.300w.png) +- - - + +# RapidField.SolidInstruments.Web.Autofac + +This document describes the purpose of the [`RapidField.SolidInstruments.Web`]() library and offers guidance with respect to licensing, installation and usage. + +## Features + +This library exposes the [**Autofac**](https://autofac.org/) IoC integration for the **Solid Instruments** web application abstractions. + +## 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. + +## Documentation + +[![Documentation](https://img.shields.io/badge/documentation-website-tan?style=flat&logo=buffer&logoColor=lightgrey)](https://www.solidinstruments.com/api/RapidField.SolidInstruments.Web.Autofac.html) + +Check out the [**API Reference**](https://www.solidinstruments.com/api/RapidField.SolidInstruments.Web.Autofac.html) for usage examples and reference documentation. + +## Installation + +[![Version](https://img.shields.io/nuget/vpre/RapidField.SolidInstruments.Web.Autofac?style=flat&color=blue&label=version&logo=nuget&logoColor=lightgrey)](https://www.nuget.org/packages/RapidField.SolidInstruments.Web.Autofac) +[![Downloads](https://img.shields.io/nuget/dt/RapidField.SolidInstruments.Web.Autofac?style=flat&color=blue&logo=nuget&logoColor=lightgrey)](https://www.nuget.org/packages/RapidField.SolidInstruments.Web.Autofac) + +This library is available via [**NuGet**](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio). Use one of the commands below to download and install the library and all of its dependencies. + +###### .NET CLI + +```shell +dotnet add package RapidField.SolidInstruments.Web.Autofac +``` + +###### NuGet Package Manager + +```shell +Install-Package RapidField.SolidInstruments.Web.Autofac +``` + +
+ +- - - + +
+ +[![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/src/RapidField.SolidInstruments.Web.Autofac/RapidField.SolidInstruments.Web.Autofac.csproj b/src/RapidField.SolidInstruments.Web.Autofac/RapidField.SolidInstruments.Web.Autofac.csproj new file mode 100644 index 00000000..11bdb4d9 --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.Autofac/RapidField.SolidInstruments.Web.Autofac.csproj @@ -0,0 +1,50 @@ + + + + + Solid Instruments contributors + RapidField + Copyright (c) RapidField LLC. All rights reserved. + Solid Instruments + This library exposes the Autofac IoC integration for the Solid Instruments web application abstractions. + $(BuildVersion) + netstandard2.1 + latest + git + https://github.com/rapidfield/solid-instruments + true + true + LICENSE.txt + https://www.solidinstruments.com + Icon.Web.128w.png + solid-instruments;web;web-application;inversion-of-control;ioc;dependency-injection;di;autofac + + + bin\Debug\netstandard2.1\RapidField.SolidInstruments.Web.Autofac.xml + true + + + + bin\Release\netstandard2.1\RapidField.SolidInstruments.Web.Autofac.xml + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web.DotNetNative/AssemblyAttributes.cs b/src/RapidField.SolidInstruments.Web.DotNetNative/AssemblyAttributes.cs new file mode 100644 index 00000000..a32e4acd --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.DotNetNative/AssemblyAttributes.cs @@ -0,0 +1,7 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System.Runtime.CompilerServices; + +[assembly: DisablePrivateReflection()] \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web.DotNetNative/DotNetNativeWebExecutor.cs b/src/RapidField.SolidInstruments.Web.DotNetNative/DotNetNativeWebExecutor.cs new file mode 100644 index 00000000..2eb2af88 --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.DotNetNative/DotNetNativeWebExecutor.cs @@ -0,0 +1,48 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.DependencyInjection; +using RapidField.SolidInstruments.Core; +using RapidField.SolidInstruments.InversionOfControl; +using RapidField.SolidInstruments.InversionOfControl.DotNetNative; +using System; + +namespace RapidField.SolidInstruments.Web.DotNetNative +{ + /// + /// Prepares for and performs execution of a web application using native .NET IoC tooling. + /// + /// + /// The type of the package that configures the dependency engine. + /// + public abstract class DotNetNativeWebExecutor : WebExecutor + where TDependencyPackage : class, IDependencyPackage, new() + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The name of the web application. + /// + /// + /// is empty. + /// + /// + /// is . + /// + protected DotNetNativeWebExecutor(String applicationName) + : base(applicationName) + { + 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/src/RapidField.SolidInstruments.Web.DotNetNative/Extensions/IServiceCollectionExtensions.cs b/src/RapidField.SolidInstruments.Web.DotNetNative/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 00000000..81671c50 --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.DotNetNative/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,16 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.Extensions.DependencyInjection; + +namespace RapidField.SolidInstruments.Command.DotNetNative.Extensions +{ + /// + /// Extends the interface with native .NET inversion of control features to support web + /// application abstractions. + /// + public static class IServiceCollectionExtensions + { + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web.DotNetNative/README.md b/src/RapidField.SolidInstruments.Web.DotNetNative/README.md new file mode 100644 index 00000000..8f75e3ab --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.DotNetNative/README.md @@ -0,0 +1,57 @@ + + +[![Solid Instruments](../../SolidInstruments.Logo.Color.Transparent.500w.png)](../../README.md) +
     +![Web](../../doc/images/Label.Web.300w.png) +- - - + +# RapidField.SolidInstruments.Web.DotNetNative + +This document describes the purpose of the [`RapidField.SolidInstruments.Web`]() library and offers guidance with respect to licensing, installation and usage. + +## Features + +This library exposes the native .NET IoC integration for the **Solid Instruments** web application abstractions. + +## 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. + +## Documentation + +[![Documentation](https://img.shields.io/badge/documentation-website-tan?style=flat&logo=buffer&logoColor=lightgrey)](https://www.solidinstruments.com/api/RapidField.SolidInstruments.Web.DotNetNative.html) + +Check out the [**API Reference**](https://www.solidinstruments.com/api/RapidField.SolidInstruments.Web.DotNetNative.html) for usage examples and reference documentation. + +## Installation + +[![Version](https://img.shields.io/nuget/vpre/RapidField.SolidInstruments.Web.DotNetNative?style=flat&color=blue&label=version&logo=nuget&logoColor=lightgrey)](https://www.nuget.org/packages/RapidField.SolidInstruments.Web.DotNetNative) +[![Downloads](https://img.shields.io/nuget/dt/RapidField.SolidInstruments.Web.DotNetNative?style=flat&color=blue&logo=nuget&logoColor=lightgrey)](https://www.nuget.org/packages/RapidField.SolidInstruments.Web.DotNetNative) + +This library is available via [**NuGet**](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio). Use one of the commands below to download and install the library and all of its dependencies. + +###### .NET CLI + +```shell +dotnet add package RapidField.SolidInstruments.Web.DotNetNative +``` + +###### NuGet Package Manager + +```shell +Install-Package RapidField.SolidInstruments.Web.DotNetNative +``` + +
+ +- - - + +
+ +[![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/src/RapidField.SolidInstruments.Web.DotNetNative/RapidField.SolidInstruments.Web.DotNetNative.csproj b/src/RapidField.SolidInstruments.Web.DotNetNative/RapidField.SolidInstruments.Web.DotNetNative.csproj new file mode 100644 index 00000000..9248b657 --- /dev/null +++ b/src/RapidField.SolidInstruments.Web.DotNetNative/RapidField.SolidInstruments.Web.DotNetNative.csproj @@ -0,0 +1,50 @@ + + + + + Solid Instruments contributors + RapidField + Copyright (c) RapidField LLC. All rights reserved. + Solid Instruments + This library exposes the native .NET IoC integration for the Solid Instruments web application abstractions. + $(BuildVersion) + netstandard2.1 + latest + git + https://github.com/rapidfield/solid-instruments + true + true + LICENSE.txt + https://www.solidinstruments.com + Icon.Web.128w.png + solid-instruments;web;web-application;inversion-of-control;ioc;dependency-injection;di + + + bin\Debug\netstandard2.1\RapidField.SolidInstruments.Web.DotNetNative.xml + true + + + + bin\Release\netstandard2.1\RapidField.SolidInstruments.Web.DotNetNative.xml + true + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web/AssemblyAttributes.cs b/src/RapidField.SolidInstruments.Web/AssemblyAttributes.cs new file mode 100644 index 00000000..a32e4acd --- /dev/null +++ b/src/RapidField.SolidInstruments.Web/AssemblyAttributes.cs @@ -0,0 +1,7 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System.Runtime.CompilerServices; + +[assembly: DisablePrivateReflection()] \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web/IWebExecutor.cs b/src/RapidField.SolidInstruments.Web/IWebExecutor.cs new file mode 100644 index 00000000..823e56c7 --- /dev/null +++ b/src/RapidField.SolidInstruments.Web/IWebExecutor.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.Core; +using System; + +namespace RapidField.SolidInstruments.Web +{ + /// + /// Prepares for and performs execution of a web application. + /// + public interface IWebExecutor : IInstrument + { + /// + /// Begins execution of the web application. + /// + /// + /// An exception was raised during execution of the web application. + /// + public void Execute(); + + /// + /// Begins execution of the web application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + /// + /// An exception was raised during execution of the web application. + /// + public void Execute(String[] commandLineArguments); + + /// + /// Gets the name of the web application. + /// + public String ApplicationName + { + get; + } + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web/README.md b/src/RapidField.SolidInstruments.Web/README.md new file mode 100644 index 00000000..66d3e9bc --- /dev/null +++ b/src/RapidField.SolidInstruments.Web/README.md @@ -0,0 +1,57 @@ + + +[![Solid Instruments](../../SolidInstruments.Logo.Color.Transparent.500w.png)](../../README.md) +
     +![Web](../../doc/images/Label.Web.300w.png) +- - - + +# RapidField.SolidInstruments.Web + +This document describes the purpose of the [`RapidField.SolidInstruments.Web`]() library and offers guidance with respect to licensing, installation and usage. + +## Features + +This library exposes types that simplify web application design. + +## 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. + +## Documentation + +[![Documentation](https://img.shields.io/badge/documentation-website-tan?style=flat&logo=buffer&logoColor=lightgrey)](https://www.solidinstruments.com/api/RapidField.SolidInstruments.Web.html) + +Check out the [**API Reference**](https://www.solidinstruments.com/api/RapidField.SolidInstruments.Web.html) for usage examples and reference documentation. + +## Installation + +[![Version](https://img.shields.io/nuget/vpre/RapidField.SolidInstruments.Web?style=flat&color=blue&label=version&logo=nuget&logoColor=lightgrey)](https://www.nuget.org/packages/RapidField.SolidInstruments.Web) +[![Downloads](https://img.shields.io/nuget/dt/RapidField.SolidInstruments.Web?style=flat&color=blue&logo=nuget&logoColor=lightgrey)](https://www.nuget.org/packages/RapidField.SolidInstruments.Web) + +This library is available via [**NuGet**](https://docs.microsoft.com/en-us/nuget/quickstart/install-and-use-a-package-in-visual-studio). Use one of the commands below to download and install the library and all of its dependencies. + +###### .NET CLI + +```shell +dotnet add package RapidField.SolidInstruments.Web +``` + +###### NuGet Package Manager + +```shell +Install-Package RapidField.SolidInstruments.Web +``` + +
+ +- - - + +
+ +[![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/src/RapidField.SolidInstruments.Web/RapidField.SolidInstruments.Web.csproj b/src/RapidField.SolidInstruments.Web/RapidField.SolidInstruments.Web.csproj new file mode 100644 index 00000000..012608a1 --- /dev/null +++ b/src/RapidField.SolidInstruments.Web/RapidField.SolidInstruments.Web.csproj @@ -0,0 +1,48 @@ + + + + + Solid Instruments contributors + RapidField + Copyright (c) RapidField LLC. All rights reserved. + Solid Instruments + This library exposes types that simplify web application design. + $(BuildVersion) + netstandard2.1 + latest + git + https://github.com/rapidfield/solid-instruments + true + true + LICENSE.txt + https://www.solidinstruments.com + Icon.Web.128w.png + solid-instruments;web;web-application + + + bin\Debug\netstandard2.1\RapidField.SolidInstruments.Web.xml + true + + + + bin\Release\netstandard2.1\RapidField.SolidInstruments.Web.xml + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web/WebExecutionException.cs b/src/RapidField.SolidInstruments.Web/WebExecutionException.cs new file mode 100644 index 00000000..f94823f8 --- /dev/null +++ b/src/RapidField.SolidInstruments.Web/WebExecutionException.cs @@ -0,0 +1,50 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using System; + +namespace RapidField.SolidInstruments.Web +{ + /// + /// Represents an exception that is raised during web application execution. + /// + public class WebExectuionException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public WebExectuionException() + : base() + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The error message that explains the reason for the exception. + /// + public WebExectuionException(String message) + : base(message) + { + return; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The error message that explains the reason for the exception. + /// + /// + /// The exception that is the cause of the current exception. + /// + public WebExectuionException(String message, Exception innerException) + : base(message, innerException) + { + return; + } + } +} \ No newline at end of file diff --git a/src/RapidField.SolidInstruments.Web/WebExecutor.cs b/src/RapidField.SolidInstruments.Web/WebExecutor.cs new file mode 100644 index 00000000..ad48d54a --- /dev/null +++ b/src/RapidField.SolidInstruments.Web/WebExecutor.cs @@ -0,0 +1,409 @@ +// ================================================================================================================================= +// Copyright (c) RapidField LLC. Licensed under the MIT License. See LICENSE.txt in the project root for license information. +// ================================================================================================================================= + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using RapidField.SolidInstruments.Core; +using RapidField.SolidInstruments.Core.ArgumentValidation; +using RapidField.SolidInstruments.Core.Extensions; +using RapidField.SolidInstruments.InversionOfControl; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading; +using WebHostInitializer = Microsoft.AspNetCore.WebHost; + +namespace RapidField.SolidInstruments.Web +{ + /// + /// Prepares for and performs execution of a web application. + /// + /// + /// is the default implementation of + /// . + /// + /// + /// The type of the package that configures the dependency engine. + /// + /// + /// The type of the object that configures the dependency container. + /// + /// + /// The type of the dependency engine that is produced by the dependency package. + /// + public abstract class WebExecutor : Instrument, IWebExecutor + where TDependencyPackage : class, IDependencyPackage, new() + where TDependencyConfigurator : class, new() + where TDependencyEngine : class, IDependencyEngine + { + /// + /// Initializes a new instance of the + /// class. + /// + /// + /// The name of the web application. + /// + /// + /// is empty. + /// + /// + /// is . + /// + protected WebExecutor(String applicationName) + : base() + { + ApplicationName = applicationName.Trim().RejectIf().IsNullOrEmpty(nameof(applicationName)); + CommandLineArguments = null; + LazyApplicationConfiguration = new Lazy(CreateApplicationConfiguration, LazyThreadSafetyMode.ExecutionAndPublication); + LazyDependencyEngine = new Lazy(CreateDependencyEngine, LazyThreadSafetyMode.ExecutionAndPublication); + LazyRootDependencyScope = new Lazy(DependencyEngine.Container.CreateScope, LazyThreadSafetyMode.ExecutionAndPublication); + LazyWebHost = new Lazy(CreateWebHost, LazyThreadSafetyMode.ExecutionAndPublication); + ReferenceManager = new ReferenceManager(); + } + + /// + /// Begins execution of the web application. + /// + /// + /// An exception was raised during execution of the web application. + /// + public void Execute() => Execute(Array.Empty()); + + /// + /// Begins execution of the web application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + /// + /// An exception was raised during execution of the web application. + /// + public void Execute(String[] commandLineArguments) + { + CommandLineArguments = commandLineArguments ?? Array.Empty(); + + try + { + var productName = ProductName?.Trim(); + var applicationName = ApplicationName?.Trim(); + var copyrightNotice = CopyrightNotice?.Trim(); + + if (productName.IsNullOrEmpty() == false) + { + Console.WriteLine(productName); + } + + if (applicationName.IsNullOrEmpty() == false) + { + Console.WriteLine(applicationName); + } + + if (copyrightNotice.IsNullOrEmpty() == false) + { + Console.WriteLine(copyrightNotice); + } + + Console.WriteLine($"{Environment.NewLine}Web application execution starting."); + + try + { + var webHost = WebHost; // Do not move this line. + + using (var dependencyScope = CreateDependencyScope()) + { + Execute(webHost, dependencyScope, ApplicationConfiguration, CommandLineArguments); + } + } + catch (WebExectuionException) + { + throw; + } + catch (Exception exception) + { + throw new WebExectuionException($"An exception was raised during execution of the web application: \"{ApplicationName}\". See inner exception.", exception); + } + } + catch (WebExectuionException exception) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"{exception.Message} : {exception.StackTrace}{Environment.NewLine}"); + Console.ResetColor(); + throw; + } + finally + { + Console.WriteLine("Web application execution finished."); + } + } + + /// + /// Converts the value of the current + /// to its equivalent string + /// representation. + /// + /// + /// A string representation of the current + /// . + /// + public override String ToString() => $"{{ \"{nameof(ApplicationName)}\": \"{ApplicationName}\" }}"; + + /// + /// Builds the application configuration for the web application. + /// + /// + /// The default implementation of the this method adds: + /// - environment variables with prefixes matching any of , + /// - all command line arguments supplied to and + /// - the appsettings.json file in the root application path. + /// + /// + /// An object that is used to build the configuration. + /// + protected virtual void BuildConfiguration(IConfigurationBuilder configurationBuilder) + { + foreach (var prefix in EnvironmentVariableConfigurationPrefixes) + { + _ = configurationBuilder.AddEnvironmentVariables(prefix); + } + + if (CommandLineArguments.IsNullOrEmpty() == false) + { + _ = configurationBuilder.AddCommandLine(CommandLineArguments); + } + + _ = configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile(DefaultAppSettingsJsonFileName); + } + + /// + /// Configures the application's request pipeline. + /// + /// + /// An object that configures the application's request pipeline. + /// + /// + /// Configuration information for the web application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + protected virtual void ConfigureApplication(IApplicationBuilder application, IConfiguration applicationConfiguration, String[] commandLineArguments) + { + return; + } + + /// + /// Creates a new dependency scope. + /// + /// + /// A new dependency scope. + /// + /// + /// An exception was raised while attempting to create the scope. + /// + /// + /// The object is disposed. + /// + protected IDependencyScope CreateDependencyScope() => RootDependencyScope.CreateChildScope(); + + /// + /// Releases all resources consumed by the current + /// . + /// + /// + /// A value indicating whether or not managed resources should be released. + /// + protected override void Dispose(Boolean disposing) + { + try + { + if (disposing) + { + LazyRootDependencyScope.Dispose(); + LazyDependencyEngine.Dispose(); + ReferenceManager.Dispose(); + } + } + finally + { + base.Dispose(disposing); + } + } + + /// + /// Begins execution of the web application. + /// + /// + /// A configured web host. + /// + /// + /// A scope that is used to resolve web application dependencies. + /// + /// + /// Configuration information for the web application. + /// + /// + /// Command line arguments that are provided at runtime, if any. + /// + protected virtual void Execute(IWebHost webHost, IDependencyScope dependencyScope, IConfiguration applicationConfiguration, String[] commandLineArguments) => webHost.Start(); + + /// + /// Creates configuration information for the web application. + /// + /// + /// Configuration information for the web application. + /// + [DebuggerHidden] + private IConfiguration CreateApplicationConfiguration() + { + var configurationBuilder = new ConfigurationBuilder(); + BuildConfiguration(configurationBuilder); + return configurationBuilder.Build(); + } + + /// + /// Creates the dependency engine for the web application. + /// + /// + /// The dependency engine for the web application. + /// + [DebuggerHidden] + private IDependencyEngine CreateDependencyEngine() + { + var dependencyPackage = new TDependencyPackage(); + return dependencyPackage.CreateEngine(ApplicationConfiguration, ServiceDescriptors); + } + + /// + /// Creates the web application host. + /// + /// + /// The web application host. + /// + [DebuggerHidden] + private IWebHost CreateWebHost() => WebHostInitializer.CreateDefaultBuilder() + .UseConfiguration(ApplicationConfiguration) + .Configure(application => + { + ConfigureApplication(application, ApplicationConfiguration, CommandLineArguments); + }) + .ConfigureServices(services => + { + foreach (var serviceDescritor in services) + { + ServiceDescriptors.TryAdd(serviceDescritor); + } + }) + .Configure(application => + { + application.ApplicationServices = DependencyEngine.Provider; + }) + .Build(); + + /// + /// Gets the name of the web application. + /// + public String ApplicationName + { + get; + } + + /// + /// Gets configuration information for the web application. + /// + protected IConfiguration ApplicationConfiguration => LazyApplicationConfiguration.Value; + + /// + /// When overridden by a derived class, gets a copyright notice which is written to the console at the start of web + /// application execution. + /// + protected virtual String CopyrightNotice => null; + + /// + /// When overridden by a derived class, gets a collection of textual prefixes which are used by + /// to find and add environment variables to + /// . + /// + protected virtual IEnumerable EnvironmentVariableConfigurationPrefixes => Array.Empty(); + + /// + /// When overridden by a derived class, gets a product name associated with the web application which is written to the + /// console at the start of web application execution. + /// + protected virtual String ProductName => null; + + /// + /// Gets a utility that disposes of the object references that are managed by the current + /// . + /// + protected IReferenceManager ReferenceManager + { + get; + } + + /// + /// Gets the dependency engine for the web application. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private IDependencyEngine DependencyEngine => LazyDependencyEngine.Value; + + /// + /// Gets the root dependency scope for the web application. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private IDependencyScope RootDependencyScope => LazyRootDependencyScope.Value; + + /// + /// Gets the web application host. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private IWebHost WebHost => LazyWebHost.Value; + + /// + /// Represents the command line arguments that were provided at runtime, if any. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + internal String[] CommandLineArguments; + + /// + /// Represents the default JSON settings file name which is used by + /// to add file-based configuration to . + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private const String DefaultAppSettingsJsonFileName = "appsettings.json"; + + /// + /// Represents lazily-initialized configuration information for the web application. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly Lazy LazyApplicationConfiguration; + + /// + /// Represents the lazily-initialized dependency engine for the web application. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly Lazy LazyDependencyEngine; + + /// + /// Represents the lazily-initialized root dependency scope for the web application. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly Lazy LazyRootDependencyScope; + + /// + /// Represents the lazily-initialized web application host. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly Lazy LazyWebHost; + + /// + /// Represents a collection of configured service descriptors. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly IServiceCollection ServiceDescriptors = new ServiceCollection(); + } +} \ No newline at end of file diff --git a/test/RapidField.SolidInstruments.Messaging.InMemory.UnitTests/SimulatedMessagingServiceExecutorTests.cs b/test/RapidField.SolidInstruments.Messaging.InMemory.UnitTests/SimulatedMessagingServiceExecutorTests.cs index 9f6ffb4f..7f3117e7 100644 --- a/test/RapidField.SolidInstruments.Messaging.InMemory.UnitTests/SimulatedMessagingServiceExecutorTests.cs +++ b/test/RapidField.SolidInstruments.Messaging.InMemory.UnitTests/SimulatedMessagingServiceExecutorTests.cs @@ -51,7 +51,7 @@ private void OnStopping(ICommandMediator mediator) mediator.Process(new CreateCustomerCommandMessage(new CreateCustomerCommand(smithIndustriesCustomer))); // Assert. - Thread.Sleep(6765); + Thread.Sleep(10946); SimulatedServiceState.Customers.Should().HaveCount(2); // Act.