From 1df5821fb62cf384464fe5e45c0d8606668692b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 4 Oct 2017 15:52:50 +0300 Subject: [PATCH] API Versioning improvements. --- .../AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs | 17 ++++++++++++ .../Mvc/AbpControllerAssemblySetting.cs | 3 +-- .../AbpApiDefinitionController.cs | 5 ++-- .../AspNetCoreApiDescriptionModelProvider.cs | 15 +++++------ .../DynamicProxying/ApiDescriptionCache.cs | 2 +- .../Modeling/ActionApiDescriptionModel.cs | 2 +- .../Modeling/ApiDescriptionModelOptions.cs | 26 +++++++++++++++++++ .../Modeling/ControllerApiDescriptionModel.cs | 4 ++- .../Modeling/ModuleApiDescriptionModel.cs | 5 ++-- .../AbpIdentityHttpApiHostModule.cs | 11 +------- .../Controllers/HomeController.cs | 1 - 11 files changed, 62 insertions(+), 29 deletions(-) create mode 100644 src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApiDescriptionModelOptions.cs 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 072e523877..088936b69d 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 @@ -12,10 +12,12 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.ViewComponents; using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Http; +using Volo.Abp.Http.Modeling; namespace Volo.Abp.AspNetCore.Mvc { @@ -41,6 +43,21 @@ namespace Volo.Abp.AspNetCore.Mvc ) ) ); + + services.Configure(options => + { + options.IgnoredInterfaces.AddIfNotContains(typeof(IAsyncActionFilter)); + options.IgnoredInterfaces.AddIfNotContains(typeof(IFilterMetadata)); + options.IgnoredInterfaces.AddIfNotContains(typeof(IActionFilter)); + }); + + services.Configure(options => + { + options.AppServiceControllers.Create(typeof(AbpAspNetCoreMvcModule).Assembly, o => + { + o.RootPath = "abp"; + }); + }); } public override void PostConfigureServices(IServiceCollection services) diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs index ffe510eaaa..be40f2d95f 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySetting.cs @@ -46,8 +46,7 @@ namespace Volo.Abp.AspNetCore.Mvc public List ApiVersions { get; set; } public Action ApiVersionConfigurer { get; set; } - - + public AbpControllerAssemblySetting([NotNull] Assembly assembly, [NotNull] string rootPath) { Check.NotNull(assembly, rootPath); diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController.cs index 493eaef389..19db653dc8 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApiExploring/AbpApiDefinitionController.cs @@ -1,10 +1,11 @@ using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Application.Services; using Volo.Abp.Http.Modeling; namespace Volo.Abp.AspNetCore.Mvc.ApiExploring { - [Route("api/abp/api-description")] - public class AbpApiDefinitionController : AbpController + [Route("api/abp/api-definition")] + public class AbpApiDefinitionController : AbpController, IRemoteService { private readonly IApiDescriptionModelProvider _modelProvider; diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs index 3a2fdba255..f9802f2103 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AspNetCoreApiDescriptionModelProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; @@ -9,7 +10,6 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; -using Volo.Abp.Application.Services; using Volo.Abp.AspNetCore.Mvc.Utils; using Volo.Abp.DependencyInjection; using Volo.Abp.Http.Modeling; @@ -22,13 +22,16 @@ namespace Volo.Abp.AspNetCore.Mvc private readonly IApiDescriptionGroupCollectionProvider _descriptionProvider; private readonly AbpAspNetCoreMvcOptions _options; + private readonly ApiDescriptionModelOptions _modelOptions; public AspNetCoreApiDescriptionModelProvider( IApiDescriptionGroupCollectionProvider descriptionProvider, - IOptions options) + IOptions options, + IOptions modelOptions) { _descriptionProvider = descriptionProvider; _options = options.Value; + _modelOptions = modelOptions.Value; Logger = NullLogger.Instance; } @@ -59,7 +62,7 @@ namespace Volo.Abp.AspNetCore.Mvc var moduleModel = model.GetOrAddModule(GetRootPath(controllerType)); - var controllerModel = moduleModel.GetOrAddController(GetControllerName(apiDescription), controllerType); + var controllerModel = moduleModel.GetOrAddController(controllerType.FullName, controllerType, _modelOptions.IgnoredInterfaces); var method = apiDescription.ActionDescriptor.GetMethodInfo(); @@ -80,12 +83,6 @@ namespace Volo.Abp.AspNetCore.Mvc AddParameterDescriptionsToModel(actionModel, method, apiDescription); } - private static string GetControllerName(ApiDescription apiDescription) - { - return apiDescription.GroupName?.RemovePostFix(ApplicationService.CommonPostfixes) - ?? apiDescription.ActionDescriptor.AsControllerActionDescriptor().ControllerName; - } - private static string GetUniqueActionName(MethodInfo method) { var methodNameBuilder = new StringBuilder(method.Name); diff --git a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs index 4fc370a2e2..4476ef90cd 100644 --- a/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs +++ b/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/ApiDescriptionCache.cs @@ -42,7 +42,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying { using (var client = _httpClientFactory.Create()) { - var response = await client.GetAsync(baseUrl + "api/abp/api-description"); + var response = await client.GetAsync(baseUrl + "api/abp/api-definition"); if (!response.IsSuccessStatusCode) { throw new AbpException("Remote service returns error!"); diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs index fe91a3ddf2..75c22621c3 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ActionApiDescriptionModel.cs @@ -28,7 +28,7 @@ namespace Volo.Abp.Http.Modeling } - public static ActionApiDescriptionModel Create(MethodInfo method, string uniqueName, string url, string httpMethod = null) + public static ActionApiDescriptionModel Create(MethodInfo method, string uniqueName, string url, string httpMethod) { return new ActionApiDescriptionModel { diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApiDescriptionModelOptions.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApiDescriptionModelOptions.cs new file mode 100644 index 0000000000..18b335b115 --- /dev/null +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ApiDescriptionModelOptions.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Application.Services; +using Volo.Abp.Aspects; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Http.Modeling +{ + public class ApiDescriptionModelOptions + { + public HashSet IgnoredInterfaces { get; } + + public ApiDescriptionModelOptions() + { + IgnoredInterfaces = new HashSet + { + typeof(IApplicationService), + typeof(IRemoteService), + typeof(ITransientDependency), + typeof(ISingletonDependency), + typeof(IDisposable), + typeof(IAvoidDuplicateCrossCuttingConcerns) + }; + } + } +} diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs index 51f03661f4..ca9dbb9415 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ControllerApiDescriptionModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; namespace Volo.Abp.Http.Modeling { @@ -20,7 +21,7 @@ namespace Volo.Abp.Http.Modeling } - public static ControllerApiDescriptionModel Create(string controllerName, Type type) + public static ControllerApiDescriptionModel Create(string controllerName, Type type, [CanBeNull] HashSet ignoredInterfaces = null) { return new ControllerApiDescriptionModel { @@ -29,6 +30,7 @@ namespace Volo.Abp.Http.Modeling Actions = new Dictionary(), Interfaces = type .GetInterfaces() + .WhereIf(ignoredInterfaces != null, i => !i.IsGenericType && !ignoredInterfaces.Contains(i)) .Select(ControllerInterfaceApiDescriptionModel.Create) .ToList() }; diff --git a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs index 5f776d5e4a..e776818508 100644 --- a/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs +++ b/src/Volo.Abp.Http/Volo/Abp/Http/Modeling/ModuleApiDescriptionModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; namespace Volo.Abp.Http.Modeling { @@ -40,9 +41,9 @@ namespace Volo.Abp.Http.Modeling return Controllers[controller.ControllerName] = controller; } - public ControllerApiDescriptionModel GetOrAddController(string name, Type type) + public ControllerApiDescriptionModel GetOrAddController(string name, Type type, [CanBeNull] HashSet ignoredInterfaces = null) { - return Controllers.GetOrAdd(name, () => ControllerApiDescriptionModel.Create(name, type)); + return Controllers.GetOrAdd(name, () => ControllerApiDescriptionModel.Create(name, type, ignoredInterfaces)); } public ModuleApiDescriptionModel CreateSubModel(string[] controllers, string[] actions) diff --git a/src/Volo.Abp.Identity.HttpApi.Host/AbpIdentityHttpApiHostModule.cs b/src/Volo.Abp.Identity.HttpApi.Host/AbpIdentityHttpApiHostModule.cs index c171b4fa93..503cd2189f 100644 --- a/src/Volo.Abp.Identity.HttpApi.Host/AbpIdentityHttpApiHostModule.cs +++ b/src/Volo.Abp.Identity.HttpApi.Host/AbpIdentityHttpApiHostModule.cs @@ -1,14 +1,7 @@ -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.AspNetCore.Mvc.ApplicationModels; -using Microsoft.AspNetCore.Mvc.RazorPages.Internal; -using Microsoft.AspNetCore.Mvc.Versioning; -using Microsoft.AspNetCore.Mvc.Versioning.Conventions; using Microsoft.EntityFrameworkCore; using Microsoft.Examples; using Microsoft.Extensions.Configuration; @@ -16,7 +9,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Swashbuckle.AspNetCore.Swagger; using Volo.Abp.AspNetCore.Modularity; -using Volo.Abp.AspNetCore.Mvc.ApiExploring; using Volo.Abp.Autofac; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; @@ -58,7 +50,6 @@ namespace Volo.Abp.Identity.HttpApi.Host services.AddApiVersioning(o => { o.ReportApiVersions = true; - o.Conventions.Controller().IsApiVersionNeutral(); //TODO: This should be inside the framework! //o.Conventions.Controller().Action((MethodInfo)null).MapToApiVersion(new ApiVersion(1,1),).IsApiVersionNeutral(); //o.Conventions.Controller().HasApiVersion(new ApiVersion(3, 0)); //We can do that based on controller's AbpApiVersion attribute! o.AssumeDefaultVersionWhenUnspecified = true; diff --git a/src/Volo.Abp.Identity.HttpApi.Host/Controllers/HomeController.cs b/src/Volo.Abp.Identity.HttpApi.Host/Controllers/HomeController.cs index 2a8c3aed0b..3b61831e3f 100644 --- a/src/Volo.Abp.Identity.HttpApi.Host/Controllers/HomeController.cs +++ b/src/Volo.Abp.Identity.HttpApi.Host/Controllers/HomeController.cs @@ -6,7 +6,6 @@ namespace Volo.Abp.Identity.HttpApi.Host.Controllers public class HomeController : AbpController { [HttpPost] - [Route("/api/v1/users/create")] public IActionResult Index() { return Redirect("/swagger");