diff --git a/Oqtane.Client/Modules/Controls/ActionDialog.razor b/Oqtane.Client/Modules/Controls/ActionDialog.razor index 08b2d77d..0ee455d7 100644 --- a/Oqtane.Client/Modules/Controls/ActionDialog.razor +++ b/Oqtane.Client/Modules/Controls/ActionDialog.razor @@ -1,6 +1,6 @@ @namespace Oqtane.Modules.Controls @inherits ModuleBase - +@attribute [OqtaneIgnore] @if (_visible) {
diff --git a/Oqtane.Client/Modules/Controls/ActionLink.razor b/Oqtane.Client/Modules/Controls/ActionLink.razor index cf588579..97fd0a0e 100644 --- a/Oqtane.Client/Modules/Controls/ActionLink.razor +++ b/Oqtane.Client/Modules/Controls/ActionLink.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore] @inject IUserService UserService @if (_authorized) diff --git a/Oqtane.Client/Modules/Controls/AuditInfo.razor b/Oqtane.Client/Modules/Controls/AuditInfo.razor index 75079c6c..7c081d3f 100644 --- a/Oqtane.Client/Modules/Controls/AuditInfo.razor +++ b/Oqtane.Client/Modules/Controls/AuditInfo.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore] @if (_text != string.Empty) { diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index 0519e1b5..8dc70ffb 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore] @inject IFolderService FolderService @inject IFileService FileService @inject IJSRuntime JsRuntime diff --git a/Oqtane.Client/Modules/Controls/Label.razor b/Oqtane.Client/Modules/Controls/Label.razor index 0826e0cb..e57d01ec 100644 --- a/Oqtane.Client/Modules/Controls/Label.razor +++ b/Oqtane.Client/Modules/Controls/Label.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore] @if (!string.IsNullOrEmpty(HelpText)) { @@ -41,4 +42,4 @@ else _openLabel += ">"; } -} \ No newline at end of file +} diff --git a/Oqtane.Client/Modules/Controls/ModuleMessage.razor b/Oqtane.Client/Modules/Controls/ModuleMessage.razor index 67f3f50d..5e00cb76 100644 --- a/Oqtane.Client/Modules/Controls/ModuleMessage.razor +++ b/Oqtane.Client/Modules/Controls/ModuleMessage.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore] @if (!string.IsNullOrEmpty(_message)) { diff --git a/Oqtane.Client/Modules/Controls/Pager.razor b/Oqtane.Client/Modules/Controls/Pager.razor index 184eaa8a..ff7e13ee 100644 --- a/Oqtane.Client/Modules/Controls/Pager.razor +++ b/Oqtane.Client/Modules/Controls/Pager.razor @@ -1,6 +1,8 @@ @namespace Oqtane.Modules.Controls @inherits ModuleBase -@typeparam TableItem +@attribute [OqtaneIgnore] +@typeparam TableItem +

@if(Format == "Table") @@ -209,4 +211,4 @@ UpdateList(_page); } -} \ No newline at end of file +} diff --git a/Oqtane.Client/Modules/Controls/PermissionGrid.razor b/Oqtane.Client/Modules/Controls/PermissionGrid.razor index 543403f2..90954bbe 100644 --- a/Oqtane.Client/Modules/Controls/PermissionGrid.razor +++ b/Oqtane.Client/Modules/Controls/PermissionGrid.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore] @inject IRoleService RoleService @inject IUserService UserService diff --git a/Oqtane.Client/Modules/Controls/RichTextEditor.razor b/Oqtane.Client/Modules/Controls/RichTextEditor.razor index 36368c5a..175717fd 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditor.razor +++ b/Oqtane.Client/Modules/Controls/RichTextEditor.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore] @inject IJSRuntime JsRuntime @if (_filemanagervisible) diff --git a/Oqtane.Client/Modules/Controls/Section.razor b/Oqtane.Client/Modules/Controls/Section.razor index 6921f933..4f33b42f 100644 --- a/Oqtane.Client/Modules/Controls/Section.razor +++ b/Oqtane.Client/Modules/Controls/Section.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore]

