From bcb6c81e439900a9ffa68539af8141d4ff5afda8 Mon Sep 17 00:00:00 2001 From: hishamco Date: Sat, 3 Oct 2020 22:41:48 +0300 Subject: [PATCH 1/3] Avoid Building ServiceProvider in ConfigureServices --- .../OqtaneServiceCollectionExtensions.cs | 54 +++++++++---------- Oqtane.Server/Startup.cs | 19 ++++--- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 4090be8d..0b94b088 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -15,10 +15,10 @@ namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions { - public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime) + public static IServiceCollection AddOqtane(this IServiceCollection services, Runtime runtime, string[] supportedCultures) { LoadAssemblies(); - LoadSatelliteAssemblies(); + LoadSatelliteAssemblies(supportedCultures); services.AddOqtaneServices(runtime); return services; @@ -122,7 +122,7 @@ namespace Microsoft.Extensions.DependencyInjection } } - private static void LoadSatelliteAssemblies() + private static void LoadSatelliteAssemblies(string[] supportedCultures) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); @@ -133,39 +133,35 @@ namespace Microsoft.Extensions.DependencyInjection AssemblyLoadContext.Default.Resolving += ResolveDependencies; - using (var serviceScope = ServiceActivator.GetScope()) + foreach (var culture in supportedCultures) { - var localizationManager = serviceScope.ServiceProvider.GetService(); - foreach (var culture in localizationManager.GetSupportedCultures()) + if (culture == Constants.DefaultCulture) { - if (culture == Constants.DefaultCulture) + continue; + } + + var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); + foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) + { + AssemblyName assemblyName; + try { + assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); + } + catch + { + Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); continue; } - var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); - foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) + try { - AssemblyName assemblyName; - try - { - assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); - } - catch - { - Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); - continue; - } - - try - { - Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); - Console.WriteLine($"Loaded : {assemblyName}"); - } - catch (Exception e) - { - Console.WriteLine($"Failed : {assemblyName}\n{e}"); - } + Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); + Console.WriteLine($"Loaded : {assemblyName}"); + } + catch (Exception e) + { + Console.WriteLine($"Failed : {assemblyName}\n{e}"); } } } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 98d43bcd..396e6602 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.IO; using System.Linq; using System.Net.Http; @@ -26,11 +27,14 @@ namespace Oqtane { public class Startup { - public IConfigurationRoot Configuration { get; } + private static readonly string[] DefaultSupportedCultures = new[] { Constants.DefaultCulture }; + private string _webRoot; private Runtime _runtime; private bool _useSwagger; + public IConfigurationRoot Configuration { get; } + public Startup(IWebHostEnvironment env) { var builder = new ConfigurationBuilder() @@ -128,7 +132,10 @@ namespace Oqtane .AddSignInManager() .AddDefaultTokenProviders(); - services.Configure(Configuration.GetSection("Localization")); + var localizationSection = Configuration.GetSection("Localization"); + var localizationOptions = localizationSection.Get(); + + services.Configure(localizationSection); services.Configure(options => { @@ -202,11 +209,11 @@ namespace Oqtane services.AddTransient(); services.AddTransient(); - // TODO: Check if there's a better way instead of building service provider - ServiceActivator.Configure(services.BuildServiceProvider()); - // load the external assemblies into the app domain, install services - services.AddOqtane(_runtime); + services.AddOqtane(_runtime, + localizationOptions.SupportedCultures.IsNullOrEmpty() + ? DefaultSupportedCultures + : localizationOptions.SupportedCultures); services.AddMvc() .AddNewtonsoftJson() From ce37d2f2d294c25c5e5bca927d3d1f9a4a70cbe8 Mon Sep 17 00:00:00 2001 From: hishamco Date: Sat, 3 Oct 2020 23:26:44 +0300 Subject: [PATCH 2/3] Skip missed satellite assemblies forlders --- .../Controllers/InstallationController.cs | 12 +++++- .../OqtaneServiceCollectionExtensions.cs | 43 +++++++++++-------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index d3529a98..29583e8a 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -79,14 +79,22 @@ namespace Oqtane.Controllers // Get the satellite assemblies foreach (var culture in _localizationManager.GetSupportedCultures()) { + var assembliesFolderPath = Path.Combine(binFolder, culture); if (culture == Constants.DefaultCulture) { continue; } - foreach (var resourceFile in Directory.EnumerateFiles(Path.Combine(binFolder, culture))) + if(Directory.Exists(assembliesFolderPath)) { - list.Add(Path.Combine(culture, Path.GetFileNameWithoutExtension(resourceFile))); + foreach (var resourceFile in Directory.EnumerateFiles(assembliesFolderPath)) + { + list.Add(Path.Combine(culture, Path.GetFileNameWithoutExtension(resourceFile))); + } + } + else + { + Console.WriteLine($"The satellite assemblies folder named '{culture}' is not found."); } } diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 0b94b088..540f399c 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -141,29 +141,36 @@ namespace Microsoft.Extensions.DependencyInjection } var assembliesFolder = new DirectoryInfo(Path.Combine(assemblyPath, culture)); - foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) + if (assembliesFolder.Exists) { - AssemblyName assemblyName; - try + foreach (var assemblyFile in assembliesFolder.EnumerateFiles(Constants.StalliteAssemblyExtension)) { - assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); - } - catch - { - Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); - continue; - } + AssemblyName assemblyName; + try + { + assemblyName = AssemblyName.GetAssemblyName(assemblyFile.FullName); + } + catch + { + Console.WriteLine($"Not Satellite Assembly : {assemblyFile.Name}"); + continue; + } - try - { - Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); - Console.WriteLine($"Loaded : {assemblyName}"); - } - catch (Exception e) - { - Console.WriteLine($"Failed : {assemblyName}\n{e}"); + try + { + Assembly assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(assemblyFile.FullName))); + Console.WriteLine($"Loaded : {assemblyName}"); + } + catch (Exception e) + { + Console.WriteLine($"Failed : {assemblyName}\n{e}"); + } } } + else + { + Console.WriteLine($"The satellite assemblies folder named '{culture}' is not found."); + } } } From 3d7630d3d4521566580009d5632331915651b382 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Sun, 4 Oct 2020 10:43:09 -0400 Subject: [PATCH 3/3] Update README.md --- README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5b3af4e2..24ec4eea 100644 --- a/README.md +++ b/README.md @@ -38,15 +38,10 @@ Please note that this project is owned by the .NET Foundation and is governed by # Roadmap This project is a work in progress and the schedule for implementing enhancements is dependent upon the availability of community members who are willing/able to assist. -V.Next ( still in the process of being prioritized ) -- [ ] Admin UI markup optimization -- [ ] DB Migrations for framework installation/upgrade -- [ ] Support for SQLite +V.2.0.0 ( estimated release date Nov 10, 2020 ) +- [ ] Migrate to .NET 5 - [ ] Static Localization ( ie. labels, help text, etc.. ) -- [ ] Migrate to Code-Behind Pattern ( *.razor.cs ) -- [ ] Generic Repository Pattern -- [ ] JwT token authentication ( possibly using IdentityServer ) -- [ ] Optional Encryption for Settings Values +- [ ] Admin UI markup optimization V1.0.0 (MVP) - Released in conjunction with .NET Core 3.2 ( May 2020 ) - [x] Multi-Tenant ( Shared Database & Isolated Database ) @@ -66,6 +61,13 @@ V1.0.0 (MVP) - Released in conjunction with .NET Core 3.2 ( May 2020 ) - [x] Auto-Upgrade Framework - [x] Progressive Web Application Support +Future Consideration +- [ ] DB Migrations for framework installation/upgrade +- [ ] Support for SQLite +- [ ] Generic Repository Pattern +- [ ] JwT token authentication ( possibly using IdentityServer ) +- [ ] Optional Encryption for Settings Values + # Background Oqtane was created by [Shaun Walker](https://www.linkedin.com/in/shaunbrucewalker/) and is inspired by the DotNetNuke web application framework. Initially created as a proof of concept, Oqtane is a native Blazor application written from the ground up using modern .NET Core technology. It is a modular application framework offering a fully dynamic page compositing model, multi-site support, designer friendly templates (skins), and extensibility via third party modules.