Browse Source

Introduced IModuleContainer. Created unit test for AssemblyFinder.

pull/96/head
Halil İbrahim Kalkan 9 years ago
parent
commit
b2b8074eab
  1. 4
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  2. 7
      src/Volo.Abp/Volo/Abp/AbpApplicationBase.cs
  3. 7
      src/Volo.Abp/Volo/Abp/IAbpApplication.cs
  4. 19
      src/Volo.Abp/Volo/Abp/Modularity/AbpModuleDescriptor.cs
  5. 16
      src/Volo.Abp/Volo/Abp/Modularity/IAbpModuleDescriptor.cs
  6. 11
      src/Volo.Abp/Volo/Abp/Modularity/IModuleContainer.cs
  7. 6
      src/Volo.Abp/Volo/Abp/Modularity/IModuleLoader.cs
  8. 6
      src/Volo.Abp/Volo/Abp/Modularity/IModuleManager.cs
  9. 33
      src/Volo.Abp/Volo/Abp/Modularity/ModuleLoader.cs
  10. 16
      src/Volo.Abp/Volo/Abp/Modularity/ModuleManager.cs
  11. 38
      src/Volo.Abp/Volo/Abp/Reflection/AssemblyFinder.cs
  12. 14
      src/Volo.Abp/Volo/Abp/Reflection/IAssemblyFinder.cs
  13. 14
      src/Volo.Abp/Volo/Abp/Reflection/ITypeFinder.cs
  14. 65
      src/Volo.Abp/Volo/Abp/Reflection/TypeFinder.cs
  15. 1
      test/Volo.Abp.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs
  16. 57
      test/Volo.Abp.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs
  17. 1
      test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs

4
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -49,9 +49,9 @@ namespace Volo.Abp.AspNetCore.Mvc
return;
}
var moduleManager = context.ServiceProvider.GetRequiredService<IModuleManager>();
var moduleContainer = context.ServiceProvider.GetRequiredService<IModuleContainer>();
foreach (var module in moduleManager.Modules.Where(m => m.IsLoadedAsPlugIn))
foreach (var module in moduleContainer.Modules.Where(m => m.IsLoadedAsPlugIn))
{
partManager.ApplicationParts.Add(new AssemblyPart(module.Type.GetTypeInfo().Assembly));
}

