diff --git a/.github/workflows/pr_ci.yml b/.github/workflows/pr_ci.yml
index 7dcde8681af..19a2d28215d 100644
--- a/.github/workflows/pr_ci.yml
+++ b/.github/workflows/pr_ci.yml
@@ -24,6 +24,13 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'
+ dotnet-quality: 'preview'
+ - name: Update Workload
+ run: |
+ dotnet workload update --from-previous-sdk
+ - name: Setup Aspire
+ run: |
+ dotnet workload install aspire
- name: Build
run: |
dotnet build -c Release
diff --git a/OrchardCore.sln b/OrchardCore.sln
index 012a41a30d5..c9f860434f2 100644
--- a/OrchardCore.sln
+++ b/OrchardCore.sln
@@ -507,6 +507,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Sms", "src\Orch
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Sms.Core", "src\OrchardCore\OrchardCore.Sms.Core\OrchardCore.Sms.Core.csproj", "{20356393-B16D-466C-8203-877A534E287D}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.AppHost", "src\Aspire\Aspire.AppHost\Aspire.AppHost.csproj", "{B8A5D532-1F7D-40ED-B6B0-BE36C8B81D91}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.ServiceDefaults", "src\Aspire\Aspire.ServiceDefaults\Aspire.ServiceDefaults.csproj", "{C2BB6BBB-4F5F-4D2F-975D-D50DD38FCABF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aspire", "Aspire", "{5DC4B8E4-9BE0-4B57-8065-7DC0A44DBD20}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.OrchardCore.Cms.Web", "src\Aspire\Aspire.OrchardCore.Cms.Web\Aspire.OrchardCore.Cms.Web.csproj", "{3DE87BB4-BA03-4C02-861F-6EE51898E682}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspire.OrchardCore.Mvc.Web", "src\Aspire\Aspire.OrchardCore.Mvc.Web\Aspire.OrchardCore.Mvc.Web.csproj", "{59D2CC21-A422-42D5-8118-C16B7EE52F77}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Search.AzureAI", "src\OrchardCore.Modules\OrchardCore.Search.AzureAI\OrchardCore.Search.AzureAI.csproj", "{5527BACF-FA5D-4617-978B-7EDE8942E6F6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Search.AzureAI.Core", "src\OrchardCore\OrchardCore.Search.AzureAI.Core\OrchardCore.Search.AzureAI.Core.csproj", "{E9428DE8-5D81-4359-BF84-31435041FF1A}"
@@ -1339,6 +1348,22 @@ Global
{20356393-B16D-466C-8203-877A534E287D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20356393-B16D-466C-8203-877A534E287D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20356393-B16D-466C-8203-877A534E287D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8A5D532-1F7D-40ED-B6B0-BE36C8B81D91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B8A5D532-1F7D-40ED-B6B0-BE36C8B81D91}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8A5D532-1F7D-40ED-B6B0-BE36C8B81D91}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B8A5D532-1F7D-40ED-B6B0-BE36C8B81D91}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C2BB6BBB-4F5F-4D2F-975D-D50DD38FCABF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C2BB6BBB-4F5F-4D2F-975D-D50DD38FCABF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C2BB6BBB-4F5F-4D2F-975D-D50DD38FCABF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C2BB6BBB-4F5F-4D2F-975D-D50DD38FCABF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3DE87BB4-BA03-4C02-861F-6EE51898E682}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3DE87BB4-BA03-4C02-861F-6EE51898E682}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3DE87BB4-BA03-4C02-861F-6EE51898E682}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3DE87BB4-BA03-4C02-861F-6EE51898E682}.Release|Any CPU.Build.0 = Release|Any CPU
+ {59D2CC21-A422-42D5-8118-C16B7EE52F77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {59D2CC21-A422-42D5-8118-C16B7EE52F77}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {59D2CC21-A422-42D5-8118-C16B7EE52F77}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {59D2CC21-A422-42D5-8118-C16B7EE52F77}.Release|Any CPU.Build.0 = Release|Any CPU
{5527BACF-FA5D-4617-978B-7EDE8942E6F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5527BACF-FA5D-4617-978B-7EDE8942E6F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5527BACF-FA5D-4617-978B-7EDE8942E6F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -1578,6 +1603,11 @@ Global
{2D93F509-1FB3-4E22-92F0-588D0EFBA921} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
{CBF6DB53-FD0C-47F8-9E60-A1D247ACFD05} = {A066395F-6F73-45DC-B5A6-B4E306110DCE}
{20356393-B16D-466C-8203-877A534E287D} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
+ {B8A5D532-1F7D-40ED-B6B0-BE36C8B81D91} = {5DC4B8E4-9BE0-4B57-8065-7DC0A44DBD20}
+ {C2BB6BBB-4F5F-4D2F-975D-D50DD38FCABF} = {5DC4B8E4-9BE0-4B57-8065-7DC0A44DBD20}
+ {5DC4B8E4-9BE0-4B57-8065-7DC0A44DBD20} = {275E087F-A4E2-4A7B-A924-ED68E3A52086}
+ {3DE87BB4-BA03-4C02-861F-6EE51898E682} = {5DC4B8E4-9BE0-4B57-8065-7DC0A44DBD20}
+ {59D2CC21-A422-42D5-8118-C16B7EE52F77} = {5DC4B8E4-9BE0-4B57-8065-7DC0A44DBD20}
{5527BACF-FA5D-4617-978B-7EDE8942E6F6} = {90030E85-0C4F-456F-B879-443E8A3F220D}
{E9428DE8-5D81-4359-BF84-31435041FF1A} = {F23AC6C2-DE44-4699-999D-3C478EF3D691}
EndGlobalSection
diff --git a/src/Aspire/Aspire.AppHost/Aspire.AppHost.csproj b/src/Aspire/Aspire.AppHost/Aspire.AppHost.csproj
new file mode 100644
index 00000000000..5f4dcd6bb78
--- /dev/null
+++ b/src/Aspire/Aspire.AppHost/Aspire.AppHost.csproj
@@ -0,0 +1,21 @@
+
+
+
+ Exe
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Aspire/Aspire.AppHost/Program.cs b/src/Aspire/Aspire.AppHost/Program.cs
new file mode 100644
index 00000000000..e0f47e57d24
--- /dev/null
+++ b/src/Aspire/Aspire.AppHost/Program.cs
@@ -0,0 +1,10 @@
+var builder = DistributedApplication.CreateBuilder(args);
+
+var redis = builder.AddRedisContainer("Redis", 50963);
+
+builder.AddProject("OrchardCore CMS App")
+ .WithReference(redis);
+
+builder.AddProject("OrchardCore MVC App");
+
+await builder.Build().RunAsync();
diff --git a/src/Aspire/Aspire.AppHost/Properties/launchSettings.json b/src/Aspire/Aspire.AppHost/Properties/launchSettings.json
new file mode 100644
index 00000000000..6296f010cc7
--- /dev/null
+++ b/src/Aspire/Aspire.AppHost/Properties/launchSettings.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:15139",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16125"
+ }
+ }
+ }
+}
diff --git a/src/Aspire/Aspire.AppHost/appsettings.Development.json b/src/Aspire/Aspire.AppHost/appsettings.Development.json
new file mode 100644
index 00000000000..0c208ae9181
--- /dev/null
+++ b/src/Aspire/Aspire.AppHost/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/src/Aspire/Aspire.AppHost/appsettings.json b/src/Aspire/Aspire.AppHost/appsettings.json
new file mode 100644
index 00000000000..31c092aa450
--- /dev/null
+++ b/src/Aspire/Aspire.AppHost/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Aspire.Hosting.Dcp": "Warning"
+ }
+ }
+}
diff --git a/src/Aspire/Aspire.OrchardCore.Cms.Web/Aspire.OrchardCore.Cms.Web.csproj b/src/Aspire/Aspire.OrchardCore.Cms.Web/Aspire.OrchardCore.Cms.Web.csproj
new file mode 100644
index 00000000000..dc7cff0639c
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Cms.Web/Aspire.OrchardCore.Cms.Web.csproj
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Aspire/Aspire.OrchardCore.Cms.Web/Localization/.placeholder b/src/Aspire/Aspire.OrchardCore.Cms.Web/Localization/.placeholder
new file mode 100644
index 00000000000..95c193c13ef
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Cms.Web/Localization/.placeholder
@@ -0,0 +1 @@
+# This file is used to ensure the Localization folder is created during deployment
diff --git a/src/Aspire/Aspire.OrchardCore.Cms.Web/NLog.config b/src/Aspire/Aspire.OrchardCore.Cms.Web/NLog.config
new file mode 100644
index 00000000000..8d4eef2d62b
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Cms.Web/NLog.config
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Aspire/Aspire.OrchardCore.Cms.Web/Program.cs b/src/Aspire/Aspire.OrchardCore.Cms.Web/Program.cs
new file mode 100644
index 00000000000..772eb0500ad
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Cms.Web/Program.cs
@@ -0,0 +1,41 @@
+using OrchardCore.Logging;
+
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Host.UseNLogHost();
+builder.AddServiceDefaults();
+
+var ocBuilder = builder.Services
+ .AddOrchardCms()
+ .AddSetupFeatures("OrchardCore.AutoSetup");
+
+if (builder.Configuration.GetValue("EnableAzureCoreFeatures"))
+{
+ // Enable Azure based resources to store the shell configs and the data protections.
+ ocBuilder.AddAzureShellsConfiguration()
+ .AddGlobalFeatures("OrchardCore.DataProtection.Azure");
+}
+
+if (builder.Configuration.GetValue("EnableRedisCache"))
+{
+ ocBuilder.AddSetupFeatures("OrchardCore.Redis", "OrchardCore.Redis.Lock")
+ .AddGlobalFeatures("OrchardCore.Redis", "OrchardCore.Redis.Cache", "OrchardCore.Redis.DataProtection", "OrchardCore.Redis.Lock");
+}
+
+if (builder.Configuration.GetValue("EnableAzureStorage"))
+{
+ ocBuilder.AddTenantFeatures("OrchardCore.Media.Azure.Storage");
+}
+
+var app = builder.Build();
+
+if (!app.Environment.IsDevelopment())
+{
+ app.UseExceptionHandler("/Error");
+}
+
+app.UseStaticFiles();
+
+app.UseOrchardCore();
+
+await app.RunAsync();
diff --git a/src/Aspire/Aspire.OrchardCore.Cms.Web/Properties/launchSettings.json b/src/Aspire/Aspire.OrchardCore.Cms.Web/Properties/launchSettings.json
new file mode 100644
index 00000000000..448ea2ff178
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Cms.Web/Properties/launchSettings.json
@@ -0,0 +1,38 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:23843",
+ "sslPort": 44303
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:5084",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:7179;http://localhost:5084",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/src/Aspire/Aspire.OrchardCore.Cms.Web/appsettings.Development.json b/src/Aspire/Aspire.OrchardCore.Cms.Web/appsettings.Development.json
new file mode 100644
index 00000000000..0c208ae9181
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Cms.Web/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/src/Aspire/Aspire.OrchardCore.Cms.Web/appsettings.json b/src/Aspire/Aspire.OrchardCore.Cms.Web/appsettings.json
new file mode 100644
index 00000000000..261a52e72a6
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Cms.Web/appsettings.json
@@ -0,0 +1,17 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "EnableAzureCoreFeatures": false,
+ "EnableAzureStorage": false,
+ "EnableRedisCache": true,
+ "OrchardCore": {
+ "OrchardCore_Redis": {
+ "Configuration": "127.0.0.1:50963,allowAdmin=true",
+ "InstancePrefix": ""
+ }
+ }
+}
diff --git a/src/Aspire/Aspire.OrchardCore.Mvc.Web/Aspire.OrchardCore.Mvc.Web.csproj b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Aspire.OrchardCore.Mvc.Web.csproj
new file mode 100644
index 00000000000..7a46d082b87
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Aspire.OrchardCore.Mvc.Web.csproj
@@ -0,0 +1,19 @@
+
+
+
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Aspire/Aspire.OrchardCore.Mvc.Web/Models/ErrorViewModel.cs b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Models/ErrorViewModel.cs
new file mode 100644
index 00000000000..41677d219d4
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Models/ErrorViewModel.cs
@@ -0,0 +1,8 @@
+namespace Aspire.OrchardCore.Mvc.Web.Models;
+
+public class ErrorViewModel
+{
+ public string? RequestId { get; set; }
+
+ public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
+}
diff --git a/src/Aspire/Aspire.OrchardCore.Mvc.Web/Program.cs b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Program.cs
new file mode 100644
index 00000000000..10957c770d8
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Program.cs
@@ -0,0 +1,20 @@
+var builder = WebApplication.CreateBuilder(args);
+
+builder.AddServiceDefaults();
+
+builder.Services
+ .AddOrchardCore()
+ .AddMvc();
+
+var app = builder.Build();
+
+if (!app.Environment.IsDevelopment())
+{
+ app.UseExceptionHandler("/Error");
+}
+
+app.UseStaticFiles();
+
+app.UseOrchardCore();
+
+await app.RunAsync();
diff --git a/src/Aspire/Aspire.OrchardCore.Mvc.Web/Properties/launchSettings.json b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Properties/launchSettings.json
new file mode 100644
index 00000000000..f47de3dde58
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Properties/launchSettings.json
@@ -0,0 +1,38 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:41929",
+ "sslPort": 44395
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:5287",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:7244;http://localhost:5287",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/src/Aspire/Aspire.OrchardCore.Mvc.Web/Views/Shared/_Layout.cshtml b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Views/Shared/_Layout.cshtml
new file mode 100644
index 00000000000..d550057bd4a
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Views/Shared/_Layout.cshtml
@@ -0,0 +1,46 @@
+
+
+
+
+
+ @ViewData["Title"] - MvcSandbox
+
+
+
+
+
+
+
+
+
+
+ @RenderSection("scripts", required: false)
+
+
diff --git a/src/OrchardCore.Mvc.Web/_ViewImports.cshtml b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Views/_ViewImports.cshtml
similarity index 100%
rename from src/OrchardCore.Mvc.Web/_ViewImports.cshtml
rename to src/Aspire/Aspire.OrchardCore.Mvc.Web/Views/_ViewImports.cshtml
diff --git a/src/OrchardCore.Mvc.Web/_ViewStart.cshtml b/src/Aspire/Aspire.OrchardCore.Mvc.Web/Views/_ViewStart.cshtml
similarity index 100%
rename from src/OrchardCore.Mvc.Web/_ViewStart.cshtml
rename to src/Aspire/Aspire.OrchardCore.Mvc.Web/Views/_ViewStart.cshtml
diff --git a/src/Aspire/Aspire.OrchardCore.Mvc.Web/appsettings.Development.json b/src/Aspire/Aspire.OrchardCore.Mvc.Web/appsettings.Development.json
new file mode 100644
index 00000000000..0c208ae9181
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Mvc.Web/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/src/Aspire/Aspire.OrchardCore.Mvc.Web/appsettings.json b/src/Aspire/Aspire.OrchardCore.Mvc.Web/appsettings.json
new file mode 100644
index 00000000000..9c0b05b1642
--- /dev/null
+++ b/src/Aspire/Aspire.OrchardCore.Mvc.Web/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*",
+ "Sample": "Sample Value"
+}
diff --git a/src/Aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj b/src/Aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj
new file mode 100644
index 00000000000..52455379fbd
--- /dev/null
+++ b/src/Aspire/Aspire.ServiceDefaults/Aspire.ServiceDefaults.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Library
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Aspire/Aspire.ServiceDefaults/Extensions.cs b/src/Aspire/Aspire.ServiceDefaults/Extensions.cs
new file mode 100644
index 00000000000..c59308d50da
--- /dev/null
+++ b/src/Aspire/Aspire.ServiceDefaults/Extensions.cs
@@ -0,0 +1,119 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Logging;
+using OpenTelemetry.Logs;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
+
+namespace Microsoft.Extensions.Hosting;
+
+public static class Extensions
+{
+ public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
+ {
+ builder.ConfigureOpenTelemetry();
+
+ builder.AddDefaultHealthChecks();
+
+ builder.Services.AddServiceDiscovery();
+
+ builder.Services.ConfigureHttpClientDefaults(http =>
+ {
+ // Turn on resilience by default
+ http.AddStandardResilienceHandler();
+
+ // Turn on service discovery by default
+ http.UseServiceDiscovery();
+ });
+
+ return builder;
+ }
+
+ public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
+ {
+ builder.Logging.AddOpenTelemetry(logging =>
+ {
+ logging.IncludeFormattedMessage = true;
+ logging.IncludeScopes = true;
+ });
+
+ builder.Services.AddOpenTelemetry()
+ .WithMetrics(metrics =>
+ {
+ metrics.AddRuntimeInstrumentation()
+ .AddBuiltInMeters();
+ })
+ .WithTracing(tracing =>
+ {
+ if (builder.Environment.IsDevelopment())
+ {
+ // We want to view all traces in development
+ tracing.SetSampler(new AlwaysOnSampler());
+ }
+
+ tracing.AddAspNetCoreInstrumentation()
+ .AddGrpcClientInstrumentation()
+ .AddHttpClientInstrumentation();
+ });
+
+ builder.AddOpenTelemetryExporters();
+
+ return builder;
+ }
+
+ private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder)
+ {
+ var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+
+ if (useOtlpExporter)
+ {
+ builder.Services.Configure(logging => logging.AddOtlpExporter());
+ builder.Services.ConfigureOpenTelemetryMeterProvider(metrics => metrics.AddOtlpExporter());
+ builder.Services.ConfigureOpenTelemetryTracerProvider(tracing => tracing.AddOtlpExporter());
+ }
+
+ // Uncomment the following lines to enable the Prometheus exporter (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package)
+ // builder.Services.AddOpenTelemetry()
+ // .WithMetrics(metrics => metrics.AddPrometheusExporter());
+
+ // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.Exporter package)
+ // builder.Services.AddOpenTelemetry()
+ // .UseAzureMonitor();
+
+ return builder;
+ }
+
+ public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder)
+ {
+ builder.Services.AddHealthChecks()
+ // Add a default liveness check to ensure app is responsive
+ .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
+
+ return builder;
+ }
+
+ public static WebApplication MapDefaultEndpoints(this WebApplication app)
+ {
+ // Uncomment the following line to enable the Prometheus endpoint (requires the OpenTelemetry.Exporter.Prometheus.AspNetCore package)
+ // app.MapPrometheusScrapingEndpoint();
+
+ // All health checks must pass for app to be considered ready to accept traffic after starting
+ app.MapHealthChecks("/health");
+
+ // Only health checks tagged with the "live" tag must pass for app to be considered alive
+ app.MapHealthChecks("/alive", new HealthCheckOptions
+ {
+ Predicate = r => r.Tags.Contains("live")
+ });
+
+ return app;
+ }
+
+ private static MeterProviderBuilder AddBuiltInMeters(this MeterProviderBuilder meterProviderBuilder) =>
+ meterProviderBuilder.AddMeter(
+ "Microsoft.AspNetCore.Hosting",
+ "Microsoft.AspNetCore.Server.Kestrel",
+ "System.Net.Http");
+}
diff --git a/src/Aspire/Directory.Build.props b/src/Aspire/Directory.Build.props
new file mode 100644
index 00000000000..77240662b47
--- /dev/null
+++ b/src/Aspire/Directory.Build.props
@@ -0,0 +1,13 @@
+
+
+
+
+ net8.0
+ enable
+ False
+ False
+ false
+ 612,618
+
+
+
diff --git a/src/OrchardCore.Cms.Web/Program.cs b/src/OrchardCore.Cms.Web/Program.cs
index 4b4d39392bd..f5e06716d21 100644
--- a/src/OrchardCore.Cms.Web/Program.cs
+++ b/src/OrchardCore.Cms.Web/Program.cs
@@ -19,4 +19,4 @@
app.UseOrchardCore();
-app.Run();
+await app.RunAsync();
diff --git a/src/OrchardCore.Cms.Web/wwwroot/.placeholder b/src/OrchardCore.Cms.Web/wwwroot/.placeholder
index 46b134b197f..8b137891791 100644
--- a/src/OrchardCore.Cms.Web/wwwroot/.placeholder
+++ b/src/OrchardCore.Cms.Web/wwwroot/.placeholder
@@ -1 +1 @@
-ÿþ
\ No newline at end of file
+
diff --git a/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/OrchardCore.Mvc.HelloWorld.csproj b/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/OrchardCore.Mvc.HelloWorld.csproj
index c3c14a820a3..17cfec99d09 100644
--- a/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/OrchardCore.Mvc.HelloWorld.csproj
+++ b/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/OrchardCore.Mvc.HelloWorld.csproj
@@ -10,6 +10,22 @@
$(PackageTags) OrchardCoreFramework
+
+
+
+
+
+
+
+ true
+ PreserveNewest
+
+
+ true
+ PreserveNewest
+
+
+
diff --git a/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/Views/_ViewImports.cshtml b/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/Views/_ViewImports.cshtml
new file mode 100644
index 00000000000..a757b413b92
--- /dev/null
+++ b/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/Views/_ViewImports.cshtml
@@ -0,0 +1 @@
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
diff --git a/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/Views/_ViewStart.cshtml b/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/Views/_ViewStart.cshtml
new file mode 100644
index 00000000000..2de62418c07
--- /dev/null
+++ b/src/OrchardCore.Modules/OrchardCore.Mvc.HelloWorld/Views/_ViewStart.cshtml
@@ -0,0 +1,3 @@
+@{
+ Layout = "~/Views/Shared/_Layout.cshtml";
+}
diff --git a/src/OrchardCore.Mvc.Web/Program.cs b/src/OrchardCore.Mvc.Web/Program.cs
index d93a0dc32b3..785623cd759 100644
--- a/src/OrchardCore.Mvc.Web/Program.cs
+++ b/src/OrchardCore.Mvc.Web/Program.cs
@@ -15,4 +15,4 @@
app.UseOrchardCore();
-app.Run();
+await app.RunAsync();
diff --git a/src/OrchardCore.Mvc.Web/Views/_ViewImports.cshtml b/src/OrchardCore.Mvc.Web/Views/_ViewImports.cshtml
new file mode 100644
index 00000000000..a757b413b92
--- /dev/null
+++ b/src/OrchardCore.Mvc.Web/Views/_ViewImports.cshtml
@@ -0,0 +1 @@
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
diff --git a/src/OrchardCore.Mvc.Web/Views/_ViewStart.cshtml b/src/OrchardCore.Mvc.Web/Views/_ViewStart.cshtml
new file mode 100644
index 00000000000..2de62418c07
--- /dev/null
+++ b/src/OrchardCore.Mvc.Web/Views/_ViewStart.cshtml
@@ -0,0 +1,3 @@
+@{
+ Layout = "~/Views/Shared/_Layout.cshtml";
+}
diff --git a/src/README.md b/src/README.md
index 7f6d137faf0..799539d2d83 100644
--- a/src/README.md
+++ b/src/README.md
@@ -104,6 +104,11 @@ For more details on the various development tools we recommend for using with Or
Docker images and parameters can be found at
+### .NET Aspire
+
+The configuration of the OrchardCore solution is tailored for execution within the Aspire project. To initiate the Aspire project rather than the CMS directly, designate the `Aspire.AppHost` project as the startup project of the solution, then launch it. To run the Aspire project, [install .NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/setup-tooling?tabs=visual-studio) on your local machine. Ensure you have Docker Desktop installed, and you are using Visual Studio version 17.9.0 or later
+
+
## Showcasing Orchard Core CMS