diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationPartSorter.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationPartSorter.cs index 9664a2005e..dc39ef5f53 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationPartSorter.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationPartSorter.cs @@ -125,7 +125,7 @@ public static class ApplicationPartSorter var moduleDependedAssemblies = moduleDescriptor .Dependencies - .Select(d => d.Assembly) + .SelectMany(d => d.AllAssemblies) .ToArray(); return partManager.ApplicationParts @@ -161,6 +161,6 @@ public static class ApplicationPartSorter { return moduleContainer .Modules - .FirstOrDefault(m => m.Assembly == assembly); + .FirstOrDefault(m => m.AllAssemblies.Contains(assembly)); } } diff --git a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs index 03084d8351..4ee9ba5916 100644 --- a/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.Autofac/Autofac/Builder/AbpRegistrationBuilderExtensions.cs @@ -69,7 +69,7 @@ public static class AbpRegistrationBuilderExtensions where TActivatorData : ReflectionActivatorData { // Enable Property Injection only for types in an assembly containing an AbpModule and without a DisablePropertyInjection attribute on class or properties. - if (moduleContainer.Modules.Any(m => m.Assembly == implementationType.Assembly) && + if (moduleContainer.Modules.Any(m => m.AllAssemblies.Contains(implementationType.Assembly)) && implementationType.GetCustomAttributes(typeof(DisablePropertyInjectionAttribute), true).IsNullOrEmpty()) { registrationBuilder = registrationBuilder.PropertiesAutowired(new AbpPropertySelector(false)); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleDescriptor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleDescriptor.cs index dcb9cfc817..cfd1ce6a4b 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleDescriptor.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleDescriptor.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Reflection; using JetBrains.Annotations; @@ -11,6 +12,8 @@ public class AbpModuleDescriptor : IAbpModuleDescriptor public Type Type { get; } public Assembly Assembly { get; } + + public List AllAssemblies { get; } public IAbpModule Instance { get; } @@ -26,6 +29,7 @@ public class AbpModuleDescriptor : IAbpModuleDescriptor { Check.NotNull(type, nameof(type)); Check.NotNull(instance, nameof(instance)); + AbpModule.CheckAbpModuleType(type); if (!type.GetTypeInfo().IsAssignableFrom(instance.GetType())) { @@ -34,6 +38,7 @@ public class AbpModuleDescriptor : IAbpModuleDescriptor Type = type; Assembly = type.Assembly; + AllAssemblies = CreateAllAssembliesList(type); Instance = instance; IsLoadedAsPlugIn = isLoadedAsPlugIn; @@ -49,4 +54,25 @@ public class AbpModuleDescriptor : IAbpModuleDescriptor { return $"[AbpModuleDescriptor {Type.FullName}]"; } + + private static List CreateAllAssembliesList(Type moduleType) + { + var assemblies = new List(); + + var additionalAssemblyDescriptors = moduleType + .GetCustomAttributes() + .OfType(); + + foreach (var descriptor in additionalAssemblyDescriptors) + { + foreach (var assembly in descriptor.GetAssemblies()) + { + assemblies.AddIfNotContains(assembly); + } + } + + assemblies.Add(moduleType.Assembly); + + return assemblies; + } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalModuleAssemblyAttribute.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalModuleAssemblyAttribute.cs new file mode 100644 index 0000000000..4ae1be015e --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalModuleAssemblyAttribute.cs @@ -0,0 +1,24 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace Volo.Abp.Modularity; + +/// +/// Used to define additional assemblies for a module. +/// +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +public class AdditionalModuleAssemblyAttribute : Attribute, IAdditionalModuleAssemblyProvider +{ + public Type[] TypesInAssemblies { get; } + + public AdditionalModuleAssemblyAttribute(params Type[]? typesInAssemblies) + { + TypesInAssemblies = typesInAssemblies ?? Type.EmptyTypes; + } + + public virtual Assembly[] GetAssemblies() + { + return TypesInAssemblies.Select(t => t.Assembly).Distinct().ToArray(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/DependsOnAttribute.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/DependsOnAttribute.cs index 89970859e8..8792d146d9 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/DependsOnAttribute.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/DependsOnAttribute.cs @@ -1,5 +1,4 @@ using System; -using JetBrains.Annotations; namespace Volo.Abp.Modularity; @@ -9,12 +8,11 @@ namespace Volo.Abp.Modularity; [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class DependsOnAttribute : Attribute, IDependedTypesProvider { - [NotNull] public Type[] DependedTypes { get; } public DependsOnAttribute(params Type[]? dependedTypes) { - DependedTypes = dependedTypes ?? new Type[0]; + DependedTypes = dependedTypes ?? Type.EmptyTypes; } public virtual Type[] GetDependedTypes() diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAbpModuleDescriptor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAbpModuleDescriptor.cs index 8a4fb1e270..6b0a7214af 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAbpModuleDescriptor.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAbpModuleDescriptor.cs @@ -6,13 +6,36 @@ namespace Volo.Abp.Modularity; public interface IAbpModuleDescriptor { + /// + /// Type of the module class. + /// Type Type { get; } + /// + /// Main assembly that defines the module . + /// Assembly Assembly { get; } + + /// + /// All the assemblies of the module. + /// Includes the main and other assemblies defined + /// on the module using the attribute. + /// + List AllAssemblies { get; } + /// + /// The instance of the module class (singleton). + /// IAbpModule Instance { get; } + /// + /// Is this module loaded as a plug-in? + /// bool IsLoadedAsPlugIn { get; } + /// + /// Modules on which this module depends on. + /// A module can depend on another module using the attribute. + /// IReadOnlyList Dependencies { get; } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAdditionalModuleAssemblyProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAdditionalModuleAssemblyProvider.cs new file mode 100644 index 0000000000..3a26d8e918 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAdditionalModuleAssemblyProvider.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +namespace Volo.Abp.Modularity; + +public interface IAdditionalModuleAssemblyProvider +{ + Assembly[] GetAssemblies(); +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs index eb15943670..52cc7f7b70 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Modularity/ModuleLoader_Tests.cs @@ -21,9 +21,14 @@ public class ModuleLoader_Tests modules.Length.ShouldBe(2); modules[0].Type.ShouldBe(typeof(IndependentEmptyModule)); modules[1].Type.ShouldBe(typeof(MyStartupModule)); + modules[1].Assembly.ShouldBe(typeof(MyStartupModule).Assembly); + modules[1].AllAssemblies.Count.ShouldBe(2); + modules[1].AllAssemblies[0].ShouldBe(typeof(IAbpApplication).Assembly); + modules[1].AllAssemblies[1].ShouldBe(typeof(MyStartupModule).Assembly); } [DependsOn(typeof(IndependentEmptyModule))] + [AdditionalModuleAssembly(typeof(IAbpApplication))] public class MyStartupModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context)