From 4b05406d403885cba37d1014a72758a8aeb98a61 Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Wed, 8 Oct 2025 15:00:03 +0200 Subject: [PATCH 01/35] Update Framework and Oqtane Theme to 5.3.8 Oqtane Framework https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/js/bootstrap.bundle.min.js https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css Oqtane Theme https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.8/cyborg/bootstrap.min.css --- Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs | 2 +- Oqtane.Shared/Shared/Constants.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs b/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs index 09725a29..3b611b88 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs +++ b/Oqtane.Client/Themes/OqtaneTheme/ThemeInfo.cs @@ -17,7 +17,7 @@ namespace Oqtane.Themes.OqtaneTheme Resources = new List() { // obtained from https://cdnjs.com/libraries/bootswatch - new Stylesheet("https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.7/cyborg/bootstrap.min.css", "sha512-/LQFzDeXqysGQ/POl5YOEjgVZH1BmqDHvshhnFIChf50bMGQ470qhUrsecD9MRCUwzwqRoshwAbmA2oTW4I6Yg==", "anonymous"), + new Stylesheet("https://cdnjs.cloudflare.com/ajax/libs/bootswatch/5.3.8/cyborg/bootstrap.min.css", "sha512-Sq+1MhDgkXwshbeZBKh8j5N7bjn56Jg40kyGm27FoBYEBPksAG+GcRwLEHT/UL4F/WdYUCl65IAQiGTANnBzLg==", "anonymous"), new Stylesheet("~/Theme.css"), new Script(Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous") } diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 9fc43717..749249e8 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -89,10 +89,10 @@ namespace Oqtane.Shared public const string DefaultTextEditor = "Oqtane.Modules.Controls.RadzenTextEditor, Oqtane.Client"; // obtained from https://cdnjs.com/libraries/bootstrap - public const string BootstrapScriptUrl = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/js/bootstrap.bundle.min.js"; - public const string BootstrapScriptIntegrity = "sha512-Tc0i+vRogmX4NN7tuLbQfBxa8JkfUSAxSFVzmU31nVdHyiHElPPy2cWfFacmCJKw0VqovrzKhdd2TSTMdAxp2g=="; - public const string BootstrapStylesheetUrl = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css"; - public const string BootstrapStylesheetIntegrity = "sha512-fw7f+TcMjTb7bpbLJZlP8g2Y4XcCyFZW8uy8HsRZsH/SwbMw0plKHFHr99DN3l04VsYNwvzicUX/6qurvIxbxw=="; + public const string BootstrapScriptUrl = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.8/js/bootstrap.bundle.min.js"; + public const string BootstrapScriptIntegrity = "sha512-HvOjJrdwNpDbkGJIG2ZNqDlVqMo77qbs4Me4cah0HoDrfhrbA+8SBlZn1KrvAQw7cILLPFJvdwIgphzQmMm+Pw=="; + public const string BootstrapStylesheetUrl = "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.8/css/bootstrap.min.css"; + public const string BootstrapStylesheetIntegrity = "sha512-2bBQCjcnw658Lho4nlXJcc6WkV/UxpE/sAokbXPxQNGqmNdQrWqtw26Ns9kFF/yG792pKR1Sx8/Y1Lf1XN4GKA=="; public const string CookieConsentCookieName = "Oqtane.CookieConsent"; public const string CookieConsentCookieValue = "yes"; From 002cf28e129f4dcae9bd30401a40b08d85c6497a Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 9 Oct 2025 13:16:16 -0400 Subject: [PATCH 02/35] use class on element rather than span wrapper --- .../Themes/Controls/Theme/Login.razor | 38 +++++++++---------- .../Themes/Controls/Theme/UserProfile.razor | 20 +++++----- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/Oqtane.Client/Themes/Controls/Theme/Login.razor b/Oqtane.Client/Themes/Controls/Theme/Login.razor index f1bf1ebc..3d9ee0c1 100644 --- a/Oqtane.Client/Themes/Controls/Theme/Login.razor +++ b/Oqtane.Client/Themes/Controls/Theme/Login.razor @@ -3,31 +3,29 @@ @inject IStringLocalizer Localizer @inject IStringLocalizer SharedLocalizer - +} +else +{ + @if (ShowLogin) + { + + } +} @code { diff --git a/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor b/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor index e99eada5..43c2677d 100644 --- a/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor +++ b/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor @@ -5,19 +5,17 @@ @inject IStringLocalizer Localizer @inject NavigationManager NavigationManager - - @if (PageState.User != null) +@if (PageState.User != null) +{ + @PageState.User.Username +} +else +{ + @if (ShowRegister && PageState.Site.AllowRegistration) { - @PageState.User.Username + @Localizer["Register"] } - else - { - @if (ShowRegister && PageState.Site.AllowRegistration) - { - @Localizer["Register"] - } - } - +} @code { From 95ec163f2c691243853c5b25ca4ba5997dbda3a7 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Fri, 10 Oct 2025 15:23:04 -0400 Subject: [PATCH 03/35] upgrade to .NET 10 RC1 --- Directory.Build.props | 6 +- .../.template.config/template.json | 8 +-- .../Client/Oqtane.Application.Client.csproj | 16 ++--- .../Oqtane.Application.Template.nuspec | 2 +- .../Server/Oqtane.Application.Server.csproj | 12 ++-- Oqtane.Application/Server/Program.cs | 53 ++++++++------ Oqtane.Application/Server/Startup.cs | 45 ------------ .../Shared/Oqtane.Application.Shared.csproj | 4 +- Oqtane.Client/Oqtane.Client.csproj | 10 +-- Oqtane.Maui/Oqtane.Maui.csproj | 72 +++++++++---------- Oqtane.Package/Oqtane.Client.nuspec | 19 +++-- Oqtane.Package/Oqtane.Framework.nuspec | 6 +- Oqtane.Package/Oqtane.Server.nuspec | 44 ++++++------ Oqtane.Package/Oqtane.Shared.nuspec | 17 +++-- Oqtane.Package/Oqtane.Updater.nuspec | 6 +- Oqtane.Package/install.ps1 | 2 +- Oqtane.Package/release.cmd | 34 ++++----- Oqtane.Package/upgrade.ps1 | 2 +- .../Controllers/ModuleDefinitionController.cs | 6 +- Oqtane.Server/Controllers/ThemeController.cs | 4 +- Oqtane.Server/Oqtane.Server.csproj | 20 +++--- Oqtane.Server/Program.cs | 51 +++++++------ Oqtane.Server/Startup.cs | 43 ----------- Oqtane.Server/appsettings.json | 11 +-- Oqtane.Shared/Oqtane.Shared.csproj | 7 +- Oqtane.Shared/Shared/Constants.cs | 4 +- 26 files changed, 219 insertions(+), 285 deletions(-) delete mode 100644 Oqtane.Application/Server/Startup.cs delete mode 100644 Oqtane.Server/Startup.cs diff --git a/Directory.Build.props b/Directory.Build.props index 223c5f9b..aff5bd3e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,8 +1,8 @@ - net9.0 + net10.0 Debug;Release - 6.2.1 + 10.0.0 Oqtane Shaun Walker .NET Foundation @@ -10,7 +10,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.0 https://github.com/oqtane/oqtane.framework Git diff --git a/Oqtane.Application/.template.config/template.json b/Oqtane.Application/.template.config/template.json index ebcd1b03..c0f9459d 100644 --- a/Oqtane.Application/.template.config/template.json +++ b/Oqtane.Application/.template.config/template.json @@ -30,12 +30,12 @@ "datatype": "choice", "choices": [ { - "choice": "net9.0", - "description": "Target net9.0" + "choice": "net10.0", + "description": "Target net10.0" } ], - "replaces": "net9.0", - "defaultValue": "net9.0" + "replaces": "net10.0", + "defaultValue": "net10.0" }, "HttpPort": { "type": "parameter", diff --git a/Oqtane.Application/Client/Oqtane.Application.Client.csproj b/Oqtane.Application/Client/Oqtane.Application.Client.csproj index c7bd2e5c..ff108bec 100644 --- a/Oqtane.Application/Client/Oqtane.Application.Client.csproj +++ b/Oqtane.Application/Client/Oqtane.Application.Client.csproj @@ -1,22 +1,22 @@ - net9.0 - Exe + net10.0 1.0.0 Oqtane.Application.Client.Oqtane Default true false false + true - - - - - + + + + + @@ -24,7 +24,7 @@ - + diff --git a/Oqtane.Application/Oqtane.Application.Template.nuspec b/Oqtane.Application/Oqtane.Application.Template.nuspec index 47d1af9d..e7097801 100644 --- a/Oqtane.Application/Oqtane.Application.Template.nuspec +++ b/Oqtane.Application/Oqtane.Application.Template.nuspec @@ -2,7 +2,7 @@ Oqtane.Application.Template - 6.2.1 + 10.0.0 Oqtane Application Template For Blazor Shaun Walker false diff --git a/Oqtane.Application/Server/Oqtane.Application.Server.csproj b/Oqtane.Application/Server/Oqtane.Application.Server.csproj index aaf443fa..5e4ee71c 100644 --- a/Oqtane.Application/Server/Oqtane.Application.Server.csproj +++ b/Oqtane.Application/Server/Oqtane.Application.Server.csproj @@ -1,20 +1,20 @@  - net9.0 + net10.0 1.0.0 Oqtane.Application.Server.Oqtane true none false false + true - - - - + + + @@ -23,7 +23,7 @@ - + diff --git a/Oqtane.Application/Server/Program.cs b/Oqtane.Application/Server/Program.cs index 55a18e50..a4eaab1b 100644 --- a/Oqtane.Application/Server/Program.cs +++ b/Oqtane.Application/Server/Program.cs @@ -1,9 +1,13 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore; +using System; +using System.IO; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Oqtane.Infrastructure; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Oqtane.Extensions; +using Oqtane.Infrastructure; +using Oqtane.Shared; namespace Oqtane.Application.Server { @@ -11,32 +15,41 @@ namespace Oqtane.Application.Server { public static void Main(string[] args) { - // defer server startup to Oqtane - do not modify - var host = BuildWebHost(args); - var databaseManager = host.Services.GetService(); + var builder = WebApplication.CreateBuilder(args); + + AppDomain.CurrentDomain.SetData(Constants.DataDirectory, Path.Combine(builder.Environment.ContentRootPath, "Data")); + + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("appsettings.json", false, true) + .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", true, true) + .AddEnvironmentVariables(); + var configuration = configurationBuilder.Build(); + + builder.Services.AddOqtane(configuration, builder.Environment); + + var app = builder.Build(); + + var corsService = app.Services.GetRequiredService(); + var corsPolicyProvider = app.Services.GetRequiredService(); + var syncManager = app.Services.GetRequiredService(); + + app.UseOqtane(configuration, builder.Environment, corsService, corsPolicyProvider, syncManager); + + var databaseManager = app.Services.GetService(); var install = databaseManager.Install(); if (!string.IsNullOrEmpty(install.Message)) { - var filelogger = host.Services.GetRequiredService>(); + var filelogger = app.Services.GetRequiredService>(); if (filelogger != null) { - filelogger.LogError($"[Oqtane.Application.Server.Program.Main] {install.Message}"); + filelogger.LogError($"[Oqtane.Server.Program.Main] {install.Message}"); } } else { - host.Run(); + app.Run(); } } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseConfiguration(new ConfigurationBuilder() - .AddCommandLine(args) - .AddEnvironmentVariables() - .Build()) - .UseStartup() - .ConfigureLocalizationSettings() - .Build(); } } diff --git a/Oqtane.Application/Server/Startup.cs b/Oqtane.Application/Server/Startup.cs deleted file mode 100644 index 71f5bd19..00000000 --- a/Oqtane.Application/Server/Startup.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.IO; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Oqtane.Extensions; -using Oqtane.Infrastructure; -using Oqtane.Shared; -using Microsoft.AspNetCore.Cors.Infrastructure; - -namespace Oqtane.Application.Server -{ - public class Startup - { - private readonly IConfigurationRoot _configuration; - private readonly IWebHostEnvironment _environment; - - public Startup(IWebHostEnvironment environment) - { - AppDomain.CurrentDomain.SetData(Constants.DataDirectory, Path.Combine(environment.ContentRootPath, "Data")); - - var builder = new ConfigurationBuilder() - .SetBasePath(environment.ContentRootPath) - .AddJsonFile("appsettings.json", false, true) - .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", true, true) - .AddEnvironmentVariables(); - - _configuration = builder.Build(); - _environment = environment; - } - - public void ConfigureServices(IServiceCollection services) - { - // defer server startup to Oqtane - do not modify - services.AddOqtane(_configuration, _environment); - } - - public void Configure(IApplicationBuilder app, IConfigurationRoot configuration, IWebHostEnvironment environment, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider, ISyncManager sync) - { - // defer server startup to Oqtane - do not modify - app.UseOqtane(configuration, environment, corsService, corsPolicyProvider, sync); - } - } -} diff --git a/Oqtane.Application/Shared/Oqtane.Application.Shared.csproj b/Oqtane.Application/Shared/Oqtane.Application.Shared.csproj index 1125b6c0..bc957313 100644 --- a/Oqtane.Application/Shared/Oqtane.Application.Shared.csproj +++ b/Oqtane.Application/Shared/Oqtane.Application.Shared.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 1.0.0 Oqtane.Application.Shared.Oqtane @@ -11,7 +11,7 @@ - + diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 366741b0..9aea4292 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -1,17 +1,17 @@ - Exe Oqtane true Default + true - - - - + + + + diff --git a/Oqtane.Maui/Oqtane.Maui.csproj b/Oqtane.Maui/Oqtane.Maui.csproj index 9154ba05..84c86bf6 100644 --- a/Oqtane.Maui/Oqtane.Maui.csproj +++ b/Oqtane.Maui/Oqtane.Maui.csproj @@ -1,12 +1,11 @@ - $(TargetFrameworks);net9.0-windows10.0.19041.0 - - - + $(TargetFrameworks);net10.0-windows10.0.19041.0 + + Exe - Oqtane.Maui + Oqtane.Maui true true enable @@ -19,32 +18,31 @@ com.oqtane.maui - 6.2.1 + 10.0.0 1 - - None + + None - 15.0 - 15.0 - 24.0 - 10.0.17763.0 - 10.0.17763.0 - 6.5 - + 15.0 + 15.0 + 24.0 + 10.0.17763.0 + 10.0.17763.0 + - + - + - + - + @@ -55,24 +53,24 @@ - - - - - - - - - - + + + + + + + + + + - - - ..\Oqtane.Server\bin\Debug\net9.0\Oqtane.Client.dll - - - ..\Oqtane.Server\bin\Debug\net9.0\Oqtane.Shared.dll - - + + + ..\Oqtane.Server\bin\Debug\net10.0\Oqtane.Client.dll + + + ..\Oqtane.Server\bin\Debug\net10.0\Oqtane.Shared.dll + + diff --git a/Oqtane.Package/Oqtane.Client.nuspec b/Oqtane.Package/Oqtane.Client.nuspec index e719802b..a94c1510 100644 --- a/Oqtane.Package/Oqtane.Client.nuspec +++ b/Oqtane.Package/Oqtane.Client.nuspec @@ -2,7 +2,7 @@ Oqtane.Client - 6.2.1 + 10.0.0 Shaun Walker .NET Foundation Oqtane Framework @@ -12,24 +12,23 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.0 readme.md icon.png oqtane - - - - - - + + + + + - - + + diff --git a/Oqtane.Package/Oqtane.Framework.nuspec b/Oqtane.Package/Oqtane.Framework.nuspec index c4d8b054..2a1dabff 100644 --- a/Oqtane.Package/Oqtane.Framework.nuspec +++ b/Oqtane.Package/Oqtane.Framework.nuspec @@ -2,7 +2,7 @@ Oqtane.Framework - 6.2.1 + 10.0.0 Shaun Walker .NET Foundation Oqtane Framework @@ -11,8 +11,8 @@ .NET Foundation false MIT - https://github.com/oqtane/oqtane.framework/releases/download/v6.2.1/Oqtane.Framework.6.2.1.Upgrade.zip - https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1 + https://github.com/oqtane/oqtane.framework/releases/download/v10.0.0/Oqtane.Framework.10.0.0.Upgrade.zip + https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.0 readme.md icon.png oqtane framework diff --git a/Oqtane.Package/Oqtane.Server.nuspec b/Oqtane.Package/Oqtane.Server.nuspec index 7a436eae..46680dad 100644 --- a/Oqtane.Package/Oqtane.Server.nuspec +++ b/Oqtane.Package/Oqtane.Server.nuspec @@ -2,7 +2,7 @@ Oqtane.Server - 6.2.1 + 10.0.0 Shaun Walker .NET Foundation Oqtane Framework @@ -12,20 +12,20 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.0 readme.md icon.png oqtane - - - - - + + + + + - - - + + + @@ -33,28 +33,28 @@ - + - - + + - + - + - - - - - - - + + + + + + + diff --git a/Oqtane.Package/Oqtane.Shared.nuspec b/Oqtane.Package/Oqtane.Shared.nuspec index cb148f19..ecdde09c 100644 --- a/Oqtane.Package/Oqtane.Shared.nuspec +++ b/Oqtane.Package/Oqtane.Shared.nuspec @@ -2,7 +2,7 @@ Oqtane.Shared - 6.2.1 + 10.0.0 Shaun Walker .NET Foundation Oqtane Framework @@ -12,24 +12,23 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.0 readme.md icon.png oqtane - - - - + + + + - - - + + diff --git a/Oqtane.Package/Oqtane.Updater.nuspec b/Oqtane.Package/Oqtane.Updater.nuspec index 0acd762e..597f5617 100644 --- a/Oqtane.Package/Oqtane.Updater.nuspec +++ b/Oqtane.Package/Oqtane.Updater.nuspec @@ -2,7 +2,7 @@ Oqtane.Updater - 6.2.1 + 10.0.0 Shaun Walker .NET Foundation Oqtane Framework @@ -12,13 +12,13 @@ false MIT https://github.com/oqtane/oqtane.framework - https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1 + https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.0 readme.md icon.png oqtane - + diff --git a/Oqtane.Package/install.ps1 b/Oqtane.Package/install.ps1 index 70f1001b..a59e4412 100644 --- a/Oqtane.Package/install.ps1 +++ b/Oqtane.Package/install.ps1 @@ -1 +1 @@ -Compress-Archive -Path "..\Oqtane.Server\bin\Release\net9.0\publish\*" -DestinationPath "Oqtane.Framework.6.2.1.Install.zip" -Force +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.0.0.Install.zip" -Force diff --git a/Oqtane.Package/release.cmd b/Oqtane.Package/release.cmd index f32f8178..99a1d8db 100644 --- a/Oqtane.Package/release.cmd +++ b/Oqtane.Package/release.cmd @@ -4,24 +4,24 @@ nuget.exe pack Oqtane.Server.nuspec nuget.exe pack Oqtane.Shared.nuspec nuget.exe pack Oqtane.Framework.nuspec dotnet publish ..\Oqtane.Server\Oqtane.Server.csproj /p:Configuration=Release -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\Content" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\wwwroot\Content" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\android-arm" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\android-arm64" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\android-x64" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\android-x86" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\ios-arm" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\ios-arm64" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\iossimulator-arm64" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\iossimulator-x64" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\runtimes\iossimulator-x86" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\wwwroot\Modules\Templates" -rmdir /Q /S "..\Oqtane.Server\bin\Release\net9.0\publish\wwwroot\Themes\Templates" -del "..\Oqtane.Server\bin\Release\net9.0\publish\appsettings.json" -ren "..\Oqtane.Server\bin\Release\net9.0\publish\appsettings.release.json" "appsettings.json" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\Content" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\wwwroot\Content" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\android-arm" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\android-arm64" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\android-x64" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\android-x86" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\ios-arm" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\ios-arm64" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\iossimulator-arm64" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\iossimulator-x64" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\runtimes\iossimulator-x86" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\wwwroot\Modules\Templates" +rmdir /Q /S "..\Oqtane.Server\bin\Release\net10.0\publish\wwwroot\Themes\Templates" +del "..\Oqtane.Server\bin\Release\net10.0\publish\appsettings.json" +ren "..\Oqtane.Server\bin\Release\net10.0\publish\appsettings.release.json" "appsettings.json" C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\install.ps1" -del "..\Oqtane.Server\bin\Release\net9.0\publish\appsettings.json" -del "..\Oqtane.Server\bin\Release\net9.0\publish\web.config" +del "..\Oqtane.Server\bin\Release\net10.0\publish\appsettings.json" +del "..\Oqtane.Server\bin\Release\net10.0\publish\web.config" C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\upgrade.ps1" dotnet build -c Release ..\Oqtane.Updater.sln dotnet publish ..\Oqtane.Updater\Oqtane.Updater.csproj /p:Configuration=Release diff --git a/Oqtane.Package/upgrade.ps1 b/Oqtane.Package/upgrade.ps1 index cc87a261..5979f4d7 100644 --- a/Oqtane.Package/upgrade.ps1 +++ b/Oqtane.Package/upgrade.ps1 @@ -1 +1 @@ -Compress-Archive -Path "..\Oqtane.Server\bin\Release\net9.0\publish\*" -DestinationPath "Oqtane.Framework.6.2.1.Upgrade.zip" -Force +Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.0.0.Upgrade.zip" -Force diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index 486af9fc..8b04ad20 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -350,9 +350,9 @@ namespace Oqtane.Controllers return new Dictionary() { { "FrameworkVersion", Constants.Version }, - { "ClientReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Client.dll" }, - { "ServerReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Server.dll" }, - { "SharedReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Shared.dll" }, + { "ClientReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net10.0\\Oqtane.Client.dll" }, + { "ServerReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net10.0\\Oqtane.Server.dll" }, + { "SharedReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net10.0\\Oqtane.Shared.dll" }, }; }); } diff --git a/Oqtane.Server/Controllers/ThemeController.cs b/Oqtane.Server/Controllers/ThemeController.cs index c103d501..b2cc657f 100644 --- a/Oqtane.Server/Controllers/ThemeController.cs +++ b/Oqtane.Server/Controllers/ThemeController.cs @@ -304,8 +304,8 @@ namespace Oqtane.Controllers return new Dictionary() { { "FrameworkVersion", Constants.Version }, - { "ClientReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Client.dll" }, - { "SharedReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Shared.dll" }, + { "ClientReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net10.0\\Oqtane.Client.dll" }, + { "SharedReference", $"..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net10.0\\Oqtane.Shared.dll" }, }; }); } diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj index 76dd1fb6..afbcfba2 100644 --- a/Oqtane.Server/Oqtane.Server.csproj +++ b/Oqtane.Server/Oqtane.Server.csproj @@ -9,6 +9,7 @@ false false / + true @@ -26,16 +27,15 @@ - - + + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + @@ -48,14 +48,14 @@ - + - - + + - + diff --git a/Oqtane.Server/Program.cs b/Oqtane.Server/Program.cs index 24eeee11..5fb2fad2 100644 --- a/Oqtane.Server/Program.cs +++ b/Oqtane.Server/Program.cs @@ -1,25 +1,46 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; +using System; +using System.IO; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.Extensions.Configuration; -using Microsoft.AspNetCore; using Microsoft.Extensions.DependencyInjection; -using Oqtane.Infrastructure; using Microsoft.Extensions.Logging; -using Oqtane.Documentation; +using Oqtane.Extensions; +using Oqtane.Infrastructure; +using Oqtane.Shared; namespace Oqtane.Server { - [PrivateApi("Mark Entry-Program as private, since it's not very useful in the public docs")] public class Program { public static void Main(string[] args) { - var host = BuildWebHost(args); - var databaseManager = host.Services.GetService(); + var builder = WebApplication.CreateBuilder(args); + + AppDomain.CurrentDomain.SetData(Constants.DataDirectory, Path.Combine(builder.Environment.ContentRootPath, "Data")); + + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(builder.Environment.ContentRootPath) + .AddJsonFile("appsettings.json", false, true) + .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", true, true) + .AddEnvironmentVariables(); + var configuration = configurationBuilder.Build(); + + builder.Services.AddOqtane(configuration, builder.Environment); + + var app = builder.Build(); + + var corsService = app.Services.GetRequiredService(); + var corsPolicyProvider = app.Services.GetRequiredService(); + var syncManager = app.Services.GetRequiredService(); + + app.UseOqtane(configuration, builder.Environment, corsService, corsPolicyProvider, syncManager); + + var databaseManager = app.Services.GetService(); var install = databaseManager.Install(); if (!string.IsNullOrEmpty(install.Message)) { - var filelogger = host.Services.GetRequiredService>(); + var filelogger = app.Services.GetRequiredService>(); if (filelogger != null) { filelogger.LogError($"[Oqtane.Server.Program.Main] {install.Message}"); @@ -27,18 +48,8 @@ namespace Oqtane.Server } else { - host.Run(); + app.Run(); } } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseConfiguration(new ConfigurationBuilder() - .AddCommandLine(args) - .AddEnvironmentVariables() - .Build()) - .UseStartup() - .ConfigureLocalizationSettings() - .Build(); } } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs deleted file mode 100644 index 979c57e4..00000000 --- a/Oqtane.Server/Startup.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.IO; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Oqtane.Extensions; -using Oqtane.Infrastructure; -using Oqtane.Shared; -using Microsoft.AspNetCore.Cors.Infrastructure; - -namespace Oqtane -{ - public class Startup - { - private readonly IConfigurationRoot _configuration; - private readonly IWebHostEnvironment _environment; - - public Startup(IWebHostEnvironment environment) - { - AppDomain.CurrentDomain.SetData(Constants.DataDirectory, Path.Combine(environment.ContentRootPath, "Data")); - - var builder = new ConfigurationBuilder() - .SetBasePath(environment.ContentRootPath) - .AddJsonFile("appsettings.json", false, true) - .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", true, true) - .AddEnvironmentVariables(); - - _configuration = builder.Build(); - _environment = environment; - } - - public void ConfigureServices(IServiceCollection services) - { - services.AddOqtane(_configuration, _environment); - } - - public void Configure(IApplicationBuilder app, IConfigurationRoot configuration, IWebHostEnvironment environment, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider, ISyncManager sync) - { - app.UseOqtane(configuration, environment, corsService, corsPolicyProvider, sync); - } - } -} diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index 9f96daeb..5e29e649 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -2,10 +2,10 @@ "RenderMode": "Static", "Runtime": "Server", "Database": { - "DefaultDBType": "" + "DefaultDBType": "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server" }, "ConnectionStrings": { - "DefaultConnection": "" + "DefaultConnection": "Data Source=(LocalDb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\Oqtane-202510101823.mdf;Initial Catalog=Oqtane-202510101823;Integrated Security=SSPI;Encrypt=false;" }, "Installation": { "DefaultAlias": "", @@ -59,5 +59,8 @@ "LogLevel": { "Default": "Information" } - } -} + }, + "InstallationId": "27da509b-b133-43a4-999d-d47e3baa0993", + "InstallationVersion": "10.0.0", + "InstallationDate": "202510101749" +} \ No newline at end of file diff --git a/Oqtane.Shared/Oqtane.Shared.csproj b/Oqtane.Shared/Oqtane.Shared.csproj index 78b6ba46..744b0513 100644 --- a/Oqtane.Shared/Oqtane.Shared.csproj +++ b/Oqtane.Shared/Oqtane.Shared.csproj @@ -5,12 +5,11 @@ - - - + + + - diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 749249e8..d6740658 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -4,8 +4,8 @@ namespace Oqtane.Shared { public class Constants { - public static readonly string Version = "6.2.1"; - public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1,5.1.2,5.2.0,5.2.1,5.2.2,5.2.3,5.2.4,6.0.0,6.0.1,6.1.0,6.1.1,6.1.2,6.1.3,6.1.4,6.1.5,6.2.0,6.2.1"; + public static readonly string Version = "10.0.0"; + public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1,5.1.2,5.2.0,5.2.1,5.2.2,5.2.3,5.2.4,6.0.0,6.0.1,6.1.0,6.1.1,6.1.2,6.1.3,6.1.4,6.1.5,6.2.0,6.2.1,10.0.0"; public const string PackageId = "Oqtane.Framework"; public const string ClientId = "Oqtane.Client"; public const string UpdaterPackageId = "Oqtane.Updater"; From 0c3aed5fa9699752193256f7a7ad05f871c48ae5 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Fri, 10 Oct 2025 15:29:38 -0400 Subject: [PATCH 04/35] Update appsettings.json --- Oqtane.Server/appsettings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index 5e29e649..6dde319e 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -2,10 +2,10 @@ "RenderMode": "Static", "Runtime": "Server", "Database": { - "DefaultDBType": "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Server" + "DefaultDBType": "" }, "ConnectionStrings": { - "DefaultConnection": "Data Source=(LocalDb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\Oqtane-202510101823.mdf;Initial Catalog=Oqtane-202510101823;Integrated Security=SSPI;Encrypt=false;" + "DefaultConnection": "" }, "Installation": { "DefaultAlias": "", @@ -63,4 +63,4 @@ "InstallationId": "27da509b-b133-43a4-999d-d47e3baa0993", "InstallationVersion": "10.0.0", "InstallationDate": "202510101749" -} \ No newline at end of file +} From 8e10a8e042dcf9487dc9106b19e3d1454206e975 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Fri, 10 Oct 2025 15:31:13 -0400 Subject: [PATCH 05/35] Remove installation ID, version, and date Removed installation-related settings from appsettings.json. --- Oqtane.Server/appsettings.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index 6dde319e..9f96daeb 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -59,8 +59,5 @@ "LogLevel": { "Default": "Information" } - }, - "InstallationId": "27da509b-b133-43a4-999d-d47e3baa0993", - "InstallationVersion": "10.0.0", - "InstallationDate": "202510101749" + } } From 02c4da553901fe0e4f6e4aaea710071fa11e9dcf Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 13 Oct 2025 11:50:46 -0400 Subject: [PATCH 06/35] use ModelBase in module template --- .../Modules/Templates/External/Shared/Models/[Module].cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Shared/Models/[Module].cs b/Oqtane.Server/wwwroot/Modules/Templates/External/Shared/Models/[Module].cs index ddba10ad..7236fb25 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Shared/Models/[Module].cs +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Shared/Models/[Module].cs @@ -1,4 +1,3 @@ -using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using Oqtane.Models; @@ -6,16 +5,11 @@ using Oqtane.Models; namespace [Owner].Module.[Module].Models { [Table("[Owner][Module]")] - public class [Module] : IAuditable + public class [Module] : ModelBase { [Key] public int [Module]Id { get; set; } public int ModuleId { get; set; } public string Name { get; set; } - - public string CreatedBy { get; set; } - public DateTime CreatedOn { get; set; } - public string ModifiedBy { get; set; } - public DateTime ModifiedOn { get; set; } } } From db85d1fbc3a301d03ac8cdf083f405b6d1b3d2b8 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 13 Oct 2025 14:19:49 -0400 Subject: [PATCH 07/35] improve error handling when handling module migrations --- Oqtane.Server/Infrastructure/DatabaseManager.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index 4dd4ea52..1cc78a5a 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -507,6 +507,10 @@ namespace Oqtane.Infrastructure } } } + else + { + result.Message = "An Error Occurred Installing " + moduleDefinition.Name + " - ServerManagerType " + moduleDefinition.ServerManagerType + " Does Not Exist"; + } } if (string.IsNullOrEmpty(result.Message) && moduleDefinition.Version != versions[versions.Length - 1]) From bc617db649e80a4420fe2a42af38122ded9bca90 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Mon, 13 Oct 2025 14:42:53 -0400 Subject: [PATCH 08/35] fix internal template logic so that assembly name is determined dynamically --- Oqtane.Server/Controllers/ModuleDefinitionController.cs | 5 +++-- Oqtane.Server/Controllers/ThemeController.cs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index 8b04ad20..df876829 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -132,8 +132,9 @@ namespace Oqtane.Controllers if (moduleDefinition.Template.ToLower().Contains("internal")) { rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString()); - moduleDefinition.ServerManagerType = moduleDefinition.ModuleDefinitionName + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server"; - moduleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName + ", Oqtane.Client"; + var assemblyName = Assembly.GetExecutingAssembly().GetName().Name; + moduleDefinition.ServerManagerType = moduleDefinition.ModuleDefinitionName + ".Manager." + moduleDefinition.Name + "Manager, " + assemblyName; + moduleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName + ", " + assemblyName.Replace(".Server", ".Client"); } else { diff --git a/Oqtane.Server/Controllers/ThemeController.cs b/Oqtane.Server/Controllers/ThemeController.cs index b2cc657f..0463ae34 100644 --- a/Oqtane.Server/Controllers/ThemeController.cs +++ b/Oqtane.Server/Controllers/ThemeController.cs @@ -226,7 +226,8 @@ namespace Oqtane.Controllers if (theme.Template.ToLower().Contains("internal")) { rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString()); - theme.ThemeName = theme.ThemeName + ", Oqtane.Client"; + var assemblyName = Assembly.GetExecutingAssembly().GetName().Name; + theme.ThemeName = theme.ThemeName + ", " + assemblyName.Replace(".Server", ".Client"); } else { From 83b56966f41ef00590df698d31405ef68b187543 Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 14 Oct 2025 13:01:34 -0400 Subject: [PATCH 09/35] use consistent pattern for settings --- .../Client/Modules/[Owner].Module.[Module]/Settings.razor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].Module.[Module]/Settings.razor b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].Module.[Module]/Settings.razor index 3c4cae69..624dee2a 100644 --- a/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].Module.[Module]/Settings.razor +++ b/Oqtane.Server/wwwroot/Modules/Templates/External/Client/Modules/[Owner].Module.[Module]/Settings.razor @@ -35,8 +35,8 @@ { try { - Dictionary settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId); - SettingService.SetSetting(settings, "SettingName", _value); + var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId); + settings = SettingService.SetSetting(settings, "SettingName", _value); await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId); } catch (Exception ex) From 7cf325f4f66fcda7706d0511722c4465fddb446a Mon Sep 17 00:00:00 2001 From: sbwalker Date: Tue, 14 Oct 2025 13:37:39 -0400 Subject: [PATCH 10/35] improve support for internal module/theme templates --- .../Admin/ModuleDefinitions/Create.razor | 51 ++++++++------- .../Modules/Admin/Themes/Create.razor | 63 +++++++++++-------- 2 files changed, 66 insertions(+), 48 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor index bcb78bc5..13e89847 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor @@ -42,29 +42,32 @@ -
- -
- -
-
- @if (!string.IsNullOrEmpty(_location)) + @if (_type == "External") {
- +
- +
+ @if (!string.IsNullOrEmpty(_location)) + { +
+ +
+ +
+
+ } } @@ -80,9 +83,10 @@ private string _description = string.Empty; private List