diff --git a/.gitignore b/.gitignore
index 870ddfc7..2d0804d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -340,4 +340,7 @@ appsettings.json
**/MsDeploy
-*.feature.cs
\ No newline at end of file
+*.feature.cs
+
+# ignore local settings file that may contain secrets.
+/Solutions/Marain.Tenancy.Host.AspNetCore/appsettings.Development.json
diff --git a/Solutions/Docker.Compose/.dockerignore b/Solutions/Docker.Compose/.dockerignore
new file mode 100644
index 00000000..3729ff0c
--- /dev/null
+++ b/Solutions/Docker.Compose/.dockerignore
@@ -0,0 +1,25 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/Solutions/Docker.Compose/docker-compose.dcproj b/Solutions/Docker.Compose/docker-compose.dcproj
new file mode 100644
index 00000000..4726c6c7
--- /dev/null
+++ b/Solutions/Docker.Compose/docker-compose.dcproj
@@ -0,0 +1,20 @@
+
+
+
+ 2.1
+ Linux
+ e6ef3336-38d7-43ae-9840-6359f20db9c8
+ LaunchBrowser
+ {Scheme}://localhost:{ServicePort}/swagger
+ marain.tenancy.host.aspnetcore
+
+
+
+ docker-compose.yml
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Solutions/Docker.Compose/docker-compose.override.yml b/Solutions/Docker.Compose/docker-compose.override.yml
new file mode 100644
index 00000000..367efe70
--- /dev/null
+++ b/Solutions/Docker.Compose/docker-compose.override.yml
@@ -0,0 +1,8 @@
+version: '3.4'
+
+services:
+ marain.tenancy.host.aspnetcore:
+ environment:
+ - ASPNETCORE_ENVIRONMENT=Development
+ ports:
+ - "80"
diff --git a/Solutions/Docker.Compose/docker-compose.yml b/Solutions/Docker.Compose/docker-compose.yml
new file mode 100644
index 00000000..85cc8e33
--- /dev/null
+++ b/Solutions/Docker.Compose/docker-compose.yml
@@ -0,0 +1,15 @@
+version: '3.4'
+
+services:
+ marain.tenancy.host.aspnetcore:
+ image: ${DOCKER_REGISTRY-}maraintenancyhostaspnetcore
+ build:
+ context: ./../
+ dockerfile: Marain.Tenancy.Host.AspNetCore/Dockerfile
+
+ marain.tenancy.host.aspnetcore-dapr:
+ image: "daprio/daprd:latest"
+ command: [ "./daprd", "-app-id", "marain.tenancy.host.aspnetcore", "-app-port", "80" ]
+ depends_on:
+ - marain.tenancy.host.aspnetcore
+ network_mode: "service:marain.tenancy.host.aspnetcore"
\ No newline at end of file
diff --git a/Solutions/Marain.Tenancy.Host.AspNetCore/Dockerfile b/Solutions/Marain.Tenancy.Host.AspNetCore/Dockerfile
new file mode 100644
index 00000000..ab8d4d6f
--- /dev/null
+++ b/Solutions/Marain.Tenancy.Host.AspNetCore/Dockerfile
@@ -0,0 +1,23 @@
+#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
+WORKDIR /app
+EXPOSE 80
+
+FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
+WORKDIR /src
+COPY ["Marain.Tenancy.Host.AspNetCore/Marain.Tenancy.Host.AspNetCore.csproj", "Marain.Tenancy.Host.AspNetCore/"]
+COPY ["Marain.Tenancy.Hosting.AspNetCore/Marain.Tenancy.Hosting.AspNetCore.csproj", "Marain.Tenancy.Hosting.AspNetCore/"]
+COPY ["Marain.Tenancy.OpenApi.Service/Marain.Tenancy.OpenApi.Service.csproj", "Marain.Tenancy.OpenApi.Service/"]
+RUN dotnet restore "Marain.Tenancy.Host.AspNetCore/Marain.Tenancy.Host.AspNetCore.csproj"
+COPY . .
+WORKDIR "/src/Marain.Tenancy.Host.AspNetCore"
+RUN dotnet build "Marain.Tenancy.Host.AspNetCore.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "Marain.Tenancy.Host.AspNetCore.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "Marain.Tenancy.Host.AspNetCore.dll"]
\ No newline at end of file
diff --git a/Solutions/Marain.Tenancy.Host.AspNetCore/Marain.Tenancy.Host.AspNetCore.csproj b/Solutions/Marain.Tenancy.Host.AspNetCore/Marain.Tenancy.Host.AspNetCore.csproj
new file mode 100644
index 00000000..2d3c836b
--- /dev/null
+++ b/Solutions/Marain.Tenancy.Host.AspNetCore/Marain.Tenancy.Host.AspNetCore.csproj
@@ -0,0 +1,19 @@
+
+
+
+ net6.0
+ ..\docker-compose.dcproj
+ Linux
+ false
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Solutions/Marain.Tenancy.Host.AspNetCore/Program.cs b/Solutions/Marain.Tenancy.Host.AspNetCore/Program.cs
new file mode 100644
index 00000000..36b4916a
--- /dev/null
+++ b/Solutions/Marain.Tenancy.Host.AspNetCore/Program.cs
@@ -0,0 +1,25 @@
+namespace Marain.Tenancy.Host.AspNetCore
+{
+ using Microsoft.AspNetCore.Hosting;
+ using Microsoft.Extensions.Configuration;
+ using Microsoft.Extensions.Hosting;
+
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureAppConfiguration((hostingContext, config) =>
+ {
+ config.AddEnvironmentVariables();
+ })
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
\ No newline at end of file
diff --git a/Solutions/Marain.Tenancy.Host.AspNetCore/Properties/launchSettings.json b/Solutions/Marain.Tenancy.Host.AspNetCore/Properties/launchSettings.json
new file mode 100644
index 00000000..06ce2152
--- /dev/null
+++ b/Solutions/Marain.Tenancy.Host.AspNetCore/Properties/launchSettings.json
@@ -0,0 +1,35 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:44494",
+ "sslPort": 0
+ }
+ },
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "Marain.Tenancy.Host.AspNetCore": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "dotnetRunMessages": "true",
+ "applicationUrl": "http://localhost:5000"
+ },
+ "Docker": {
+ "commandName": "Docker",
+ "launchBrowser": true,
+ "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
+ "publishAllPorts": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/Solutions/Marain.Tenancy.Host.AspNetCore/Startup.cs b/Solutions/Marain.Tenancy.Host.AspNetCore/Startup.cs
new file mode 100644
index 00000000..5f52e34d
--- /dev/null
+++ b/Solutions/Marain.Tenancy.Host.AspNetCore/Startup.cs
@@ -0,0 +1,73 @@
+namespace Marain.Tenancy.Host.AspNetCore
+{
+ using System;
+
+ using Corvus.Storage.Azure.BlobStorage;
+
+ using Menes;
+ using Menes.Auditing.AuditLogSinks.Development;
+ using Menes.Hosting.AspNetCore;
+ using Microsoft.AspNetCore.Builder;
+ using Microsoft.AspNetCore.Hosting;
+ using Microsoft.Extensions.Configuration;
+ using Microsoft.Extensions.DependencyInjection;
+ using Microsoft.Extensions.Hosting;
+
+ public class Startup
+ {
+ public IConfiguration Configuration { get; }
+
+ public Startup(IConfiguration configuration)
+ {
+ this.Configuration = configuration;
+ }
+
+ // This method gets called by the runtime. Use this method to add services to the container.
+ // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddTenancyApiWithAspNetPipelineHosting(ConfigureOpenApiHost);
+ services.AddOpenApiAuditing();
+
+ BlobContainerConfiguration rootStorageConfiguration = this.Configuration
+ .GetSection("RootBlobStorageConfiguration")
+ .Get();
+
+ services.AddTenantStoreOnAzureBlobStorage(rootStorageConfiguration);
+
+#if DEBUG
+ services.AddAuditLogSink();
+#endif
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseMenesCatchAll();
+ }
+
+ // TODO: consolidate with functions startup code.
+ // This fixes a bug from that - the 2nd exception handler was wrong on two counts:
+ // 1. wrong exception type: if config is non-null and config.Documents is null, that's
+ // not ArgumentNullException
+ // 2. wrong argument order: we had the nameof and message flipped
+ // In any case, this startup is likely to be needed by any host, so we should put it
+ // somewhere common.
+ private static void ConfigureOpenApiHost(IOpenApiHostConfiguration config)
+ {
+ ArgumentNullException.ThrowIfNull(config);
+
+ if (config.Documents is null)
+ {
+ throw new ArgumentException("AddTenancyApi callback: config.Documents", nameof(config));
+ }
+
+ config.Documents.AddSwaggerEndpoint();
+ }
+ }
+}
diff --git a/Solutions/Marain.Tenancy.Host.AspNetCore/appsettings.template.json b/Solutions/Marain.Tenancy.Host.AspNetCore/appsettings.template.json
new file mode 100644
index 00000000..82efc507
--- /dev/null
+++ b/Solutions/Marain.Tenancy.Host.AspNetCore/appsettings.template.json
@@ -0,0 +1,15 @@
+// Rename to appsettings.development.json and remove this line.
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "TenantCloudBlobContainerFactoryOptions:AzureServicesAuthConnectionString": "",
+ "TenantCacheConfiguration:GetTenantResponseCacheControlHeaderValue": "max-age=300",
+ "RootBlobStorageConfiguration": {
+ "ConnectionStringPlainText": "DefaultEndpointsProtocol=https;AccountName=;AccountKey=;EndpointSuffix=core.windows.net"
+ }
+}
\ No newline at end of file
diff --git a/Solutions/Marain.Tenancy.Host.Functions/Marain/Tenancy/Functions/TenancyHost.cs b/Solutions/Marain.Tenancy.Host.Functions/Marain/Tenancy/Functions/TenancyHost.cs
index 94e06c69..ee842729 100644
--- a/Solutions/Marain.Tenancy.Host.Functions/Marain/Tenancy/Functions/TenancyHost.cs
+++ b/Solutions/Marain.Tenancy.Host.Functions/Marain/Tenancy/Functions/TenancyHost.cs
@@ -23,8 +23,7 @@ public class TenancyHost
/// Initializes a new instance of the class.
///
/// The OpenApi host.
- public TenancyHost(
- IOpenApiHost host)
+ public TenancyHost(IOpenApiHost host)
{
this.host = host;
}
diff --git a/Solutions/Marain.Tenancy.sln b/Solutions/Marain.Tenancy.sln
index f0f82dd2..c95befb6 100644
--- a/Solutions/Marain.Tenancy.sln
+++ b/Solutions/Marain.Tenancy.sln
@@ -31,6 +31,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marain.Tenancy.Storage.Azur
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marain.Tenancy.Storage.Azure.BlobStorage.Specs", "Marain.Tenancy.Storage.Azure.BlobStorage.Specs\Marain.Tenancy.Storage.Azure.BlobStorage.Specs.csproj", "{B9D61A6F-9330-4590-98F2-3A033C96CD2E}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marain.Tenancy.Host.AspNetCore", "Marain.Tenancy.Host.AspNetCore\Marain.Tenancy.Host.AspNetCore.csproj", "{039CF3D2-264A-4073-8CA0-612186FF809A}"
+EndProject
+Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "Docker.Compose\docker-compose.dcproj", "{E6EF3336-38D7-43AE-9840-6359F20DB9C8}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -77,6 +81,14 @@ Global
{B9D61A6F-9330-4590-98F2-3A033C96CD2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9D61A6F-9330-4590-98F2-3A033C96CD2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9D61A6F-9330-4590-98F2-3A033C96CD2E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {039CF3D2-264A-4073-8CA0-612186FF809A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {039CF3D2-264A-4073-8CA0-612186FF809A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {039CF3D2-264A-4073-8CA0-612186FF809A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {039CF3D2-264A-4073-8CA0-612186FF809A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E6EF3336-38D7-43AE-9840-6359F20DB9C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E6EF3336-38D7-43AE-9840-6359F20DB9C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E6EF3336-38D7-43AE-9840-6359F20DB9C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E6EF3336-38D7-43AE-9840-6359F20DB9C8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE