From 38519a001acc0cfa4949ad8cc8f7ebc67bc3d45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 31 Aug 2017 14:22:30 +0300 Subject: [PATCH] Make "application services as controllers" working. --- .../AbpAppServiceControllerFeatureProvider.cs | 45 ++++++++++++++ .../AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs | 61 ++++++++++++++++++- .../AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs | 1 + ...pApplicationWithExternalServiceProvider.cs | 9 ++- ...pApplicationWithInternalServiceProvider.cs | 10 ++- .../Services/CrudAppServiceBase.cs | 1 + .../Volo.Abp.AspNetCore.Mvc.Tests.csproj | 1 + .../Volo/Abp/AspNetCore/App/AppModule.cs | 14 ++++- .../Volo/Abp/AspNetCore/App/Startup.cs | 1 - ...cyTestBase.cs => AspNetCoreMvcTestBase.cs} | 0 .../AspNetCore/Mvc/PersonAppService_Tests.cs | 18 ++++++ 11 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceControllerFeatureProvider.cs rename test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/{AspNetCoreMultiTenancyTestBase.cs => AspNetCoreMvcTestBase.cs} (100%) create mode 100644 test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceControllerFeatureProvider.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceControllerFeatureProvider.cs new file mode 100644 index 0000000000..1ef53867b6 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceControllerFeatureProvider.cs @@ -0,0 +1,45 @@ +using System; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Application.Services; +using Volo.Abp.Http; +using Volo.Abp.Reflection; + +namespace Volo.Abp.AspNetCore.Mvc +{ + /// + /// Used to add application services as controller. + /// + public class AbpAppServiceControllerFeatureProvider : ControllerFeatureProvider + { + private readonly IAbpApplication _application; + + public AbpAppServiceControllerFeatureProvider(IAbpApplication application) + { + _application = application; + } + + protected override bool IsController(TypeInfo typeInfo) + { + var type = typeInfo.AsType(); + + if (!typeof(IApplicationService).IsAssignableFrom(type) || + !typeInfo.IsPublic || typeInfo.IsAbstract || typeInfo.IsGenericType) + { + return false; + } + + var remoteServiceAttr = ReflectionHelper.GetSingleAttributeOrDefault(typeInfo); + + if (remoteServiceAttr != null && !remoteServiceAttr.IsEnabledFor(type)) + { + return false; + } + + var configuration = _application.ServiceProvider.GetRequiredService>().Value.ControllerAssemblySettings.GetSettingOrNull(type); + return configuration != null && configuration.TypePredicate(type); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs index 3f0ce600da..dd5c302b5d 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.Extensions.DependencyInjection; @@ -9,6 +11,10 @@ using Volo.Abp.AspNetCore.EmbeddedFiles; using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc.ViewComponents; +using Microsoft.Extensions.DependencyInjection.Extensions; namespace Volo.Abp.AspNetCore.Mvc { @@ -35,6 +41,26 @@ namespace Volo.Abp.AspNetCore.Mvc ) ) ); + } + + public override void PostConfigureServices(IServiceCollection services) + { + //TODO: Consider to use services.AddMvc() and move this to ConfigureServices method! + + services.TryAddSingleton(); + services.TryAddSingleton(); + + //Use DI to create controllers + services.Replace(ServiceDescriptor.Transient()); + + //Use DI to create view components + services.Replace(ServiceDescriptor.Singleton()); + + //Add feature providers + var partManager = services.GetSingletonInstance(); + var application = services.GetSingletonInstance(); + + partManager.FeatureProviders.Add(new AbpAppServiceControllerFeatureProvider(application)); services.Configure(mvcOptions => { @@ -55,11 +81,40 @@ namespace Volo.Abp.AspNetCore.Mvc return; } - var moduleContainer = context.ServiceProvider.GetRequiredService(); + //Plugin modules + var moduleAssemblies = context + .ServiceProvider + .GetRequiredService() + .Modules + .Where(m => m.IsLoadedAsPlugIn) + .Select(m => m.Type.Assembly) + .Distinct(); - foreach (var module in moduleContainer.Modules.Where(m => m.IsLoadedAsPlugIn)) + AddToApplicationParts(partManager, moduleAssemblies); + + //Controllers for application services + var controllerAssemblies = context + .ServiceProvider + .GetRequiredService>() + .Value + .ControllerAssemblySettings + .Select(s => s.Assembly) + .Distinct(); + + AddToApplicationParts(partManager, controllerAssemblies); + } + + private static void AddToApplicationParts(ApplicationPartManager partManager, IEnumerable moduleAssemblies) + { + foreach (var moduleAssembly in moduleAssemblies) { - partManager.ApplicationParts.Add(new AssemblyPart(module.Type.GetTypeInfo().Assembly)); + if (partManager.ApplicationParts.OfType().Any(p => p.Assembly == moduleAssembly)) + { + continue; + } + + + partManager.ApplicationParts.Add(new AssemblyPart(moduleAssembly)); } } } diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs index d302985911..0b962f8f13 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcOptions.cs @@ -13,6 +13,7 @@ namespace Volo.Abp.AspNetCore.Mvc public AbpAspNetCoreMvcOptions() { + ControllerAssemblySettings = new ControllerAssemblySettingList(); FormBodyBindingIgnoredTypes = new List { typeof(IFormFile) diff --git a/src/Volo.Abp/Volo/Abp/AbpApplicationWithExternalServiceProvider.cs b/src/Volo.Abp/Volo/Abp/AbpApplicationWithExternalServiceProvider.cs index a18e8a6848..6656baaa5b 100644 --- a/src/Volo.Abp/Volo/Abp/AbpApplicationWithExternalServiceProvider.cs +++ b/src/Volo.Abp/Volo/Abp/AbpApplicationWithExternalServiceProvider.cs @@ -25,9 +25,12 @@ namespace Volo.Abp ServiceProvider = serviceProvider; - ServiceProvider - .GetRequiredService() - .InitializeModules(new ApplicationInitializationContext(ServiceProvider)); + using (var scope = ServiceProvider.CreateScope()) + { + ServiceProvider + .GetRequiredService() + .InitializeModules(new ApplicationInitializationContext(scope.ServiceProvider)); + } } } } diff --git a/src/Volo.Abp/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs b/src/Volo.Abp/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs index c46c4a8373..82c1718dd7 100644 --- a/src/Volo.Abp/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs +++ b/src/Volo.Abp/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs @@ -36,9 +36,13 @@ namespace Volo.Abp { ServiceScope = Services.BuildServiceProviderFromFactory().CreateScope(); ServiceProvider = ServiceScope.ServiceProvider; - ServiceProvider - .GetRequiredService() - .InitializeModules(new ApplicationInitializationContext(ServiceProvider)); + + using (var scope = ServiceProvider.CreateScope()) + { + ServiceProvider + .GetRequiredService() + .InitializeModules(new ApplicationInitializationContext(scope.ServiceProvider)); + } } public override void Dispose() diff --git a/src/Volo.Abp/Volo/Abp/Application/Services/CrudAppServiceBase.cs b/src/Volo.Abp/Volo/Abp/Application/Services/CrudAppServiceBase.cs index 24f89410ba..a8c0671a69 100644 --- a/src/Volo.Abp/Volo/Abp/Application/Services/CrudAppServiceBase.cs +++ b/src/Volo.Abp/Volo/Abp/Application/Services/CrudAppServiceBase.cs @@ -4,6 +4,7 @@ using System.Linq.Dynamic.Core; using Volo.Abp.Application.Dtos; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Repositories; +using Volo.Abp.ObjectMapping; namespace Volo.Abp.Application.Services { diff --git a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj index 264a146eb0..8e0059cd4a 100644 --- a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj +++ b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo.Abp.AspNetCore.Mvc.Tests.csproj @@ -19,6 +19,7 @@ + diff --git a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/AppModule.cs b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/AppModule.cs index e249dae4b2..e712b05b18 100644 --- a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/AppModule.cs +++ b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/AppModule.cs @@ -1,19 +1,31 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Modularity; +using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.TestBase; +using Volo.Abp.Autofac; +using Volo.Abp.MemoryDb; using Volo.Abp.Modularity; +using Volo.Abp.TestApp; namespace Volo.Abp.AspNetCore.App { [DependsOn( - typeof(AbpAspNetCoreTestBaseModule) + typeof(AbpAspNetCoreTestBaseModule), + typeof(AbpMemoryDbTestModule), + typeof(AbpAspNetCoreMvcModule), + typeof(AbpAutofacModule) )] public class AppModule : AbpModule { public override void ConfigureServices(IServiceCollection services) { services.AddMvc(); + + services.Configure(options => + { + options.CreateControllersForAppServices(typeof(TestAppModule).Assembly); + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/Startup.cs b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/Startup.cs index 565b801b15..8e09c6ba0f 100644 --- a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/Startup.cs +++ b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/Startup.cs @@ -17,7 +17,6 @@ namespace Volo.Abp.AspNetCore.App //TODO: This is needed because ASP.NET Core does not use IServiceProviderFactory! return services.BuildServiceProviderFromFactory(); - //return services.BuildServiceProvider(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) diff --git a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AspNetCoreMultiTenancyTestBase.cs b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AspNetCoreMvcTestBase.cs similarity index 100% rename from test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AspNetCoreMultiTenancyTestBase.cs rename to test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AspNetCoreMvcTestBase.cs diff --git a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs new file mode 100644 index 0000000000..0d7d91999f --- /dev/null +++ b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PersonAppService_Tests.cs @@ -0,0 +1,18 @@ +using Shouldly; +using System.Threading.Tasks; +using Volo.Abp.Application.Dtos; +using Volo.Abp.TestApp.Application; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc +{ + public class PersonAppService_Tests : AspNetCoreMvcTestBase + { + [Fact] + public async Task GetAll_Test() + { + var result = await GetResponseAsObjectAsync>("/api/services/app/person/GetAll"); + result.Items.Count.ShouldBeGreaterThan(0); + } + } +}