diff --git a/Oqtane.Client/Modules/Controls/TabPanel.razor b/Oqtane.Client/Modules/Controls/TabPanel.razor index d09ff53f..bd89ab59 100644 --- a/Oqtane.Client/Modules/Controls/TabPanel.razor +++ b/Oqtane.Client/Modules/Controls/TabPanel.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore] @if (Name == Parent.ActiveTab) { diff --git a/Oqtane.Client/Modules/Controls/TabStrip.razor b/Oqtane.Client/Modules/Controls/TabStrip.razor index 4f0b872f..8d8d3838 100644 --- a/Oqtane.Client/Modules/Controls/TabStrip.razor +++ b/Oqtane.Client/Modules/Controls/TabStrip.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits ModuleBase +@inherits ModuleBase +@attribute [OqtaneIgnore]
diff --git a/Oqtane.Client/Services/ServiceBase.cs b/Oqtane.Client/Services/ServiceBase.cs index 742bd3fa..57bad2b7 100644 --- a/Oqtane.Client/Services/ServiceBase.cs +++ b/Oqtane.Client/Services/ServiceBase.cs @@ -82,7 +82,6 @@ namespace Oqtane.Services var result = await response.Content.ReadFromJsonAsync(); return result; } - return default; } @@ -121,6 +120,8 @@ namespace Oqtane.Services if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.NotFound) { //TODO: Log errors here + + Console.WriteLine($"Request: {response.RequestMessage.RequestUri}"); Console.WriteLine($"Response status: {response.StatusCode} {response.ReasonPhrase}"); } diff --git a/Oqtane.Client/Themes/Controls/Breadcrumbs.razor b/Oqtane.Client/Themes/Controls/Breadcrumbs.razor index 7175f85d..06d9eceb 100644 --- a/Oqtane.Client/Themes/Controls/Breadcrumbs.razor +++ b/Oqtane.Client/Themes/Controls/Breadcrumbs.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls -@inherits ThemeControlBase +@inherits ThemeControlBase +@attribute [OqtaneIgnore] @if (BreadCrumbPages.Any()) { diff --git a/Oqtane.Client/Themes/Controls/ControlPanel.razor b/Oqtane.Client/Themes/Controls/ControlPanel.razor index fe9e5486..042e2ef4 100644 --- a/Oqtane.Client/Themes/Controls/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/ControlPanel.razor @@ -1,6 +1,7 @@ @namespace Oqtane.Themes.Controls @using Oqtane.Enums -@inherits ThemeControlBase +@inherits ThemeControlBase +@attribute [OqtaneIgnore] @inject NavigationManager NavigationManager @inject IUserService UserService @inject IModuleDefinitionService ModuleDefinitionService diff --git a/Oqtane.Client/Themes/Controls/Login.razor b/Oqtane.Client/Themes/Controls/Login.razor index 55d975aa..dbdb9444 100644 --- a/Oqtane.Client/Themes/Controls/Login.razor +++ b/Oqtane.Client/Themes/Controls/Login.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls -@inherits LoginBase +@inherits LoginBase +@attribute [OqtaneIgnore] diff --git a/Oqtane.Client/Themes/Controls/Logo.razor b/Oqtane.Client/Themes/Controls/Logo.razor index fe9929f4..c98d58b7 100644 --- a/Oqtane.Client/Themes/Controls/Logo.razor +++ b/Oqtane.Client/Themes/Controls/Logo.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls -@inherits ThemeControlBase +@inherits ThemeControlBase +@attribute [OqtaneIgnore] @inject NavigationManager NavigationManager @if (PageState.Site.LogoFileId != null) diff --git a/Oqtane.Client/Themes/Controls/MenuHorizontal.Razor b/Oqtane.Client/Themes/Controls/MenuHorizontal.Razor index 708a3059..075a955a 100644 --- a/Oqtane.Client/Themes/Controls/MenuHorizontal.Razor +++ b/Oqtane.Client/Themes/Controls/MenuHorizontal.Razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls @inherits MenuBase +@attribute [OqtaneIgnore] @if (MenuPages.Any()) {
diff --git a/Oqtane.Client/Themes/Controls/MenuVertical.razor b/Oqtane.Client/Themes/Controls/MenuVertical.razor index 8991b277..3d6500bf 100644 --- a/Oqtane.Client/Themes/Controls/MenuVertical.razor +++ b/Oqtane.Client/Themes/Controls/MenuVertical.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls -@inherits MenuBase +@inherits MenuBase +@attribute [OqtaneIgnore] @if (MenuPages.Any()) {
diff --git a/Oqtane.Client/Themes/Controls/ModuleActions.razor b/Oqtane.Client/Themes/Controls/ModuleActions.razor index 6ca55f1a..0a9cc6ea 100644 --- a/Oqtane.Client/Themes/Controls/ModuleActions.razor +++ b/Oqtane.Client/Themes/Controls/ModuleActions.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls -@inherits ModuleActionsBase +@inherits ModuleActionsBase +@attribute [OqtaneIgnore] @if (PageState.EditMode && !PageState.Page.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions)) { diff --git a/Oqtane.Client/Themes/Controls/ModuleTitle.razor b/Oqtane.Client/Themes/Controls/ModuleTitle.razor index bb8d6f62..b8da32bf 100644 --- a/Oqtane.Client/Themes/Controls/ModuleTitle.razor +++ b/Oqtane.Client/Themes/Controls/ModuleTitle.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls -@inherits ContainerBase +@inherits ContainerBase +@attribute [OqtaneIgnore] @((MarkupString)title) diff --git a/Oqtane.Client/Themes/Controls/UserProfile.razor b/Oqtane.Client/Themes/Controls/UserProfile.razor index 1f101caf..4f78741b 100644 --- a/Oqtane.Client/Themes/Controls/UserProfile.razor +++ b/Oqtane.Client/Themes/Controls/UserProfile.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls -@inherits ThemeControlBase +@inherits ThemeControlBase +@attribute [OqtaneIgnore] @inject NavigationManager NavigationManager diff --git a/Oqtane.Server/Extensions/AssemblyExtensions.cs b/Oqtane.Server/Extensions/AssemblyExtensions.cs index 8cb7c39d..9785d229 100644 --- a/Oqtane.Server/Extensions/AssemblyExtensions.cs +++ b/Oqtane.Server/Extensions/AssemblyExtensions.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; +using System.IO; using System.Linq; +using Oqtane.Shared; // ReSharper disable once CheckNamespace namespace System.Reflection @@ -31,5 +33,20 @@ namespace System.Reflection return assembly.GetTypes() .Where(t => t.GetInterfaces().Contains(interfaceType)); } + + public static bool IsOqtaneAssembly(this Assembly assembly) + { + return assembly.FullName != null && (assembly.FullName.Contains("oqtane.", StringComparison.OrdinalIgnoreCase)); + } + + public static bool IsOqtaneAssembly(this FileInfo fileInfo) + { + return (fileInfo.Name.Contains("oqtane.", StringComparison.OrdinalIgnoreCase)); + } + + public static IEnumerable GetOqtaneAssemblies(this AppDomain appDomain) + { + return appDomain.GetAssemblies().Where(a => a.IsOqtaneAssembly()); + } } } diff --git a/Oqtane.Server/Extensions/OqtaneMvcBuilderExtensions.cs b/Oqtane.Server/Extensions/OqtaneMvcBuilderExtensions.cs index 9464e767..fdb801df 100644 --- a/Oqtane.Server/Extensions/OqtaneMvcBuilderExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneMvcBuilderExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Reflection; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationParts; @@ -16,10 +17,11 @@ namespace Microsoft.Extensions.DependencyInjection } // load MVC application parts from module assemblies - foreach (var assembly in OqtaneServiceCollectionExtensions.GetOqtaneModuleAssemblies()) + var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); + foreach (var assembly in assemblies) { // check if assembly contains MVC Controllers - if (assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Controller))).ToArray().Length > 0) + if (assembly.GetTypes().Any(t => t.IsSubclassOf(typeof(Controller)))) { var partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly); foreach (var part in partFactory.GetApplicationParts(assembly)) diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 685327a9..5c093f48 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -5,67 +5,35 @@ using System.Linq; using System.Reflection; using System.Runtime.Loader; using Microsoft.Extensions.Hosting; +using Oqtane.Extensions; using Oqtane.Infrastructure; using Oqtane.Modules; +using Oqtane.Shared; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class OqtaneServiceCollectionExtensions { - private static readonly IList OqtaneModuleAssemblies = new List(); - - private static Assembly[] Assemblies => AppDomain.CurrentDomain.GetAssemblies(); - - internal static IEnumerable GetOqtaneModuleAssemblies() => OqtaneModuleAssemblies; - - public static IServiceCollection AddOqtaneModules(this IServiceCollection services) + public static IServiceCollection AddOqtaneParts(this IServiceCollection services) { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - LoadAssemblies("Module"); - + LoadAssemblies(); + services.AddOqtaneServices(); return services; } - public static IServiceCollection AddOqtaneThemes(this IServiceCollection services) + private static IServiceCollection AddOqtaneServices(this IServiceCollection services) { if (services is null) { throw new ArgumentNullException(nameof(services)); } - LoadAssemblies("Theme"); - - return services; - } - - public static IServiceCollection AddOqtaneSiteTemplates(this IServiceCollection services) - { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - LoadAssemblies("SiteTemplate"); - - return services; - } - - public static IServiceCollection AddOqtaneServices(this IServiceCollection services) - { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - // dynamically register module services, contexts, and repository classes - var assemblies = Assemblies.Where(item => item.FullName != null && (item.FullName.StartsWith("Oqtane.") || item.FullName.Contains(".Module."))).ToArray(); + var hostedServiceType = typeof(IHostedService); + var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); foreach (var assembly in assemblies) { + // dynamically register module services, contexts, and repository classes var implementationTypes = assembly.GetInterfaces(); foreach (var implementationType in implementationTypes) { @@ -75,22 +43,8 @@ namespace Microsoft.Extensions.DependencyInjection services.AddScoped(serviceType ?? implementationType, implementationType); } } - } - return services; - } - - public static IServiceCollection AddOqtaneHostedServices(this IServiceCollection services) - { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - // dynamically register hosted services - var hostedServiceType = typeof(IHostedService); - foreach (var assembly in Assemblies) - { + // dynamically register hosted services var serviceTypes = assembly.GetTypes(hostedServiceType); foreach (var serviceType in serviceTypes) { @@ -104,34 +58,50 @@ namespace Microsoft.Extensions.DependencyInjection return services; } - private static void LoadAssemblies(string pattern) + private static void LoadAssemblies() { var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); if (assemblyPath == null) return; var assembliesFolder = new DirectoryInfo(assemblyPath); + // iterate through Oqtane assemblies in /bin ( filter is narrow to optimize loading process ) - foreach (var dll in assembliesFolder.EnumerateFiles($"*.{pattern}.*.dll")) + foreach (var dll in assembliesFolder.EnumerateFiles($"*.dll", SearchOption.TopDirectoryOnly).Where(f => f.IsOqtaneAssembly())) { - // check if assembly is already loaded - var assembly = Assemblies.FirstOrDefault(a =>!a.IsDynamic && a.Location == dll.FullName); - if (assembly == null) + AssemblyName assemblyName; + try { - // load assembly ( and symbols ) from stream to prevent locking files ( as long as dependencies are in /bin they will load as well ) - string pdb = dll.FullName.Replace(".dll", ".pdb"); - if (File.Exists(pdb)) + assemblyName = AssemblyName.GetAssemblyName(dll.FullName); + } + catch + { + Console.WriteLine($"Not Assembly : {dll.Name}"); + continue; + } + + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + if (!assemblies.Any(a => AssemblyName.ReferenceMatchesDefinition(assemblyName, a.GetName()))) + { + try { - assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName)), new MemoryStream(File.ReadAllBytes(pdb))); + var pdb = Path.ChangeExtension(dll.FullName, ".pdb"); + Assembly assembly = null; + + // load assembly ( and symbols ) from stream to prevent locking files ( as long as dependencies are in /bin they will load as well ) + if (File.Exists(pdb)) + { + assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName)), new MemoryStream(File.ReadAllBytes(pdb))); + } + else + { + assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName))); + } + Console.WriteLine($"Loaded : {assemblyName}"); } - else + catch (Exception e) { - assembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(File.ReadAllBytes(dll.FullName))); - } - if (pattern == "Module") - { - // build a list of module assemblies - OqtaneModuleAssemblies.Add(assembly); + Console.WriteLine($"Failed : {assemblyName}\n{e}"); } } } diff --git a/Oqtane.Server/Extensions/StringExtensions.cs b/Oqtane.Server/Extensions/StringExtensions.cs new file mode 100644 index 00000000..49b3b2cd --- /dev/null +++ b/Oqtane.Server/Extensions/StringExtensions.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Oqtane.Extensions +{ + public static class StringExtensions + { + public static bool StartWithAnyOf(this string s, IEnumerable list) + { + if (s == null) + { + return false; + } + return list.Any(f => s.StartsWith(f)); + } + } +} diff --git a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs index 0e968076..9e717e37 100644 --- a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs +++ b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs @@ -75,6 +75,7 @@ namespace Oqtane.Repository // get module assemblies _moduleDefinitions = LoadModuleDefinitionsFromAssemblies(); } + List moduleDefinitions = _moduleDefinitions; List permissions = new List(); @@ -94,7 +95,7 @@ namespace Oqtane.Repository if (moduledef == null) { // new module definition - moduledef = new ModuleDefinition { ModuleDefinitionName = moduledefinition.ModuleDefinitionName }; + moduledef = new ModuleDefinition {ModuleDefinitionName = moduledefinition.ModuleDefinitionName}; _db.ModuleDefinition.Add(moduledef); _db.SaveChanges(); if (siteId != -1) @@ -109,18 +110,22 @@ namespace Oqtane.Repository { moduledefinition.Name = moduledef.Name; } + if (!string.IsNullOrEmpty(moduledef.Description)) { moduledefinition.Description = moduledef.Description; } + if (!string.IsNullOrEmpty(moduledef.Categories)) { moduledefinition.Categories = moduledef.Categories; } + if (!string.IsNullOrEmpty(moduledef.Version)) { moduledefinition.Version = moduledef.Version; } + if (siteId != -1) { if (permissions.Count == 0) @@ -139,9 +144,11 @@ namespace Oqtane.Repository } } } + // remove module definition from list as it is already synced moduledefs.Remove(moduledef); } + moduledefinition.ModuleDefinitionId = moduledef.ModuleDefinitionId; moduledefinition.SiteId = siteId; moduledefinition.CreatedBy = moduledef.CreatedBy; @@ -157,6 +164,7 @@ namespace Oqtane.Repository { _permissions.DeletePermissions(siteId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId); } + _db.ModuleDefinition.Remove(moduledefinition); // delete _db.SaveChanges(); } @@ -168,12 +176,12 @@ namespace Oqtane.Repository { List moduleDefinitions = new List(); // iterate through Oqtane module assemblies - Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies() - .Where(item => item.FullName.StartsWith("Oqtane.") || item.FullName.Contains(".Module.")).ToArray(); + var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); foreach (Assembly assembly in assemblies) { moduleDefinitions = LoadModuleDefinitionsFromAssembly(moduleDefinitions, assembly); } + return moduleDefinitions; } @@ -183,84 +191,92 @@ namespace Oqtane.Repository Type[] modulecontroltypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModuleControl))).ToArray(); foreach (Type modulecontroltype in modulecontroltypes) { - if (modulecontroltype.Name != "ModuleBase" && !modulecontroltype.Namespace.EndsWith(".Controls")) - { - string[] typename = modulecontroltype.AssemblyQualifiedName?.Split(',').Select(item => item.Trim()).ToArray(); - string[] segments = typename[0].Split('.'); - Array.Resize(ref segments, segments.Length - 1); - string moduleType = string.Join(".", segments); - string qualifiedModuleType = moduleType + ", " + typename[1]; + // Check if type should be ignored + if (modulecontroltype.Name == "ModuleBase" + || modulecontroltype.IsGenericType + || Attribute.IsDefined(modulecontroltype, typeof(OqtaneIgnoreAttribute)) + ) continue; - int index = moduledefinitions.FindIndex(item => item.ModuleDefinitionName == qualifiedModuleType); - if (index == -1) + string[] typename = modulecontroltype.AssemblyQualifiedName?.Split(',').Select(item => item.Trim()).ToArray(); + string[] segments = typename[0].Split('.'); + Array.Resize(ref segments, segments.Length - 1); + string moduleType = string.Join(".", segments); + string qualifiedModuleType = moduleType + ", " + typename[1]; + + int index = moduledefinitions.FindIndex(item => item.ModuleDefinitionName == qualifiedModuleType); + if (index == -1) + { + // determine if this module implements IModule + Type moduletype = assembly + .GetTypes() + .Where(item => item.Namespace != null) + .Where(item => item.Namespace.StartsWith(moduleType)) + .FirstOrDefault(item => item.GetInterfaces().Contains(typeof(IModule))); + if (moduletype != null) { - // determine if this module implements IModule - Type moduletype = assembly - .GetTypes() - .Where(item => item.Namespace != null) - .Where(item => item.Namespace.StartsWith(moduleType)) - .FirstOrDefault(item => item.GetInterfaces().Contains(typeof(IModule))); - if (moduletype != null) - { - // get property values from IModule - var moduleobject = Activator.CreateInstance(moduletype); - moduledefinition = (ModuleDefinition)moduletype.GetProperty("ModuleDefinition").GetValue(moduleobject); - } - else - { - // set default property values - moduledefinition = new ModuleDefinition - { - Name = moduleType.Substring(moduleType.LastIndexOf(".") + 1), - Description = "Manage " + moduleType.Substring(moduleType.LastIndexOf(".") + 1), - Categories = ((qualifiedModuleType.StartsWith("Oqtane.Modules.Admin.")) ? "Admin" : "") - }; - } - // set internal properties - moduledefinition.ModuleDefinitionName = qualifiedModuleType; - moduledefinition.Version = ""; // will be populated from database - moduledefinition.ControlTypeTemplate = moduleType + "." + Constants.ActionToken + ", " + typename[1]; - moduledefinition.AssemblyName = assembly.GetName().Name; - - if (string.IsNullOrEmpty(moduledefinition.Categories)) - { - moduledefinition.Categories = "Common"; - } - if (moduledefinition.Categories == "Admin") - { - moduledefinition.Permissions = new List - { - new Permission(PermissionNames.Utilize, Constants.AdminRole, true) - }.EncodePermissions(); - } - else - { - moduledefinition.Permissions = new List - { - new Permission(PermissionNames.Utilize, Constants.AdminRole, true), - new Permission(PermissionNames.Utilize, Constants.RegisteredRole, true) - }.EncodePermissions(); - } - moduledefinitions.Add(moduledefinition); - index = moduledefinitions.FindIndex(item => item.ModuleDefinitionName == qualifiedModuleType); + // get property values from IModule + var moduleobject = Activator.CreateInstance(moduletype); + moduledefinition = (ModuleDefinition) moduletype.GetProperty("ModuleDefinition").GetValue(moduleobject); } - moduledefinition = moduledefinitions[index]; - // actions - var modulecontrolobject = Activator.CreateInstance(modulecontroltype); - string actions = (string)modulecontroltype.GetProperty("Actions")?.GetValue(modulecontrolobject); - if (!string.IsNullOrEmpty(actions)) + else { - foreach (string action in actions.Split(',')) + // set default property values + moduledefinition = new ModuleDefinition { - moduledefinition.ControlTypeRoutes += (action + "=" + modulecontroltype.FullName + ", " + typename[1] + ";"); - } + Name = moduleType.Substring(moduleType.LastIndexOf(".") + 1), + Description = "Manage " + moduleType.Substring(moduleType.LastIndexOf(".") + 1), + Categories = ((qualifiedModuleType.StartsWith("Oqtane.Modules.Admin.")) ? "Admin" : "") + }; } - moduledefinitions[index] = moduledefinition; + + // set internal properties + moduledefinition.ModuleDefinitionName = qualifiedModuleType; + moduledefinition.Version = ""; // will be populated from database + moduledefinition.ControlTypeTemplate = moduleType + "." + Constants.ActionToken + ", " + typename[1]; + moduledefinition.AssemblyName = assembly.GetName().Name; + + if (string.IsNullOrEmpty(moduledefinition.Categories)) + { + moduledefinition.Categories = "Common"; + } + + if (moduledefinition.Categories == "Admin") + { + moduledefinition.Permissions = new List + { + new Permission(PermissionNames.Utilize, Constants.AdminRole, true) + }.EncodePermissions(); + } + else + { + moduledefinition.Permissions = new List + { + new Permission(PermissionNames.Utilize, Constants.AdminRole, true), + new Permission(PermissionNames.Utilize, Constants.RegisteredRole, true) + }.EncodePermissions(); + } + + Console.WriteLine($"Registering module: {moduledefinition.ModuleDefinitionName}"); + moduledefinitions.Add(moduledefinition); + index = moduledefinitions.FindIndex(item => item.ModuleDefinitionName == qualifiedModuleType); } + + moduledefinition = moduledefinitions[index]; + // actions + var modulecontrolobject = Activator.CreateInstance(modulecontroltype); + string actions = (string) modulecontroltype.GetProperty("Actions")?.GetValue(modulecontrolobject); + if (!string.IsNullOrEmpty(actions)) + { + foreach (string action in actions.Split(',')) + { + moduledefinition.ControlTypeRoutes += (action + "=" + modulecontroltype.FullName + ", " + typename[1] + ";"); + } + } + + moduledefinitions[index] = moduledefinition; } return moduledefinitions; } - } } diff --git a/Oqtane.Server/Repository/SiteTemplateRepository.cs b/Oqtane.Server/Repository/SiteTemplateRepository.cs index c471f5c0..6c559cdd 100644 --- a/Oqtane.Server/Repository/SiteTemplateRepository.cs +++ b/Oqtane.Server/Repository/SiteTemplateRepository.cs @@ -22,8 +22,8 @@ namespace Oqtane.Repository List siteTemplates = new List(); // iterate through Oqtane site template assemblies - Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies() - .Where(item => item.FullName.StartsWith("Oqtane.") || item.FullName.Contains(".SiteTemplate.")).ToArray(); + var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); + foreach (Assembly assembly in assemblies) { siteTemplates = LoadSiteTemplatesFromAssembly(siteTemplates, assembly); diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs index 943f42a8..9885fe83 100644 --- a/Oqtane.Server/Repository/ThemeRepository.cs +++ b/Oqtane.Server/Repository/ThemeRepository.cs @@ -31,8 +31,7 @@ namespace Oqtane.Repository List themes = new List(); // iterate through Oqtane theme assemblies - Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies() - .Where(item => item.FullName.StartsWith("Oqtane.") || item.FullName.Contains(".Theme.")).ToArray(); + var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies(); foreach (Assembly assembly in assemblies) { themes = LoadThemesFromAssembly(themes, assembly); diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 00b5f188..de4c89a7 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -41,7 +41,7 @@ namespace Oqtane // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { - services.AddMvc().AddNewtonsoftJson(); + services.AddServerSideBlazor(); // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) @@ -188,16 +188,13 @@ namespace Oqtane services.AddTransient(); // load the external assemblies into the app domain - services.AddOqtaneModules(); - services.AddOqtaneThemes(); - services.AddOqtaneSiteTemplates(); + services.AddOqtaneParts(); services.AddMvc() .AddOqtaneApplicationParts() // register any Controllers from custom modules .AddNewtonsoftJson(); - services.AddOqtaneServices(); - services.AddOqtaneHostedServices(); + services.AddSwaggerGen(c => { diff --git a/Oqtane.Shared/Shared/OqtaneIgnoreAttribute.cs b/Oqtane.Shared/Shared/OqtaneIgnoreAttribute.cs new file mode 100644 index 00000000..0cffe8d1 --- /dev/null +++ b/Oqtane.Shared/Shared/OqtaneIgnoreAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Oqtane.Shared +{ + [AttributeUsage(AttributeTargets.Class)] + public class OqtaneIgnoreAttribute : Attribute + { + } +}