7
src/Volo.Abp/Volo/Abp/AbpApplicationBase.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Internal;
@ -15,8 +16,7 @@ namespace Volo.Abp
public IServiceCollection Services { get; }
[NotNull]
public AbpModuleDescriptor[] Modules { get; }
public IReadOnlyList<IAbpModuleDescriptor> Modules { get; }
internal AbpApplicationBase(
[NotNull] Type startupModuleType,
@ -33,12 +33,13 @@ namespace Volo.Abp
optionsAction?.Invoke(options);
services.AddSingleton<IAbpApplication>(_ => this);
services.AddSingleton<IModuleContainer>(_ => this);
services.AddCoreAbpServices();
Modules = LoadModules(services, options);
}
private AbpModuleDescriptor[] LoadModules(IServiceCollection services, AbpApplicationCreationOptions options)
private IReadOnlyList<IAbpModuleDescriptor> LoadModules(IServiceCollection services, AbpApplicationCreationOptions options)
{
return services
.GetSingletonInstance<IModuleLoader>()

7
src/Volo.Abp/Volo/Abp/IAbpApplication.cs

@ -4,7 +4,7 @@ using Volo.Abp.Modularity;
namespace Volo.Abp
{
public interface IAbpApplication : IDisposable
public interface IAbpApplication : IModuleContainer, IDisposable
{
/// <summary>
/// Type of the startup (entrance) module of the application.
@ -23,11 +23,6 @@ namespace Volo.Abp
/// </summary>
IServiceProvider ServiceProvider { get; }
/// <summary>
/// List of modules loaded into this application.
/// </summary>
AbpModuleDescriptor[] Modules { get; }
/// <summary>
/// Used to gracefully shutdown the application and all modules.
/// </summary>

19
src/Volo.Abp/Volo/Abp/Modularity/AbpModuleDescriptor.cs

@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Reflection;
using JetBrains.Annotations;
using Volo.ExtensionMethods.Collections.Generic;
namespace Volo.Abp.Modularity
{
public class AbpModuleDescriptor
public class AbpModuleDescriptor : IAbpModuleDescriptor
{
public Type Type { get; }
@ -13,9 +15,13 @@ namespace Volo.Abp.Modularity
public bool IsLoadedAsPlugIn { get; }
internal List<AbpModuleDescriptor> Dependencies { get; }
public IReadOnlyList<IAbpModuleDescriptor> Dependencies => _dependencies.ToImmutableList();
private readonly List<IAbpModuleDescriptor> _dependencies;
public AbpModuleDescriptor([NotNull] Type type, [NotNull] IAbpModule instance, bool isLoadedAsPlugIn)
public AbpModuleDescriptor(
[NotNull] Type type,
[NotNull] IAbpModule instance,
bool isLoadedAsPlugIn)
{
Check.NotNull(type, nameof(type));
Check.NotNull(instance, nameof(instance));
@ -29,7 +35,12 @@ namespace Volo.Abp.Modularity
Instance = instance;
IsLoadedAsPlugIn = isLoadedAsPlugIn;
Dependencies = new List<AbpModuleDescriptor>();
_dependencies = new List<IAbpModuleDescriptor>();
}
public void AddDependency(IAbpModuleDescriptor descriptor)
{
_dependencies.AddIfNotContains(descriptor);
}
public override string ToString()

16
src/Volo.Abp/Volo/Abp/Modularity/IAbpModuleDescriptor.cs

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Modularity
{
public interface IAbpModuleDescriptor
{
Type Type { get; }
IAbpModule Instance { get; }
bool IsLoadedAsPlugIn { get; }
IReadOnlyList<IAbpModuleDescriptor> Dependencies { get; }
}
}

11
src/Volo.Abp/Volo/Abp/Modularity/IModuleContainer.cs

@ -0,0 +1,11 @@
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Volo.Abp.Modularity
{
public interface IModuleContainer
{
[NotNull]
IReadOnlyList<IAbpModuleDescriptor> Modules { get; }
}
}

6
src/Volo.Abp/Volo/Abp/Modularity/IModuleLoader.cs

@ -8,6 +8,10 @@ namespace Volo.Abp.Modularity
public interface IModuleLoader
{
[NotNull]
AbpModuleDescriptor[] LoadModules([NotNull] IServiceCollection services, [NotNull] Type startupModuleType, [NotNull] PlugInSourceList plugInSources);
IAbpModuleDescriptor[] LoadModules(
[NotNull] IServiceCollection services,
[NotNull] Type startupModuleType,
[NotNull] PlugInSourceList plugInSources
);
}
}

6
src/Volo.Abp/Volo/Abp/Modularity/IModuleManager.cs

@ -1,13 +1,9 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using JetBrains.Annotations;
namespace Volo.Abp.Modularity
{
public interface IModuleManager
{
[NotNull]
IReadOnlyList<AbpModuleDescriptor> Modules { get; }
void InitializeModules([NotNull] ApplicationInitializationContext context);
void ShutdownModules([NotNull] ApplicationShutdownContext context);

33
src/Volo.Abp/Volo/Abp/Modularity/ModuleLoader.cs

@ -9,7 +9,7 @@ namespace Volo.Abp.Modularity
{
public class ModuleLoader : IModuleLoader
{
public AbpModuleDescriptor[] LoadModules(
public IAbpModuleDescriptor[] LoadModules(
IServiceCollection services,
Type startupModuleType,
PlugInSourceList plugInSources)
@ -18,18 +18,27 @@ namespace Volo.Abp.Modularity
Check.NotNull(startupModuleType, nameof(startupModuleType));
Check.NotNull(plugInSources, nameof(plugInSources));
var modules = new List<AbpModuleDescriptor>();
FillModules(modules, services, startupModuleType, plugInSources);
SetModuleDependencies(modules);
var modules = GetDescriptors(services, startupModuleType, plugInSources);
modules = SortByDependency(modules, startupModuleType);
ConfigureServices(modules, services);
return modules.ToArray();
}
private List<IAbpModuleDescriptor> GetDescriptors(
IServiceCollection services,
Type startupModuleType,
PlugInSourceList plugInSources)
{
var modules = new List<AbpModuleDescriptor>();
FillModules(modules, services, startupModuleType, plugInSources);
SetDependencies(modules);
return modules.Cast<IAbpModuleDescriptor>().ToList();
}
protected virtual void FillModules(
List<AbpModuleDescriptor> modules,
IServiceCollection services,
@ -54,15 +63,15 @@ namespace Volo.Abp.Modularity
}
}
protected virtual void SetModuleDependencies(List<AbpModuleDescriptor> modules)
protected virtual void SetDependencies(List<AbpModuleDescriptor> modules)
{
foreach (var module in modules)
{
SetModuleDependencies(modules, module);
SetDependencies(modules, module);
}
}
protected virtual List<AbpModuleDescriptor> SortByDependency(List<AbpModuleDescriptor> modules, Type startupModuleType)
protected virtual List<IAbpModuleDescriptor> SortByDependency(List<IAbpModuleDescriptor> modules, Type startupModuleType)
{
var sortedModules = modules.SortByDependencies(m => m.Dependencies);
sortedModules.MoveItem(m => m.Type == typeof(AbpKernelModule), 0);
@ -82,7 +91,7 @@ namespace Volo.Abp.Modularity
return module;
}
protected virtual void ConfigureServices(List<AbpModuleDescriptor> modules, IServiceCollection services)
protected virtual void ConfigureServices(List<IAbpModuleDescriptor> modules, IServiceCollection services)
{
//PreConfigureServices
foreach (var module in modules.Where(m => m.Instance is IPreConfigureServices))
@ -103,7 +112,7 @@ namespace Volo.Abp.Modularity
}
}
protected virtual void SetModuleDependencies(List<AbpModuleDescriptor> modules, AbpModuleDescriptor module)
protected virtual void SetDependencies(List<AbpModuleDescriptor> modules, AbpModuleDescriptor module)
{
foreach (var dependedModuleType in AbpModuleHelper.FindDependedModuleTypes(module.Type))
{
@ -113,7 +122,7 @@ namespace Volo.Abp.Modularity
throw new AbpException("Could not find a depended module " + dependedModuleType.AssemblyQualifiedName + " for " + module.Type.AssemblyQualifiedName);
}
module.Dependencies.AddIfNotContains(dependedModule);
module.AddDependency(dependedModule);
}
}
}

16
src/Volo.Abp/Volo/Abp/Modularity/ModuleManager.cs

@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.Extensions.Logging;
using Volo.DependencyInjection;
@ -8,20 +6,18 @@ namespace Volo.Abp.Modularity
{
public class ModuleManager : IModuleManager, ISingletonDependency
{
public IReadOnlyList<AbpModuleDescriptor> Modules => _modules.ToImmutableList();
private readonly List<AbpModuleDescriptor> _modules;
private readonly IModuleContainer _moduleContainer;
private readonly IEnumerable<IModuleLifecycleContributer> _lifecycleContributers;
private readonly ILogger<ModuleManager> _logger;
public ModuleManager(
IAbpApplication application,
IModuleContainer moduleContainer,
IEnumerable<IModuleLifecycleContributer> lifecycleContributers,
ILogger<ModuleManager> logger)
{
_moduleContainer = moduleContainer;
_lifecycleContributers = lifecycleContributers;
_logger = logger;
_modules = application.Modules.ToList();
}
public void InitializeModules(ApplicationInitializationContext context)
@ -30,7 +26,7 @@ namespace Volo.Abp.Modularity
foreach (var contributer in _lifecycleContributers)
{
foreach (var module in Modules)
foreach (var module in _moduleContainer.Modules)
{
contributer.Initialize(context, module.Instance);
}
@ -43,7 +39,7 @@ namespace Volo.Abp.Modularity
{
_logger.LogInformation("Loaded modules:");
foreach (var module in Modules)
foreach (var module in _moduleContainer.Modules)
{
_logger.LogInformation("- " + module.Type.FullName);
}
@ -53,7 +49,7 @@ namespace Volo.Abp.Modularity
{
foreach (var contributer in _lifecycleContributers)
{
foreach (var module in Modules)
foreach (var module in _moduleContainer.Modules)
{
contributer.Shutdown(context, module.Instance);
}

38
src/Volo.Abp/Volo/Abp/Reflection/AssemblyFinder.cs

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Threading;
using Volo.Abp.Modularity;
namespace Volo.Abp.Reflection
{
public class AssemblyFinder : IAssemblyFinder
{
private readonly IModuleContainer _moduleContainer;
private readonly Lazy<IReadOnlyList<Assembly>> _assemblies;
public AssemblyFinder(IModuleContainer moduleContainer)
{
_moduleContainer = moduleContainer;
_assemblies = new Lazy<IReadOnlyList<Assembly>>(FindAll, LazyThreadSafetyMode.ExecutionAndPublication);
}
public IReadOnlyList<Assembly> Assemblies => _assemblies.Value;
public IReadOnlyList<Assembly> FindAll()
{
var assemblies = new List<Assembly>();
foreach (var module in _moduleContainer.Modules)
{
assemblies.Add(module.Type.GetAssembly());
}
return assemblies.Distinct().ToImmutableList();
}
}
}

14
src/Volo.Abp/Volo/Abp/Reflection/IAssemblyFinder.cs

@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Reflection;
namespace Volo.Abp.Reflection
{
/// <summary>
/// Used to get assemblies in the application.
/// It may not return all assemblies, but those are related with modules.
/// </summary>
public interface IAssemblyFinder
{
IReadOnlyList<Assembly> Assemblies { get; }
}
}

14
src/Volo.Abp/Volo/Abp/Reflection/ITypeFinder.cs

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Reflection
{
/// <summary>
/// Used to get types in the application.
/// It may not return all types, but those are related with modules.
/// </summary>
public interface ITypeFinder
{
IReadOnlyList<Type> Types { get; }
}
}

65
src/Volo.Abp/Volo/Abp/Reflection/TypeFinder.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.Extensions.Logging;
using Volo.ExtensionMethods.Collections.Generic;
namespace Volo.Abp.Reflection
{
//TODO: Write unit tests!
public class TypeFinder : ITypeFinder
{
private readonly IAssemblyFinder _assemblyFinder;
private readonly ILogger<TypeFinder> _logger;
private readonly Lazy<IReadOnlyList<Type>> _types;
public TypeFinder(IAssemblyFinder assemblyFinder, ILogger<TypeFinder> logger)
{
_assemblyFinder = assemblyFinder;
_logger = logger;
_types = new Lazy<IReadOnlyList<Type>>(FindAll, LazyThreadSafetyMode.ExecutionAndPublication);
}
public IReadOnlyList<Type> Types => _types.Value;
private IReadOnlyList<Type> FindAll()
{
var allTypes = new List<Type>();
foreach (var assembly in _assemblyFinder.Assemblies)
{
try
{
Type[] typesInThisAssembly;
try
{
typesInThisAssembly = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
typesInThisAssembly = ex.Types;
}
if (typesInThisAssembly.IsNullOrEmpty())
{
continue;
}
allTypes.AddRange(typesInThisAssembly.Where(type => type != null));
}
catch (Exception ex)
{
_logger.LogWarning(ex.ToString());
}
}
return allTypes;
}
}
}

1
test/Volo.Abp.Tests/Volo/Abp/DynamicProxy/SimpleAsyncInterceptor.cs

@ -1,6 +1,5 @@
using System.Threading.Tasks;
using Volo.Abp.TestBase.Logging;
using Volo.DependencyInjection;
namespace Volo.Abp.DynamicProxy
{

57
test/Volo.Abp.Tests/Volo/Abp/Reflection/AssemblyFinder_Tests.cs

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NSubstitute;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.Reflection
{
public class AssemblyFinder_Tests
{
[Theory]
[InlineData(new object[] { new Type[] { } })]
[InlineData(new object[] { new[] { typeof(IndependentEmptyModule) } })]
[InlineData(new object[] { new[] { typeof(AbpKernelModule), typeof(IndependentEmptyModule) } })]
public void Should_Get_Assemblies_Of_All_Modules(Type[] moduleTypes)
{
//Arrange
var fakeModuleContainer = CreateFakeModuleContainer(moduleTypes);
//Act
var assemblyFinder = new AssemblyFinder(fakeModuleContainer);
//Assert
assemblyFinder.Assemblies.Count.ShouldBe(moduleTypes.Length);
foreach (var moduleType in moduleTypes)
{
assemblyFinder.Assemblies.ShouldContain(moduleType.GetAssembly());
}
}
private static IModuleContainer CreateFakeModuleContainer(IEnumerable<Type> moduleTypes)
{
var moduleDescriptors = moduleTypes.Select(CreateModuleDescriptor).ToList();
return CreateFakeModuleContainer(moduleDescriptors);
}
private static IModuleContainer CreateFakeModuleContainer(List<IAbpModuleDescriptor> moduleDescriptors)
{
var fakeModuleContainer = Substitute.For<IModuleContainer>();
fakeModuleContainer.Modules.Returns(moduleDescriptors);
return fakeModuleContainer;
}
private static IAbpModuleDescriptor CreateModuleDescriptor(Type moduleType)
{
var moduleDescriptor = Substitute.For<IAbpModuleDescriptor>();
moduleDescriptor.Type.Returns(moduleType);
return moduleDescriptor;
}
}
}

1
test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Events_Tests.cs

@ -66,7 +66,6 @@ namespace Volo.Abp.Uow
disposed.ShouldBeTrue();
}
[Fact]
public void Should_Not_Trigger_Complete_If_Uow_Is_Not_Completed()
{

Loading…
Cancel
Save