From d46ba3463f6f08e09b34aafb278e3a44addb15b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 4 Jul 2023 17:27:34 +0300 Subject: [PATCH 1/7] Introduce AdditionalModuleAssemblyAttribute to define additional assemblies to be part of a module --- .../AspNetCore/Mvc/ApplicationPartSorter.cs | 4 +-- .../AbpRegistrationBuilderExtensions.cs | 2 +- .../Abp/Modularity/AbpModuleDescriptor.cs | 26 +++++++++++++++++++ .../AdditionalModuleAssemblyAttribute.cs | 24 +++++++++++++++++ .../Volo/Abp/Modularity/DependsOnAttribute.cs | 4 +-- .../Abp/Modularity/IAbpModuleDescriptor.cs | 23 ++++++++++++++++ .../IAdditionalModuleAssemblyProvider.cs | 8 ++++++ .../Volo/Abp/Modularity/ModuleLoader_Tests.cs | 5 ++++ 8 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalModuleAssemblyAttribute.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAdditionalModuleAssemblyProvider.cs 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) From db1609dced22afee4f2cd899485dad9159b732bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 4 Jul 2023 17:42:12 +0300 Subject: [PATCH 2/7] Use AllAssemblies instead of Type.Assembly --- .../AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs | 2 +- .../Volo/Abp/AbpApplicationBase.cs | 20 +++++++++++-------- .../Volo/Abp/Reflection/AssemblyFinder.cs | 2 +- .../Http/Client/Web/AbpHttpClientWebModule.cs | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index e22fef4236..0e93bb7ec6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -233,7 +233,7 @@ public class AbpAspNetCoreMvcModule : AbpModule .GetRequiredService() .Modules .Where(m => m.IsLoadedAsPlugIn) - .Select(m => m.Type.Assembly) + .SelectMany(m => m.AllAssemblies) .Distinct(); AddToApplicationParts(partManager, moduleAssemblies); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs index 0ccff2db23..ec20467ac9 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs @@ -188,11 +188,13 @@ public abstract class AbpApplicationBase : IAbpApplication { if (!abpModule.SkipAutoServiceRegistration) { - var assembly = module.Type.Assembly; - if (!assemblies.Contains(assembly)) + foreach (var assembly in module.AllAssemblies) { - Services.AddAssembly(assembly); - assemblies.Add(assembly); + if (!assemblies.Contains(assembly)) + { + Services.AddAssembly(assembly); + assemblies.Add(assembly); + } } } } @@ -279,11 +281,13 @@ public abstract class AbpApplicationBase : IAbpApplication { if (!abpModule.SkipAutoServiceRegistration) { - var assembly = module.Type.Assembly; - if (!assemblies.Contains(assembly)) + foreach (var assembly in module.AllAssemblies) { - Services.AddAssembly(assembly); - assemblies.Add(assembly); + if (!assemblies.Contains(assembly)) + { + Services.AddAssembly(assembly); + assemblies.Add(assembly); + } } } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/AssemblyFinder.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/AssemblyFinder.cs index 4e9a37db1a..602c577050 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/AssemblyFinder.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Reflection/AssemblyFinder.cs @@ -29,7 +29,7 @@ public class AssemblyFinder : IAssemblyFinder foreach (var module in _moduleContainer.Modules) { - assemblies.Add(module.Type.Assembly); + assemblies.AddRange(module.AllAssemblies); } return assemblies.Distinct().ToImmutableList(); diff --git a/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/AbpHttpClientWebModule.cs b/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/AbpHttpClientWebModule.cs index 5fcab7a7f1..655f96f068 100644 --- a/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/AbpHttpClientWebModule.cs +++ b/framework/src/Volo.Abp.Http.Client.Web/Volo/Abp/Http/Client/Web/AbpHttpClientWebModule.cs @@ -31,7 +31,7 @@ public class AbpHttpClientWebModule : AbpModule .ServiceProvider .GetRequiredService() .Modules - .Select(m => m.Type.Assembly) + .SelectMany(m => m.AllAssemblies) .Where(a => a.GetTypes().Any(AbpHttpClientProxyHelper.IsClientProxyService)) .Distinct()) { From fd47e4ed71b9db756ef9e910d46ddd7ba209ae70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 4 Jul 2023 18:00:06 +0300 Subject: [PATCH 3/7] Rename AdditionalModuleAssemblyAttribute and document usage --- docs/en/Module-Development-Basics.md | 21 ++++++++++++++++++- ...bute.cs => AdditionalAssemblyAttribute.cs} | 4 ++-- .../Abp/Modularity/IAbpModuleDescriptor.cs | 2 +- .../Volo/Abp/Modularity/ModuleLoader_Tests.cs | 2 +- .../Abp/Reflection/AssemblyFinder_Tests.cs | 2 ++ 5 files changed, 26 insertions(+), 5 deletions(-) rename framework/src/Volo.Abp.Core/Volo/Abp/Modularity/{AdditionalModuleAssemblyAttribute.cs => AdditionalAssemblyAttribute.cs} (74%) diff --git a/docs/en/Module-Development-Basics.md b/docs/en/Module-Development-Basics.md index dfce0bf4b2..915535906e 100644 --- a/docs/en/Module-Development-Basics.md +++ b/docs/en/Module-Development-Basics.md @@ -147,7 +147,7 @@ Lastly, you can override ``OnApplicationShutdown`` method if you want to execute ## Module Dependencies -In a modular application, it's not unusual for one module to depend upon another module(s). An Abp module must declare ``[DependsOn]`` attribute if it does have a dependency upon another module, as shown below: +In a modular application, it's not unusual for one module to depend upon another module(s). An ABP module must declare ``[DependsOn]`` attribute if it does have a dependency upon another module, as shown below: ````C# [DependsOn(typeof(AbpAspNetCoreMvcModule))] @@ -162,6 +162,25 @@ You can use multiple ``DependsOn`` attribute or pass multiple module types to a A depended module may depend on another module, but you only need to define your direct dependencies. ABP investigates the dependency graph for the application at startup and initializes/shutdowns modules in the correct order. +## Additional Module Assemblies + +ABP automatically registers all the services of your module to the [dependency injection](Dependency-Injection.md) system. It finds the service types by scanning types in the assembly that defines your module class. That assembly is considered as the main assembly of your module. + +Typically, every assembly contains a separate module class definition. Then modules depends on each other using the `DependsOn` attribute as explained in the previous section. However, in some rare cases, your module may be consisting of multiple assemblies, and only one of them defines a module class, and you want to make the other assemblies parts of your module. In that case, you can use the `AdditionalAssembly` attribute as shown below: + +````csharp +[DependsOn(...)] // Your module dependencies as you normally do +[AdditionalAssembly(typeof(BlogService))] +public class BlogModule +{ + //... +} +```` + +In this example, we assume that the `BlogService` class is inside one assembly (`csproj`) and the `BlogModule` class is inside another assembly (`csproj`). With the `AdditionalAssembly` definition, ABP will load the assembly containing the `BlogService` class as a part of the blog module. + +> WARNING: If you need to use the `AdditionalAssembly`, be sure that you don't design your system in a wrong way. With this example above, `BlogService` class' assembly should normally have its own module class and the `BlogModule` should depend on it using the `DependsOn` attribute. Do not use the `AdditionalAssembly` attribute when you can use the `DependsOn` attribute. + ## Framework Modules vs Application Modules There are **two types of modules.** They don't have any structural difference but categorized by functionality and purpose: diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalModuleAssemblyAttribute.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalAssemblyAttribute.cs similarity index 74% rename from framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalModuleAssemblyAttribute.cs rename to framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalAssemblyAttribute.cs index 4ae1be015e..ac4165f85e 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalModuleAssemblyAttribute.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AdditionalAssemblyAttribute.cs @@ -8,11 +8,11 @@ namespace Volo.Abp.Modularity; /// Used to define additional assemblies for a module. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] -public class AdditionalModuleAssemblyAttribute : Attribute, IAdditionalModuleAssemblyProvider +public class AdditionalAssemblyAttribute : Attribute, IAdditionalModuleAssemblyProvider { public Type[] TypesInAssemblies { get; } - public AdditionalModuleAssemblyAttribute(params Type[]? typesInAssemblies) + public AdditionalAssemblyAttribute(params Type[]? typesInAssemblies) { TypesInAssemblies = typesInAssemblies ?? Type.EmptyTypes; } 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 6b0a7214af..472009bfb3 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAbpModuleDescriptor.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/IAbpModuleDescriptor.cs @@ -19,7 +19,7 @@ public interface IAbpModuleDescriptor /// /// All the assemblies of the module. /// Includes the main and other assemblies defined - /// on the module using the attribute. + /// on the module using the attribute. /// List AllAssemblies { get; } 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 52cc7f7b70..d06025302d 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 @@ -28,7 +28,7 @@ public class ModuleLoader_Tests } [DependsOn(typeof(IndependentEmptyModule))] - [AdditionalModuleAssembly(typeof(IAbpApplication))] + [AdditionalAssembly(typeof(IAbpApplication))] public class MyStartupModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs index 2ba02eee6b..f3086dcb8c 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using NSubstitute; using Shouldly; using Volo.Abp.Modularity; @@ -50,6 +51,7 @@ public class AssemblyFinder_Tests { var moduleDescriptor = Substitute.For(); moduleDescriptor.Type.Returns(moduleType); + moduleDescriptor.AllAssemblies.Returns(new List { moduleType.Assembly }); return moduleDescriptor; } } From 7b2d369c4a31c0abe81462b3b97ca305494bc833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 4 Jul 2023 18:02:35 +0300 Subject: [PATCH 4/7] Added notice --- docs/en/Module-Development-Basics.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/Module-Development-Basics.md b/docs/en/Module-Development-Basics.md index 915535906e..7856c30557 100644 --- a/docs/en/Module-Development-Basics.md +++ b/docs/en/Module-Development-Basics.md @@ -170,7 +170,7 @@ Typically, every assembly contains a separate module class definition. Then modu ````csharp [DependsOn(...)] // Your module dependencies as you normally do -[AdditionalAssembly(typeof(BlogService))] +[AdditionalAssembly(typeof(BlogService))] // A type in the target assembly public class BlogModule { //... @@ -179,6 +179,8 @@ public class BlogModule In this example, we assume that the `BlogService` class is inside one assembly (`csproj`) and the `BlogModule` class is inside another assembly (`csproj`). With the `AdditionalAssembly` definition, ABP will load the assembly containing the `BlogService` class as a part of the blog module. +Notice that `BlogService` is only an arbitrary selected type in the target assembly. It is just used to indicate the related assembly. You could use any type in the assembly. + > WARNING: If you need to use the `AdditionalAssembly`, be sure that you don't design your system in a wrong way. With this example above, `BlogService` class' assembly should normally have its own module class and the `BlogModule` should depend on it using the `DependsOn` attribute. Do not use the `AdditionalAssembly` attribute when you can use the `DependsOn` attribute. ## Framework Modules vs Application Modules From 06a73e94a73451ab9dcb88f7030dc23bb62d5571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 4 Jul 2023 18:12:27 +0300 Subject: [PATCH 5/7] Typo fix --- docs/en/Module-Development-Basics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/Module-Development-Basics.md b/docs/en/Module-Development-Basics.md index 7856c30557..da26124ae5 100644 --- a/docs/en/Module-Development-Basics.md +++ b/docs/en/Module-Development-Basics.md @@ -166,7 +166,7 @@ A depended module may depend on another module, but you only need to define your ABP automatically registers all the services of your module to the [dependency injection](Dependency-Injection.md) system. It finds the service types by scanning types in the assembly that defines your module class. That assembly is considered as the main assembly of your module. -Typically, every assembly contains a separate module class definition. Then modules depends on each other using the `DependsOn` attribute as explained in the previous section. However, in some rare cases, your module may be consisting of multiple assemblies, and only one of them defines a module class, and you want to make the other assemblies parts of your module. In that case, you can use the `AdditionalAssembly` attribute as shown below: +Typically, every assembly contains a separate module class definition. Then modules depend on each other using the `DependsOn` attribute as explained in the previous section. However, in some rare cases, your module may be consisting of multiple assemblies, and only one of them defines a module class, and you want to make the other assemblies parts of your module. In that case, you can use the `AdditionalAssembly` attribute as shown below: ````csharp [DependsOn(...)] // Your module dependencies as you normally do @@ -181,7 +181,7 @@ In this example, we assume that the `BlogService` class is inside one assembly ( Notice that `BlogService` is only an arbitrary selected type in the target assembly. It is just used to indicate the related assembly. You could use any type in the assembly. -> WARNING: If you need to use the `AdditionalAssembly`, be sure that you don't design your system in a wrong way. With this example above, `BlogService` class' assembly should normally have its own module class and the `BlogModule` should depend on it using the `DependsOn` attribute. Do not use the `AdditionalAssembly` attribute when you can use the `DependsOn` attribute. +> WARNING: If you need to use the `AdditionalAssembly`, be sure that you don't design your system in a wrong way. With this example above, `BlogService` class' assembly should normally have its own module class and the `BlogModule` should depend on it using the `DependsOn` attribute. Do not use the `AdditionalAssembly` attribute when you can already use the `DependsOn` attribute. ## Framework Modules vs Application Modules From 5d5bb5aab19997680910275aac36fbe99cc9240d Mon Sep 17 00:00:00 2001 From: Hamza Albreem <94292623+braim23@users.noreply.github.com> Date: Tue, 4 Jul 2023 18:28:55 +0300 Subject: [PATCH 6/7] Quick Fix for Module Development Basics Doc --- docs/en/Module-Development-Basics.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/Module-Development-Basics.md b/docs/en/Module-Development-Basics.md index da26124ae5..1fdd09f8b2 100644 --- a/docs/en/Module-Development-Basics.md +++ b/docs/en/Module-Development-Basics.md @@ -147,7 +147,7 @@ Lastly, you can override ``OnApplicationShutdown`` method if you want to execute ## Module Dependencies -In a modular application, it's not unusual for one module to depend upon another module(s). An ABP module must declare ``[DependsOn]`` attribute if it does have a dependency upon another module, as shown below: +In a modular application, it's not unusual for one module to depend upon another module(s). An ABP module must declare a ``[DependsOn]`` attribute if it does have a dependency upon another module, as shown below: ````C# [DependsOn(typeof(AbpAspNetCoreMvcModule))] @@ -166,7 +166,7 @@ A depended module may depend on another module, but you only need to define your ABP automatically registers all the services of your module to the [dependency injection](Dependency-Injection.md) system. It finds the service types by scanning types in the assembly that defines your module class. That assembly is considered as the main assembly of your module. -Typically, every assembly contains a separate module class definition. Then modules depend on each other using the `DependsOn` attribute as explained in the previous section. However, in some rare cases, your module may be consisting of multiple assemblies, and only one of them defines a module class, and you want to make the other assemblies parts of your module. In that case, you can use the `AdditionalAssembly` attribute as shown below: +Typically, every assembly contains a separate module class definition. Then modules depend on each other using the `DependsOn` attribute as explained in the previous section. However, in some rare cases, your module may consist of multiple assemblies, and only one of them defines a module class, and you want to make the other assemblies parts of your module. In that case, you can use the `AdditionalAssembly` attribute as shown below: ````csharp [DependsOn(...)] // Your module dependencies as you normally do @@ -181,7 +181,7 @@ In this example, we assume that the `BlogService` class is inside one assembly ( Notice that `BlogService` is only an arbitrary selected type in the target assembly. It is just used to indicate the related assembly. You could use any type in the assembly. -> WARNING: If you need to use the `AdditionalAssembly`, be sure that you don't design your system in a wrong way. With this example above, `BlogService` class' assembly should normally have its own module class and the `BlogModule` should depend on it using the `DependsOn` attribute. Do not use the `AdditionalAssembly` attribute when you can already use the `DependsOn` attribute. +> WARNING: If you need to use the `AdditionalAssembly`, be sure that you don't design your system in a wrong way. With this example above, the `BlogService` class' assembly should normally have its own module class and the `BlogModule` should depend on it using the `DependsOn` attribute. Do not use the `AdditionalAssembly` attribute when you can already use the `DependsOn` attribute. ## Framework Modules vs Application Modules From 204254f62aed91a58cd34641a01c3b3a9b1fc969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 4 Jul 2023 18:39:28 +0300 Subject: [PATCH 7/7] Move CreateAllAssembliesList to AbpModuleHelper --- .../Abp/Modularity/AbpModuleDescriptor.cs | 24 +------------------ .../Volo/Abp/Modularity/AbpModuleHelper.cs | 21 ++++++++++++++++ 2 files changed, 22 insertions(+), 23 deletions(-) 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 cfd1ce6a4b..d10e858377 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleDescriptor.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleDescriptor.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; using System.Reflection; using JetBrains.Annotations; @@ -38,7 +37,7 @@ public class AbpModuleDescriptor : IAbpModuleDescriptor Type = type; Assembly = type.Assembly; - AllAssemblies = CreateAllAssembliesList(type); + AllAssemblies = AbpModuleHelper.GetAllAssemblies(type); Instance = instance; IsLoadedAsPlugIn = isLoadedAsPlugIn; @@ -54,25 +53,4 @@ 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/AbpModuleHelper.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs index 697543409e..8336433994 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Modularity/AbpModuleHelper.cs @@ -36,6 +36,27 @@ internal static class AbpModuleHelper return dependencies; } + + public static List GetAllAssemblies(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; + } private static void AddModuleAndDependenciesRecursively( List moduleTypes,