diff --git a/Volo.Abp.sln b/Volo.Abp.sln index e2c6b120f7..81d733760c 100644 --- a/Volo.Abp.sln +++ b/Volo.Abp.sln @@ -30,6 +30,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Abp", "Abp", "{37087D1B-369 EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AbpTestBase", "test\AbpTestBase\AbpTestBase.xproj", "{1020F5FD-6A97-40C2-AFCA-EBDF641DF111}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.Abp.AspNetCore", "src\Volo.Abp.AspNetCore\Volo.Abp.AspNetCore.xproj", "{02BE03BA-3411-448C-AB61-CB36407CC49A}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.Abp.AspNetCore.Tests", "test\Volo.Abp.AspNetCore.Tests\Volo.Abp.AspNetCore.Tests.xproj", "{B1D860BB-6EC6-4BAE-ADAA-C2AEC2FFB510}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{A3A3B258-B3D5-4FDE-9D84-CAA8CBB70586}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AspNetCoreDemo", "test\Apps\AspNetCoreDemo\AspNetCoreDemo.xproj", "{12E14D95-4ABA-4290-AB1D-CCF5EB158411}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.ExtensionMethods", "src\Volo.ExtensionMethods\Volo.ExtensionMethods.xproj", "{FC889503-0BF4-4959-AC80-F51073787025}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Volo.CodeAnnotations", "src\Volo.CodeAnnotations\Volo.CodeAnnotations.xproj", "{161A6C10-00FF-4348-993F-D19893ABC57C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -56,6 +68,26 @@ Global {1020F5FD-6A97-40C2-AFCA-EBDF641DF111}.Debug|Any CPU.Build.0 = Debug|Any CPU {1020F5FD-6A97-40C2-AFCA-EBDF641DF111}.Release|Any CPU.ActiveCfg = Release|Any CPU {1020F5FD-6A97-40C2-AFCA-EBDF641DF111}.Release|Any CPU.Build.0 = Release|Any CPU + {02BE03BA-3411-448C-AB61-CB36407CC49A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02BE03BA-3411-448C-AB61-CB36407CC49A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02BE03BA-3411-448C-AB61-CB36407CC49A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02BE03BA-3411-448C-AB61-CB36407CC49A}.Release|Any CPU.Build.0 = Release|Any CPU + {B1D860BB-6EC6-4BAE-ADAA-C2AEC2FFB510}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1D860BB-6EC6-4BAE-ADAA-C2AEC2FFB510}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1D860BB-6EC6-4BAE-ADAA-C2AEC2FFB510}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1D860BB-6EC6-4BAE-ADAA-C2AEC2FFB510}.Release|Any CPU.Build.0 = Release|Any CPU + {12E14D95-4ABA-4290-AB1D-CCF5EB158411}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12E14D95-4ABA-4290-AB1D-CCF5EB158411}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12E14D95-4ABA-4290-AB1D-CCF5EB158411}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12E14D95-4ABA-4290-AB1D-CCF5EB158411}.Release|Any CPU.Build.0 = Release|Any CPU + {FC889503-0BF4-4959-AC80-F51073787025}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC889503-0BF4-4959-AC80-F51073787025}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC889503-0BF4-4959-AC80-F51073787025}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC889503-0BF4-4959-AC80-F51073787025}.Release|Any CPU.Build.0 = Release|Any CPU + {161A6C10-00FF-4348-993F-D19893ABC57C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {161A6C10-00FF-4348-993F-D19893ABC57C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {161A6C10-00FF-4348-993F-D19893ABC57C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {161A6C10-00FF-4348-993F-D19893ABC57C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -70,5 +102,11 @@ Global {D68B762E-2A55-4A9F-9F2F-D4361B0925B0} = {82B41A0A-6068-410F-9C6B-2508CA763E21} {37087D1B-3693-4E96-983D-A69F210BDE53} = {447C8A77-E5F0-4538-8687-7383196D04EA} {1020F5FD-6A97-40C2-AFCA-EBDF641DF111} = {82B41A0A-6068-410F-9C6B-2508CA763E21} + {02BE03BA-3411-448C-AB61-CB36407CC49A} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8} + {B1D860BB-6EC6-4BAE-ADAA-C2AEC2FFB510} = {37087D1B-3693-4E96-983D-A69F210BDE53} + {A3A3B258-B3D5-4FDE-9D84-CAA8CBB70586} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {12E14D95-4ABA-4290-AB1D-CCF5EB158411} = {A3A3B258-B3D5-4FDE-9D84-CAA8CBB70586} + {FC889503-0BF4-4959-AC80-F51073787025} = {9A4A646B-CC96-44FB-A717-E50C5C148B54} + {161A6C10-00FF-4348-993F-D19893ABC57C} = {9A4A646B-CC96-44FB-A717-E50C5C148B54} EndGlobalSection EndGlobal diff --git a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpApplicationBuilderExtensions.cs b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpApplicationBuilderExtensions.cs new file mode 100644 index 0000000000..ec4abe08e3 --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpApplicationBuilderExtensions.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.DependencyInjection; + +namespace Microsoft.AspNetCore.Builder +{ + public static class AbpApplicationBuilderExtensions + { + public static void InitializeAbpApplication(this IApplicationBuilder app) //TODO: Simply rename to InitializeApplication? + { + var abpApplication = app.ApplicationServices.GetRequiredService(); + + app.ApplicationServices.GetRequiredService().App = app; + + abpApplication.Initialize(app.ApplicationServices); + } + } + + public class ApplicationBuilderAccessor : ISingletonDependency + { + public IApplicationBuilder App { get; set; } + } +} diff --git a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpAspNetCoreModule.cs b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpAspNetCoreModule.cs new file mode 100644 index 0000000000..59264a50cc --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpAspNetCoreModule.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Modularity; +using Volo.Abp.Modularity; +using Volo.DependencyInjection; + +namespace Volo.Abp.AspNetCore +{ + public class AbpAspNetCoreModule : IAbpModule + { + public void ConfigureServices(IServiceCollection services) + { + services.AddAssemblyOf(); + services.AddSingleton(); + } + } +} diff --git a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpServiceCollectionExtensions.cs b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpServiceCollectionExtensions.cs new file mode 100644 index 0000000000..a2e03dbad5 --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/AbpServiceCollectionExtensions.cs @@ -0,0 +1,15 @@ +using Volo.Abp; +using Volo.Abp.Modularity; + +namespace Microsoft.Extensions.DependencyInjection +{ + //TODO: Decide to move ABP? + public static class AbpServiceCollectionExtensions + { + public static void AddAbpApplication(this IServiceCollection services) //TODO: Simply rename to AddApplication? + where TStartupModule : IAbpModule + { + AbpApplication.Create(services); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Builder/AspNetConfigurationContext.cs b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Builder/AspNetConfigurationContext.cs new file mode 100644 index 0000000000..4890dc41de --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Builder/AspNetConfigurationContext.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Volo.Abp.AspNetCore.Builder +{ + public class AspNetConfigurationContext + { + public IApplicationBuilder App { get; } + + public IHostingEnvironment Environment { get; } + + public ILoggerFactory LoggerFactory { get; } + + public AspNetConfigurationContext(IApplicationBuilder app) + { + App = app; + Environment = app.ApplicationServices.GetRequiredService(); + LoggerFactory = app.ApplicationServices.GetRequiredService(); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Builder/IConfigureAspNet.cs b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Builder/IConfigureAspNet.cs new file mode 100644 index 0000000000..48de0f72bb --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Builder/IConfigureAspNet.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.AspNetCore.Builder +{ + public interface IConfigureAspNet + { + void Configure(AspNetConfigurationContext context); + } +} diff --git a/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Modularity/AspNetCoreModuleInitializer.cs b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Modularity/AspNetCoreModuleInitializer.cs new file mode 100644 index 0000000000..d88799a72a --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Abp/AspNetCore/Modularity/AspNetCoreModuleInitializer.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Builder; +using Volo.Abp.AspNetCore.Builder; +using Volo.Abp.Modularity; + +namespace Volo.Abp.AspNetCore.Modularity +{ + public class AspNetCoreModuleInitializer : IModuleInitializer + { + private readonly AspNetConfigurationContext _configurationContext; + + public AspNetCoreModuleInitializer(ApplicationBuilderAccessor appAccessor) + { + _configurationContext = new AspNetConfigurationContext(appAccessor.App); + } + + public void Initialize(IAbpModule module) + { + (module as IConfigureAspNet)?.Configure(_configurationContext); + } + } +} diff --git a/src/Volo.Abp.AspNetCore/Properties/AssemblyInfo.cs b/src/Volo.Abp.AspNetCore/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..313776b4b9 --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Volo.Abp.AspNetCore")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("02be03ba-3411-448c-ab61-cb36407cc49a")] diff --git a/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.xproj b/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.xproj new file mode 100644 index 0000000000..423d263a92 --- /dev/null +++ b/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 02be03ba-3411-448c-ab61-cb36407cc49a + Volo + .\obj + .\bin\ + v4.6.1 + + + 2.0 + + + \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore/project.json b/src/Volo.Abp.AspNetCore/project.json new file mode 100644 index 0000000000..f231b64bf2 --- /dev/null +++ b/src/Volo.Abp.AspNetCore/project.json @@ -0,0 +1,16 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "NETStandard.Library": "1.6.1", + "Volo.Abp": "1.0.0-*", + "Microsoft.AspNetCore.Http.Abstractions": "1.1.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "1.1.0" + }, + + "frameworks": { + "netstandard1.6": { + "imports": "dnxcore50" + } + } +} diff --git a/src/Volo.Abp/AbpBootstrapper.cs b/src/Volo.Abp/Abp/AbpApplication.cs similarity index 52% rename from src/Volo.Abp/AbpBootstrapper.cs rename to src/Volo.Abp/Abp/AbpApplication.cs index 1951daed9a..3174426c1c 100644 --- a/src/Volo.Abp/AbpBootstrapper.cs +++ b/src/Volo.Abp/Abp/AbpApplication.cs @@ -1,22 +1,23 @@ using System; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Modularity; namespace Volo.Abp { - public class AbpApplication : IDisposable + public class AbpApplication : IAbpApplication { public Type StartupModuleType { get; } - private readonly IServiceCollection _services; private IServiceProvider _serviceProvider; private AbpApplication(Type startupModuleType, IServiceCollection services) { StartupModuleType = startupModuleType; - _services = services; - _services.AddCoreAbp(); + + services.AddSingleton(this); + services.AddCoreAbpServices(); + + services.GetSingletonInstance().LoadAll(services, StartupModuleType); } public static AbpApplication Create(IServiceCollection services) @@ -25,23 +26,15 @@ namespace Volo.Abp return new AbpApplication(typeof(TStartupModule), services); } - public void Start(IServiceProvider serviceProvider) + public void Initialize(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; - _serviceProvider.GetRequiredService().Start(); + _serviceProvider.GetRequiredService().Initialize(); } public void Dispose() { - _serviceProvider.GetRequiredService().Stop(); - } - } - internal static class AbpServiceCollectionExtensions - { - public static void AddCoreAbp(this IServiceCollection services) - { - services.TryAddSingleton(); } } } diff --git a/src/Volo.Abp/Abp/AbpException.cs b/src/Volo.Abp/Abp/AbpException.cs new file mode 100644 index 0000000000..10418a4088 --- /dev/null +++ b/src/Volo.Abp/Abp/AbpException.cs @@ -0,0 +1,39 @@ +using System; + +namespace Volo.Abp +{ + /// + /// Base exception type for those are thrown by Abp system for Abp specific exceptions. + /// + public class AbpException : Exception + { + /// + /// Creates a new object. + /// + public AbpException() + { + + } + + /// + /// Creates a new object. + /// + /// Exception message + public AbpException(string message) + : base(message) + { + + } + + /// + /// Creates a new object. + /// + /// Exception message + /// Inner exception + public AbpException(string message, Exception innerException) + : base(message, innerException) + { + + } + } +} diff --git a/src/Volo.Abp/Abp/AbpKernelModule.cs b/src/Volo.Abp/Abp/AbpKernelModule.cs new file mode 100644 index 0000000000..6fc0910396 --- /dev/null +++ b/src/Volo.Abp/Abp/AbpKernelModule.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace Volo.Abp +{ + public class AbpKernelModule : IAbpModule + { + public void ConfigureServices(IServiceCollection services) + { + + } + } +} diff --git a/src/Volo.Abp/Abp/AbpServiceCollectionExtensions.cs b/src/Volo.Abp/Abp/AbpServiceCollectionExtensions.cs new file mode 100644 index 0000000000..e63f88fc96 --- /dev/null +++ b/src/Volo.Abp/Abp/AbpServiceCollectionExtensions.cs @@ -0,0 +1,35 @@ +using System; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.Modularity; + +namespace Volo.Abp +{ + public static class AbpServiceCollectionExtensions + { + public static T GetSingletonInstanceOrNull(this IServiceCollection services) + { + return (T)services + .FirstOrDefault(d => d.ServiceType == typeof(T)) + ?.ImplementationInstance; + } + + public static T GetSingletonInstance(this IServiceCollection services) + { + var service = services.GetSingletonInstanceOrNull(); + if (service == null) + { + throw new InvalidOperationException("Could not find singleton service: " + typeof(T).AssemblyQualifiedName); + } + + return service; + } + + internal static void AddCoreAbpServices(this IServiceCollection services) + { + services.TryAddSingleton(new ModuleLoader()); + services.TryAddSingleton(); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Abp/IAbpApplication.cs b/src/Volo.Abp/Abp/IAbpApplication.cs new file mode 100644 index 0000000000..e68154d127 --- /dev/null +++ b/src/Volo.Abp/Abp/IAbpApplication.cs @@ -0,0 +1,11 @@ +using System; + +namespace Volo.Abp +{ + public interface IAbpApplication : IDisposable + { + Type StartupModuleType { get; } + + void Initialize(IServiceProvider serviceProvider); + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Abp/Modularity/AbpModuleDescriptor.cs b/src/Volo.Abp/Abp/Modularity/AbpModuleDescriptor.cs new file mode 100644 index 0000000000..e1091506d3 --- /dev/null +++ b/src/Volo.Abp/Abp/Modularity/AbpModuleDescriptor.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Abp.Modularity +{ + public class AbpModuleDescriptor + { + public Type Type { get; } + + public IAbpModule Instance { get; } + + public List Dependencies { get; } + + public AbpModuleDescriptor([NotNull] Type type, [NotNull] IAbpModule instance) + { + Check.NotNull(type, nameof(type)); + Check.NotNull(instance, nameof(instance)); + + Type = type; + Instance = instance; + Dependencies = new List(); + } + } +} diff --git a/src/Volo.Abp/Abp/Modularity/DependsOnAttribute.cs b/src/Volo.Abp/Abp/Modularity/DependsOnAttribute.cs new file mode 100644 index 0000000000..eaa1ca84ce --- /dev/null +++ b/src/Volo.Abp/Abp/Modularity/DependsOnAttribute.cs @@ -0,0 +1,31 @@ +using System; + +namespace Volo.Abp.Modularity +{ + /// + /// Used to define dependencies of an ABP module to other modules. + /// It should be used for a class implements . + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class DependsOnAttribute : Attribute, IModuleDependencyDescriptor + { + /// + /// Types of depended modules. + /// + public Type[] DependedModuleTypes { get; } + + /// + /// Used to define dependencies of an ABP module to other modules. + /// + /// Types of depended modules + public DependsOnAttribute(params Type[] dependedModuleTypes) + { + DependedModuleTypes = dependedModuleTypes; + } + + public Type[] GetDependedModuleTypes() + { + return DependedModuleTypes; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Modularity/IAbpModule.cs b/src/Volo.Abp/Abp/Modularity/IAbpModule.cs similarity index 100% rename from src/Volo.Abp/Modularity/IAbpModule.cs rename to src/Volo.Abp/Abp/Modularity/IAbpModule.cs diff --git a/src/Volo.Abp/Abp/Modularity/IModuleDependencyDescriptor.cs b/src/Volo.Abp/Abp/Modularity/IModuleDependencyDescriptor.cs new file mode 100644 index 0000000000..549a16d462 --- /dev/null +++ b/src/Volo.Abp/Abp/Modularity/IModuleDependencyDescriptor.cs @@ -0,0 +1,9 @@ +using System; + +namespace Volo.Abp.Modularity +{ + public interface IModuleDependencyDescriptor + { + Type[] GetDependedModuleTypes(); + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Abp/Modularity/IModuleInitializer.cs b/src/Volo.Abp/Abp/Modularity/IModuleInitializer.cs new file mode 100644 index 0000000000..7d2d6bdc99 --- /dev/null +++ b/src/Volo.Abp/Abp/Modularity/IModuleInitializer.cs @@ -0,0 +1,9 @@ +using Volo.DependencyInjection; + +namespace Volo.Abp.Modularity +{ + public interface IModuleInitializer : ISingletonDependency + { + void Initialize(IAbpModule module); + } +} diff --git a/src/Volo.Abp/Abp/Modularity/IModuleLoader.cs b/src/Volo.Abp/Abp/Modularity/IModuleLoader.cs new file mode 100644 index 0000000000..8f4eaced4a --- /dev/null +++ b/src/Volo.Abp/Abp/Modularity/IModuleLoader.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Volo.DependencyInjection; + +namespace Volo.Abp.Modularity +{ + public interface IModuleLoader : ISingletonDependency + { + IReadOnlyList Modules { get; } + + void LoadAll(IServiceCollection services, Type startupModuleType); + } +} diff --git a/src/Volo.Abp/Abp/Modularity/IModuleManager.cs b/src/Volo.Abp/Abp/Modularity/IModuleManager.cs new file mode 100644 index 0000000000..446645bcae --- /dev/null +++ b/src/Volo.Abp/Abp/Modularity/IModuleManager.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.Modularity +{ + public interface IModuleManager + { + void Initialize(); + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Abp/Modularity/ModuleLoader.cs b/src/Volo.Abp/Abp/Modularity/ModuleLoader.cs new file mode 100644 index 0000000000..dd8b0b8e5c --- /dev/null +++ b/src/Volo.Abp/Abp/Modularity/ModuleLoader.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection; +using Microsoft.Extensions.DependencyInjection; +using Volo.Collections.Generic; + +namespace Volo.Abp.Modularity +{ + public class ModuleLoader : IModuleLoader + { + public IReadOnlyList Modules => _modules.ToImmutableList(); + private readonly List _modules; + + public ModuleLoader() + { + _modules = new List(); + } + + public virtual void LoadAll(IServiceCollection services, Type startupModuleType) + { + if (_modules.Any()) + { + throw new InvalidOperationException($"{nameof(LoadAll)} should be called only once!"); + } + + FillModules(startupModuleType); + SetModuleDependencies(); + ConfigureServices(services); + } + + private void SetModuleDependencies() + { + foreach (var module in Modules) + { + SetModuleDependencies(module); + } + } + + private void FillModules(Type startupModuleType) + { + foreach (var moduleType in FindAllModuleTypes(startupModuleType).Distinct()) + { + _modules.Add(CreateModuleDescriptor(moduleType)); + } + } + + protected virtual IEnumerable FindAllModuleTypes(Type startupModuleType) + { + var moduleTypes = new List(); + AddModuleAndDependenciesResursively(moduleTypes, startupModuleType); + moduleTypes.AddIfNotContains(typeof(AbpKernelModule)); + return moduleTypes; + } + + protected virtual AbpModuleDescriptor CreateModuleDescriptor(Type moduleType) + { + return new AbpModuleDescriptor(moduleType, (IAbpModule)Activator.CreateInstance(moduleType)); + } + + protected virtual void ConfigureServices(IServiceCollection services) + { + foreach (var module in _modules) + { + module.Instance.ConfigureServices(services); + } + } + + protected virtual void AddModuleAndDependenciesResursively(List moduleTypes, Type moduleType) + { + CheckAbpModuleType(moduleType); + + if (moduleTypes.Contains(moduleType)) + { + return; + } + + moduleTypes.Add(moduleType); + + foreach (var dependedModuleType in FindDependedModuleTypes(moduleType)) + { + AddModuleAndDependenciesResursively(moduleTypes, dependedModuleType); + } + } + + + protected virtual List FindDependedModuleTypes(Type moduleType) + { + CheckAbpModuleType(moduleType); + + var dependencies = new List(); + + var dependencyDescriptors = moduleType + .GetTypeInfo() + .GetCustomAttributes() + .OfType(); + + foreach (var descriptor in dependencyDescriptors) + { + foreach (var dependedModuleType in descriptor.GetDependedModuleTypes()) + { + dependencies.AddIfNotContains(dependedModuleType); + } + } + + return dependencies; + } + + protected virtual void SetModuleDependencies(AbpModuleDescriptor module) + { + foreach (var dependedModuleType in FindDependedModuleTypes(module.Type)) + { + var dependedModule = _modules.FirstOrDefault(m => m.Type == dependedModuleType); + if (dependedModule == null) + { + throw new AbpException("Could not find a depended module " + dependedModuleType.AssemblyQualifiedName + " for " + module.Type.AssemblyQualifiedName); + } + + module.Dependencies.AddIfNotContains(dependedModule); + } + } + + protected static void CheckAbpModuleType(Type moduleType) + { + if (!IsAbpModule(moduleType)) + { + throw new ArgumentException("Given type is not an ABP module: " + moduleType.AssemblyQualifiedName); + } + } + + protected static bool IsAbpModule(Type type) + { + var typeInfo = type.GetTypeInfo(); + + return + typeInfo.IsClass && + !typeInfo.IsAbstract && + !typeInfo.IsGenericType && + typeof(IAbpModule).GetTypeInfo().IsAssignableFrom(type); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Abp/Modularity/ModuleManager.cs b/src/Volo.Abp/Abp/Modularity/ModuleManager.cs new file mode 100644 index 0000000000..e223590b81 --- /dev/null +++ b/src/Volo.Abp/Abp/Modularity/ModuleManager.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Modularity +{ + public class ModuleManager : IModuleManager + { + private readonly IModuleLoader _moduleLoader; + private readonly IEnumerable _initializers; + + public ModuleManager(IModuleLoader moduleLoader, IEnumerable initializers) + { + _moduleLoader = moduleLoader; + _initializers = initializers; + } + + public void Initialize() + { + foreach (var initializer in _initializers) + { + foreach (var module in _moduleLoader.Modules) + { + initializer.Initialize(module.Instance); + } + } + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp/Modularity/IModuleRunner.cs b/src/Volo.Abp/Modularity/IModuleRunner.cs deleted file mode 100644 index 0bbaef6583..0000000000 --- a/src/Volo.Abp/Modularity/IModuleRunner.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Volo.Abp.Modularity -{ - public interface IModuleRunner - { - void Start(); - - void Stop(); - } -} diff --git a/src/Volo.Abp/Modularity/ModuleRunner.cs b/src/Volo.Abp/Modularity/ModuleRunner.cs deleted file mode 100644 index 20305b7dc5..0000000000 --- a/src/Volo.Abp/Modularity/ModuleRunner.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Volo.Abp.Modularity -{ - public class ModuleRunner : IModuleRunner - { - public void Start() - { - - } - - public void Stop() - { - - } - } -} \ No newline at end of file diff --git a/src/Volo.Abp/Volo.Abp.xproj b/src/Volo.Abp/Volo.Abp.xproj index 3af070bb13..e23a5c913e 100644 --- a/src/Volo.Abp/Volo.Abp.xproj +++ b/src/Volo.Abp/Volo.Abp.xproj @@ -4,18 +4,16 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - fc5f7372-ea60-4052-b943-0ee070221cc1 - Volo.Abp + Volo .\obj .\bin\ v4.6.1 - 2.0 - + \ No newline at end of file diff --git a/src/Volo.Abp/project.json b/src/Volo.Abp/project.json index 82eab9070c..b1e94f0b63 100644 --- a/src/Volo.Abp/project.json +++ b/src/Volo.Abp/project.json @@ -3,7 +3,9 @@ "dependencies": { "NETStandard.Library": "1.6.1", - "Volo.DependencyInjection": "1.0.0-*" + "Volo.DependencyInjection": "1.0.0-*", + "System.Collections.Immutable": "1.3.0", + "Volo.ExtensionMethods": "1.0.0-*" }, "frameworks": { diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/CanBeNullAttribute.cs b/src/Volo.CodeAnnotations/CodeAnnotations/CanBeNullAttribute.cs new file mode 100644 index 0000000000..ab06a172a9 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/CanBeNullAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace JetBrains.Annotations +{ + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field)] + public sealed class CanBeNullAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/Check.cs b/src/Volo.CodeAnnotations/CodeAnnotations/Check.cs new file mode 100644 index 0000000000..ac110bfbb6 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/Check.cs @@ -0,0 +1,20 @@ +using System; +using System.Diagnostics; + +namespace JetBrains.Annotations +{ + [DebuggerStepThrough] + public static class Check + { + [ContractAnnotation("value:null => halt")] + public static T NotNull(T value, [InvokerParameterName] [NotNull] string parameterName) + { + if (value == null) + { + throw new ArgumentNullException(parameterName); + } + + return value; + } + } +} diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/ContractAnnotationAttribute.cs b/src/Volo.CodeAnnotations/CodeAnnotations/ContractAnnotationAttribute.cs new file mode 100644 index 0000000000..b79e23e6e2 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/ContractAnnotationAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace JetBrains.Annotations +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public sealed class ContractAnnotationAttribute : Attribute + { + public string Contract { get; private set; } + + public bool ForceFullStates { get; private set; } + + public ContractAnnotationAttribute([NotNull] string contract) + : this(contract, false) + { + } + + public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) + { + Contract = contract; + ForceFullStates = forceFullStates; + } + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/ImplicitUseKindFlags.cs b/src/Volo.CodeAnnotations/CodeAnnotations/ImplicitUseKindFlags.cs new file mode 100644 index 0000000000..d8d51e73f0 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/ImplicitUseKindFlags.cs @@ -0,0 +1,14 @@ +using System; + +namespace JetBrains.Annotations +{ + [Flags] + public enum ImplicitUseKindFlags + { + Default = Access | Assign | InstantiatedWithFixedConstructorSignature, + Access = 1, + Assign = 2, + InstantiatedWithFixedConstructorSignature = 4, + InstantiatedNoFixedConstructorSignature = 8 + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/ImplicitUseTargetFlags.cs b/src/Volo.CodeAnnotations/CodeAnnotations/ImplicitUseTargetFlags.cs new file mode 100644 index 0000000000..7771131c04 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/ImplicitUseTargetFlags.cs @@ -0,0 +1,13 @@ +using System; + +namespace JetBrains.Annotations +{ + [Flags] + public enum ImplicitUseTargetFlags + { + Default = Itself, + Itself = 1, + Members = 2, + WithMembers = Itself | Members + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/InvokerParameterNameAttribute.cs b/src/Volo.CodeAnnotations/CodeAnnotations/InvokerParameterNameAttribute.cs new file mode 100644 index 0000000000..028bd4fe45 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/InvokerParameterNameAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace JetBrains.Annotations +{ + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class InvokerParameterNameAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/NoEnumerationAttribute.cs b/src/Volo.CodeAnnotations/CodeAnnotations/NoEnumerationAttribute.cs new file mode 100644 index 0000000000..260c062581 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/NoEnumerationAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace JetBrains.Annotations +{ + [AttributeUsage(AttributeTargets.Parameter)] + internal sealed class NoEnumerationAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/NotNullAttribute.cs b/src/Volo.CodeAnnotations/CodeAnnotations/NotNullAttribute.cs new file mode 100644 index 0000000000..493e4cb0cf --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/NotNullAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace JetBrains.Annotations +{ + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field)] + public sealed class NotNullAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/StringFormatMethodAttribute.cs b/src/Volo.CodeAnnotations/CodeAnnotations/StringFormatMethodAttribute.cs new file mode 100644 index 0000000000..33821b14c8 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/StringFormatMethodAttribute.cs @@ -0,0 +1,16 @@ +using System; + +namespace JetBrains.Annotations +{ + [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Delegate)] + public sealed class StringFormatMethodAttribute : Attribute + { + public StringFormatMethodAttribute([NotNull] string formatParameterName) + { + FormatParameterName = formatParameterName; + } + + [NotNull] + public string FormatParameterName { get; private set; } + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/CodeAnnotations/UsedImplicitlyAttribute.cs b/src/Volo.CodeAnnotations/CodeAnnotations/UsedImplicitlyAttribute.cs new file mode 100644 index 0000000000..e230c9e336 --- /dev/null +++ b/src/Volo.CodeAnnotations/CodeAnnotations/UsedImplicitlyAttribute.cs @@ -0,0 +1,34 @@ +using System; + +namespace JetBrains.Annotations +{ + [AttributeUsage(AttributeTargets.All)] + public sealed class UsedImplicitlyAttribute : Attribute + { + public UsedImplicitlyAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) + { + } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) + { + } + + public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) + { + } + + public UsedImplicitlyAttribute( + ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + UseKindFlags = useKindFlags; + TargetFlags = targetFlags; + } + + public ImplicitUseKindFlags UseKindFlags { get; private set; } + + public ImplicitUseTargetFlags TargetFlags { get; private set; } + } +} \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/Properties/AssemblyInfo.cs b/src/Volo.CodeAnnotations/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..cfe4ccc1de --- /dev/null +++ b/src/Volo.CodeAnnotations/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Volo.CodeAnnotations")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("161a6c10-00ff-4348-993f-d19893abc57c")] diff --git a/src/Volo.CodeAnnotations/Volo.CodeAnnotations.xproj b/src/Volo.CodeAnnotations/Volo.CodeAnnotations.xproj new file mode 100644 index 0000000000..63ed8954e0 --- /dev/null +++ b/src/Volo.CodeAnnotations/Volo.CodeAnnotations.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 161a6c10-00ff-4348-993f-d19893abc57c + Volo + .\obj + .\bin\ + v4.6.1 + + + 2.0 + + + \ No newline at end of file diff --git a/src/Volo.CodeAnnotations/project.json b/src/Volo.CodeAnnotations/project.json new file mode 100644 index 0000000000..8930967524 --- /dev/null +++ b/src/Volo.CodeAnnotations/project.json @@ -0,0 +1,13 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "NETStandard.Library": "1.6.1" + }, + + "frameworks": { + "netstandard1.6": { + "imports": "dnxcore50" + } + } +} diff --git a/src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs b/src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs index e8ad85e02f..02034d2e8c 100644 --- a/src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs +++ b/src/Volo.DependencyInjection/DependencyInjection/AbpConventionalDependencyInjectionExtensions.cs @@ -9,6 +9,13 @@ namespace Volo.DependencyInjection { public static class AbpConventionalDependencyInjectionExtensions { + //TODO: Check if assembly/type is added before or add TryAdd versions of them? + + public static void AddAssemblyOf(this IServiceCollection services) + { + services.AddAssembly(typeof(T).GetTypeInfo().Assembly); + } + public static void AddAssembly(this IServiceCollection services, Assembly assembly) { services.AddTypes(AssemblyHelper.GetAllTypes(assembly).FilterInjectableTypes().ToArray()); diff --git a/src/Volo.ExtensionMethods/Collections/Generic/CollectionExtensions.cs b/src/Volo.ExtensionMethods/Collections/Generic/CollectionExtensions.cs new file mode 100644 index 0000000000..715ec70903 --- /dev/null +++ b/src/Volo.ExtensionMethods/Collections/Generic/CollectionExtensions.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Collections.Generic +{ + /// + /// Extension methods for Collections. + /// + public static class CollectionExtensions + { + /// + /// Checks whatever given collection object is null or has no item. + /// + public static bool IsNullOrEmpty([CanBeNull] this ICollection source) + { + return source == null || source.Count <= 0; + } + + /// + /// Adds an item to the collection if it's not already in the collection. + /// + /// Collection + /// Item to check and add + /// Type of the items in the collection + /// Returns True if added, returns False if not. + public static bool AddIfNotContains([NotNull] this ICollection source, T item) + { + Check.NotNull(source, nameof(source)); + + if (source.Contains(item)) + { + return false; + } + + source.Add(item); + return true; + } + } +} \ No newline at end of file diff --git a/src/Volo.ExtensionMethods/Collections/Generic/DictionaryExtensions.cs b/src/Volo.ExtensionMethods/Collections/Generic/DictionaryExtensions.cs new file mode 100644 index 0000000000..ff51c3ef50 --- /dev/null +++ b/src/Volo.ExtensionMethods/Collections/Generic/DictionaryExtensions.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Collections.Generic +{ + /// + /// Extension methods for Dictionary. + /// + public static class DictionaryExtensions + { + /// + /// This method is used to try to get a value in a dictionary if it does exists. + /// + /// Type of the value + /// The collection object + /// Key + /// Value of the key (or default value if key not exists) + /// True if key does exists in the dictionary + internal static bool TryGetValue(this IDictionary dictionary, string key, out T value) + { + object valueObj; + if (dictionary.TryGetValue(key, out valueObj) && valueObj is T) + { + value = (T)valueObj; + return true; + } + + value = default(T); + return false; + } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue GetOrDefault(this IDictionary dictionary, TKey key) + { + TValue obj; + return dictionary.TryGetValue(key, out obj) ? obj : default(TValue); + } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// A factory method used to create the value if not found in the dictionary + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue GetOrAdd(this IDictionary dictionary, TKey key, Func factory) + { + TValue obj; + if (dictionary.TryGetValue(key, out obj)) + { + return obj; + } + + return dictionary[key] = factory(key); + } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// A factory method used to create the value if not found in the dictionary + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue GetOrAdd(this IDictionary dictionary, TKey key, Func factory) + { + return dictionary.GetOrAdd(key, k => factory()); + } + } +} \ No newline at end of file diff --git a/src/Volo.ExtensionMethods/Collections/Generic/EnumerableExtensions.cs b/src/Volo.ExtensionMethods/Collections/Generic/EnumerableExtensions.cs new file mode 100644 index 0000000000..bfbc9fa9d6 --- /dev/null +++ b/src/Volo.ExtensionMethods/Collections/Generic/EnumerableExtensions.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Collections.Generic +{ + /// + /// Extension methods for . + /// + public static class EnumerableExtensions + { + /// + /// Concatenates the members of a constructed collection of type System.String, using the specified separator between each member. + /// This is a shortcut for string.Join(...) + /// + /// A collection that contains the strings to concatenate. + /// The string to use as a separator. separator is included in the returned string only if values has more than one element. + /// A string that consists of the members of values delimited by the separator string. If values has no members, the method returns System.String.Empty. + public static string JoinAsString(this IEnumerable source, string separator) + { + return string.Join(separator, source); + } + + /// + /// Concatenates the members of a collection, using the specified separator between each member. + /// This is a shortcut for string.Join(...) + /// + /// A collection that contains the objects to concatenate. + /// The string to use as a separator. separator is included in the returned string only if values has more than one element. + /// The type of the members of values. + /// A string that consists of the members of values delimited by the separator string. If values has no members, the method returns System.String.Empty. + public static string JoinAsString(this IEnumerable source, string separator) + { + return string.Join(separator, source); + } + + /// + /// Filters a by given predicate if given condition is true. + /// + /// Enumerable to apply filtering + /// A boolean value + /// Predicate to filter the enumerable + /// Filtered or not filtered enumerable based on + public static IEnumerable WhereIf(this IEnumerable source, bool condition, Func predicate) + { + return condition + ? source.Where(predicate) + : source; + } + + /// + /// Filters a by given predicate if given condition is true. + /// + /// Enumerable to apply filtering + /// A boolean value + /// Predicate to filter the enumerable + /// Filtered or not filtered enumerable based on + public static IEnumerable WhereIf(this IEnumerable source, bool condition, Func predicate) + { + return condition + ? source.Where(predicate) + : source; + } + } +} diff --git a/src/Volo.ExtensionMethods/Collections/Generic/ListExtensions.cs b/src/Volo.ExtensionMethods/Collections/Generic/ListExtensions.cs new file mode 100644 index 0000000000..847b92d092 --- /dev/null +++ b/src/Volo.ExtensionMethods/Collections/Generic/ListExtensions.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Collections.Generic +{ + /// + /// Extension methods for . + /// + public static class ListExtensions + { + /// + /// Sort a list by a topological sorting, which consider their dependencies + /// + /// The type of the members of values. + /// A list of objects to sort + /// Function to resolve the dependencies + /// + public static List SortByDependencies(this IEnumerable source, Func> getDependencies) + { + /* See: http://www.codeproject.com/Articles/869059/Topological-sorting-in-Csharp + * http://en.wikipedia.org/wiki/Topological_sorting + */ + + var sorted = new List(); + var visited = new Dictionary(); + + foreach (var item in source) + { + SortByDependenciesVisit(item, getDependencies, sorted, visited); + } + + return sorted; + } + + /// + /// + /// + /// The type of the members of values. + /// Item to resolve + /// Function to resolve the dependencies + /// List with the sortet items + /// Dictionary with the visited items + private static void SortByDependenciesVisit(T item, Func> getDependencies, List sorted, Dictionary visited) + { + bool inProcess; + var alreadyVisited = visited.TryGetValue(item, out inProcess); + + if (alreadyVisited) + { + if (inProcess) + { + throw new ArgumentException("Cyclic dependency found! Item: " + item); + } + } + else + { + visited[item] = true; + + var dependencies = getDependencies(item); + if (dependencies != null) + { + foreach (var dependency in dependencies) + { + SortByDependenciesVisit(dependency, getDependencies, sorted, visited); + } + } + + visited[item] = false; + sorted.Add(item); + } + } + } +} diff --git a/src/Volo.ExtensionMethods/Properties/AssemblyInfo.cs b/src/Volo.ExtensionMethods/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..3f4164a707 --- /dev/null +++ b/src/Volo.ExtensionMethods/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Volo.ExtensionMethods")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fc889503-0bf4-4959-ac80-f51073787025")] diff --git a/src/Volo.ExtensionMethods/Volo.ExtensionMethods.xproj b/src/Volo.ExtensionMethods/Volo.ExtensionMethods.xproj new file mode 100644 index 0000000000..a30b12f5b1 --- /dev/null +++ b/src/Volo.ExtensionMethods/Volo.ExtensionMethods.xproj @@ -0,0 +1,19 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + fc889503-0bf4-4959-ac80-f51073787025 + Volo + .\obj + .\bin\ + v4.6.1 + + + 2.0 + + + \ No newline at end of file diff --git a/src/Volo.ExtensionMethods/project.json b/src/Volo.ExtensionMethods/project.json new file mode 100644 index 0000000000..99044409f9 --- /dev/null +++ b/src/Volo.ExtensionMethods/project.json @@ -0,0 +1,14 @@ +{ + "version": "1.0.0-*", + + "dependencies": { + "NETStandard.Library": "1.6.1", + "Volo.CodeAnnotations": "1.0.0-*" + }, + + "frameworks": { + "netstandard1.6": { + "imports": "dnxcore50" + } + } +} diff --git a/test/Apps/AspNetCoreDemo/AppModule.cs b/test/Apps/AspNetCoreDemo/AppModule.cs new file mode 100644 index 0000000000..9abe5f3c2a --- /dev/null +++ b/test/Apps/AspNetCoreDemo/AppModule.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Volo.Abp.AspNetCore; +using Volo.Abp.AspNetCore.Builder; +using Volo.Abp.Modularity; + +namespace AspNetCoreDemo +{ + [DependsOn(typeof(AbpAspNetCoreModule))] + public class AppModule : IAbpModule, IConfigureAspNet + { + public void ConfigureServices(IServiceCollection services) + { + + } + + public void Configure(AspNetConfigurationContext context) + { + context.LoggerFactory.AddConsole(); + + if (context.Environment.IsDevelopment()) + { + context.App.UseDeveloperExceptionPage(); + } + + context.App.Run(async (ctx) => + { + await ctx.Response.WriteAsync("Hello World 3!"); + }); + } + } +} diff --git a/test/Apps/AspNetCoreDemo/AspNetCoreDemo.xproj b/test/Apps/AspNetCoreDemo/AspNetCoreDemo.xproj new file mode 100644 index 0000000000..c240f13525 --- /dev/null +++ b/test/Apps/AspNetCoreDemo/AspNetCoreDemo.xproj @@ -0,0 +1,25 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 12e14d95-4aba-4290-ab1d-ccf5eb158411 + AspNetCoreDemo + .\obj + .\bin\ + v4.6.1 + + + + 2.0 + + + + + + + diff --git a/test/Apps/AspNetCoreDemo/Program.cs b/test/Apps/AspNetCoreDemo/Program.cs new file mode 100644 index 0000000000..ab54746192 --- /dev/null +++ b/test/Apps/AspNetCoreDemo/Program.cs @@ -0,0 +1,20 @@ +using System.IO; +using Microsoft.AspNetCore.Hosting; + +namespace AspNetCoreDemo +{ + public class Program + { + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/test/Apps/AspNetCoreDemo/Properties/launchSettings.json b/test/Apps/AspNetCoreDemo/Properties/launchSettings.json new file mode 100644 index 0000000000..6f0054095c --- /dev/null +++ b/test/Apps/AspNetCoreDemo/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:59980/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "AspNetCoreDemo": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/test/Apps/AspNetCoreDemo/Startup.cs b/test/Apps/AspNetCoreDemo/Startup.cs new file mode 100644 index 0000000000..a9724493d3 --- /dev/null +++ b/test/Apps/AspNetCoreDemo/Startup.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace AspNetCoreDemo +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddAbpApplication(); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + { + app.InitializeAbpApplication(); + } + } +} diff --git a/test/Apps/AspNetCoreDemo/project.json b/test/Apps/AspNetCoreDemo/project.json new file mode 100644 index 0000000000..4738de3af5 --- /dev/null +++ b/test/Apps/AspNetCoreDemo/project.json @@ -0,0 +1,48 @@ +{ + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.1", + "type": "platform" + }, + "Microsoft.AspNetCore.Diagnostics": "1.1.0", + "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0", + "Microsoft.Extensions.Logging.Console": "1.1.0", + "Volo.Abp.AspNetCore": "1.0.0-*" + }, + + "tools": { + "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.1.0-preview4-final" + }, + + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.6", + "portable-net45+win8" + ] + } + }, + + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + + "runtimeOptions": { + "configProperties": { + "System.GC.Server": true + } + }, + + "publishOptions": { + "include": [ + "wwwroot", + "web.config" + ] + }, + + "scripts": { + "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ] + } +} diff --git a/test/Apps/AspNetCoreDemo/web.config b/test/Apps/AspNetCoreDemo/web.config new file mode 100644 index 0000000000..dc0514fca5 --- /dev/null +++ b/test/Apps/AspNetCoreDemo/web.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/test/Volo.Abp.AspNetCore.Tests/Properties/AssemblyInfo.cs b/test/Volo.Abp.AspNetCore.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..52795eeeb0 --- /dev/null +++ b/test/Volo.Abp.AspNetCore.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Volo.Abp.AspNetCore.Tests")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b1d860bb-6ec6-4bae-adaa-c2aec2ffb510")] diff --git a/test/Volo.Abp.AspNetCore.Tests/Volo.Abp.AspNetCore.Tests.xproj b/test/Volo.Abp.AspNetCore.Tests/Volo.Abp.AspNetCore.Tests.xproj new file mode 100644 index 0000000000..5fec7c1689 --- /dev/null +++ b/test/Volo.Abp.AspNetCore.Tests/Volo.Abp.AspNetCore.Tests.xproj @@ -0,0 +1,21 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + b1d860bb-6ec6-4bae-adaa-c2aec2ffb510 + Volo.Abp.AspNetCore.Tests + .\obj + .\bin\ + v4.6.1 + + + + 2.0 + + + diff --git a/test/Volo.Abp.AspNetCore.Tests/project.json b/test/Volo.Abp.AspNetCore.Tests/project.json new file mode 100644 index 0000000000..31438a6cfb --- /dev/null +++ b/test/Volo.Abp.AspNetCore.Tests/project.json @@ -0,0 +1,21 @@ +{ + "version": "1.0.0-*", + + "testRunner": "xunit", + + "dependencies": { + "AbpTestBase": "1.0.0-*", + "Volo.Abp.AspNetCore": "1.0.0-*" + }, + + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0" + } + } + } + } +} diff --git a/test/Volo.Abp.Tests/AbpApplication_Tests.cs b/test/Volo.Abp.Tests/AbpApplication_Tests.cs index 5969edeac4..d18b74084b 100644 --- a/test/Volo.Abp.Tests/AbpApplication_Tests.cs +++ b/test/Volo.Abp.Tests/AbpApplication_Tests.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Tests.Modularity; -using Volo.DependencyInjection.Tests; using Xunit; namespace Volo.Abp.Tests @@ -14,18 +13,7 @@ namespace Volo.Abp.Tests using (var application = AbpApplication.Create(services)) { - application.Start(services.BuildServiceProvider()); - } - } - - [Fact] - public void Should_Automatically_Register_Modules() - { - var services = new ServiceCollection(); - - using (AbpApplication.Create(services)) - { - services.ShouldContainSingleton(typeof(IndependentEmptyModule)); + application.Initialize(services.BuildServiceProvider()); } } } diff --git a/test/Volo.DependencyInjection.Tests/ServiceCollectionShouldlyExtensions.cs b/test/Volo.DependencyInjection.Tests/ServiceCollectionShouldlyExtensions.cs index 0022cd8de2..5a5f7bda93 100644 --- a/test/Volo.DependencyInjection.Tests/ServiceCollectionShouldlyExtensions.cs +++ b/test/Volo.DependencyInjection.Tests/ServiceCollectionShouldlyExtensions.cs @@ -11,6 +11,7 @@ namespace Volo.DependencyInjection.Tests { var serviceDescriptor = services.FirstOrDefault(s => s.ServiceType == type); + serviceDescriptor.ShouldNotBeNull(); serviceDescriptor.ImplementationType.ShouldBe(type); serviceDescriptor.ShouldNotBeNull(); serviceDescriptor.ImplementationFactory.ShouldBeNull(); @@ -22,6 +23,7 @@ namespace Volo.DependencyInjection.Tests { var serviceDescriptor = services.FirstOrDefault(s => s.ServiceType == type); + serviceDescriptor.ShouldNotBeNull(); serviceDescriptor.ImplementationType.ShouldBe(type); serviceDescriptor.ShouldNotBeNull(); serviceDescriptor.ImplementationFactory.ShouldBeNull();