diff --git a/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll b/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll index 8d7194d4e6..243e6fa82e 100644 Binary files a/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll and b/src/AbpDesk/Web_PlugIns/AbpDesk.MongoBlog.dll differ 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 index 4542879b20..376268eef9 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceControllerFeatureProvider.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceControllerFeatureProvider.cs @@ -35,7 +35,7 @@ namespace Volo.Abp.AspNetCore.Mvc //TODO: Move this to a lazy loaded field for efficiency. var configuration = _application.ServiceProvider.GetRequiredService>().Value.AppServiceControllers.ControllerAssemblySettings.GetSettingOrNull(type); - return configuration != null && configuration.TypePredicate(type); + return configuration != null && (configuration.TypePredicate == null || configuration.TypePredicate(type)); } } } \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs index 48baee0ff0..98a9daca43 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAppServiceConvention.cs @@ -40,7 +40,7 @@ namespace Volo.Abp.AspNetCore.Mvc if (IsRemoteService(controllerType)) { controller.ControllerName = controller.ControllerName.RemovePostFix(ApplicationService.CommonPostfixes); - configuration?.ControllerModelConfigurer(controller); + configuration?.ControllerModelConfigurer?.Invoke(controller); //ConfigureArea(controller, configuration); ConfigureRemoteService(controller, configuration); } @@ -192,7 +192,7 @@ namespace Volo.Abp.AspNetCore.Mvc } else { - NormalizeSelectorRoutes(rootPath, controllerName, action); + NormalizeSelectorRoutes(rootPath, controllerName, action, configuration); } } @@ -202,7 +202,7 @@ namespace Volo.Abp.AspNetCore.Mvc var abpServiceSelectorModel = new SelectorModel { - AttributeRouteModel = CreateAbpServiceAttributeRouteModel(rootPath, controllerName, action, httpMethod), + AttributeRouteModel = CreateAbpServiceAttributeRouteModel(rootPath, controllerName, action, httpMethod, configuration), ActionConstraints = { new HttpMethodActionConstraint(new[] { httpMethod }) } }; @@ -214,14 +214,14 @@ namespace Volo.Abp.AspNetCore.Mvc return HttpMethodHelper.GetConventionalVerbForMethodName(action.ActionName); } - protected virtual void NormalizeSelectorRoutes(string rootPath, string controllerName, ActionModel action) + protected virtual void NormalizeSelectorRoutes(string rootPath, string controllerName, ActionModel action, [CanBeNull] AbpControllerAssemblySetting configuration) { foreach (var selector in action.Selectors) { var httpMethod = selector.ActionConstraints.OfType().FirstOrDefault()?.HttpMethods?.FirstOrDefault(); if (selector.AttributeRouteModel == null) { - selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel(rootPath, controllerName, action, httpMethod); + selector.AttributeRouteModel = CreateAbpServiceAttributeRouteModel(rootPath, controllerName, action, httpMethod, configuration); } } } @@ -238,18 +238,20 @@ namespace Volo.Abp.AspNetCore.Mvc return _options.AppServiceControllers.ControllerAssemblySettings.GetSettingOrNull(controllerType); } - protected virtual AttributeRouteModel CreateAbpServiceAttributeRouteModel(string rootPath, string controllerName, ActionModel action, string httpMethod) + protected virtual AttributeRouteModel CreateAbpServiceAttributeRouteModel(string rootPath, string controllerName, ActionModel action, string httpMethod, [CanBeNull] AbpControllerAssemblySetting configuration) { return new AttributeRouteModel( new RouteAttribute( - CalculateRouteTemplate(rootPath, controllerName, action, httpMethod) + CalculateRouteTemplate(rootPath, controllerName, action, httpMethod, configuration) ) ); } - protected virtual string CalculateRouteTemplate(string rootPath, string controllerName, ActionModel action, string httpMethod) + protected virtual string CalculateRouteTemplate(string rootPath, string controllerName, ActionModel action, string httpMethod, [CanBeNull] AbpControllerAssemblySetting configuration) { - var url = $"api/{rootPath}/{controllerName.ToCamelCase()}"; + var controllerNameInUrl = NormalizeUrlControllerName(rootPath, controllerName, action, httpMethod, configuration); + + var url = $"api/{rootPath}/{controllerNameInUrl.ToCamelCase()}"; //Add {id} path if needed if (action.Parameters.Any(p => p.ParameterName == "id")) @@ -258,10 +260,10 @@ namespace Volo.Abp.AspNetCore.Mvc } //Add action name if needed - var actionNameInUrl = NormalizeUrlActionName(rootPath, controllerName, action, httpMethod); + var actionNameInUrl = NormalizeUrlActionName(rootPath, controllerName, action, httpMethod, configuration); if (!actionNameInUrl.IsNullOrEmpty()) { - url += $"/{actionNameInUrl}"; + url += $"/{actionNameInUrl.ToCamelCase()}"; //Add secondary Id var secondaryIds = action.Parameters.Where(p => p.ParameterName.EndsWith("Id", StringComparison.Ordinal)).ToList(); @@ -274,16 +276,43 @@ namespace Volo.Abp.AspNetCore.Mvc return url; } - protected virtual string NormalizeUrlActionName(string rootPath, string controllerName, ActionModel action, string httpMethod) + protected virtual string NormalizeUrlActionName(string rootPath, string controllerName, ActionModel action, string httpMethod, [CanBeNull] AbpControllerAssemblySetting configuration) { - var context = new UrlActionNameNormalizerContext(rootPath, controllerName, action, httpMethod, action.ActionName); + var actionNameInUrl = HttpMethodHelper + .RemoveHttpMethodPrefix(action.ActionName, httpMethod) + .RemovePostFix("Async"); - foreach (var normalizer in _options.AppServiceControllers.UrlActionNameNormalizers) + if (configuration?.UrlActionNameNormalizer == null) { - normalizer.Normalize(context); + return actionNameInUrl; } - return context.ActionNameInUrl; + return configuration.UrlActionNameNormalizer( + new UrlActionNameNormalizerContext( + rootPath, + controllerName, + action, + actionNameInUrl, + httpMethod + ) + ); + } + + protected virtual string NormalizeUrlControllerName(string rootPath, string controllerName, ActionModel action, string httpMethod, [CanBeNull] AbpControllerAssemblySetting configuration) + { + if(configuration?.UrlControllerNameNormalizer == null) + { + return controllerName; + } + + return configuration.UrlControllerNameNormalizer( + new UrlControllerNameNormalizerContext( + rootPath, + controllerName, + action, + httpMethod + ) + ); } protected virtual void RemoveEmptySelectors(IList selectors) 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 e0fd034214..cad6332995 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 @@ -1,26 +1,36 @@ using System; using System.Reflection; +using JetBrains.Annotations; using Microsoft.AspNetCore.Mvc.ApplicationModels; namespace Volo.Abp.AspNetCore.Mvc { public class AbpControllerAssemblySetting { + [NotNull] public Assembly Assembly { get; } + [NotNull] public string RootPath { get; } + [CanBeNull] public Func TypePredicate { get; set; } + [CanBeNull] public Action ControllerModelConfigurer { get; set; } - public AbpControllerAssemblySetting(Assembly assembly, string rootPath) + [CanBeNull] + public Func UrlControllerNameNormalizer { get; set; } + + [CanBeNull] + public Func UrlActionNameNormalizer { get; set; } + + public AbpControllerAssemblySetting([NotNull] Assembly assembly, [NotNull] string rootPath) { + Check.NotNull(assembly, rootPath); + Assembly = assembly; RootPath = rootPath; - - TypePredicate = type => true; - ControllerModelConfigurer = controller => { }; } } } \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySettingBuilder.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySettingBuilder.cs index 4799870728..ea45af6181 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySettingBuilder.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpControllerAssemblySettingBuilder.cs @@ -23,5 +23,17 @@ namespace Volo.Abp.AspNetCore.Mvc _setting.ControllerModelConfigurer = configurer; return this; } + + public AbpControllerAssemblySettingBuilder NormalizeControllerNameInUrl(Func normalizer) + { + _setting.UrlControllerNameNormalizer = normalizer; + return this; + } + + public AbpControllerAssemblySettingBuilder NormalizeActionNameInUrl(Func normalizer) + { + _setting.UrlActionNameNormalizer = normalizer; + return this; + } } } \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs index e22e1cbd27..8e118ae561 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AppServiceControllerOptions.cs @@ -12,8 +12,6 @@ namespace Volo.Abp.AspNetCore.Mvc public List FormBodyBindingIgnoredTypes { get; } - public List UrlActionNameNormalizers { get; } - public AppServiceControllerOptions() { ControllerAssemblySettings = new ControllerAssemblySettingList(); @@ -22,11 +20,6 @@ namespace Volo.Abp.AspNetCore.Mvc { typeof(IFormFile) }; - - UrlActionNameNormalizers = new List - { - new DefaultUrlActionNameNormalizer() - }; } public AbpControllerAssemblySettingBuilder CreateFor(Assembly assembly, string rootPath = ModuleApiDescriptionModel.DefaultRootPath) diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs deleted file mode 100644 index 56d7108b9f..0000000000 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/DefaultUrlActionNameNormalizer.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Volo.Abp.Http; - -namespace Volo.Abp.AspNetCore.Mvc -{ - public class DefaultUrlActionNameNormalizer : IUrlActionNameNormalizer - { - public void Normalize(UrlActionNameNormalizerContext context) - { - if (context.ActionNameInUrl.IsNullOrEmpty()) - { - return; - } - - context.ActionNameInUrl = HttpMethodHelper - .RemoveHttpMethodPrefix(context.ActionNameInUrl, context.HttpMethod) - .RemovePostFix("Async"); - } - } -} \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/IUrlActionNameNormalizer.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/IUrlActionNameNormalizer.cs deleted file mode 100644 index ca6a9df877..0000000000 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/IUrlActionNameNormalizer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Volo.Abp.AspNetCore.Mvc -{ - public interface IUrlActionNameNormalizer - { - void Normalize(UrlActionNameNormalizerContext context); - } -} \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/UrlActionNameNormalizerContext.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/UrlActionNameNormalizerContext.cs index 37719503bb..631b8b50de 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/UrlActionNameNormalizerContext.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/UrlActionNameNormalizerContext.cs @@ -10,18 +10,17 @@ namespace Volo.Abp.AspNetCore.Mvc public ActionModel Action { get; } - public string HttpMethod { get; } + public string ActionNameInUrl { get; } - public string ActionNameInUrl { get; set; } + public string HttpMethod { get; } - public UrlActionNameNormalizerContext(string rootPath, string controllerName, ActionModel action, string httpMethod, string actionNameInUrl) + public UrlActionNameNormalizerContext(string rootPath, string controllerName, ActionModel action, string actionNameInUrl, string httpMethod) { RootPath = rootPath; ControllerName = controllerName; Action = action; - HttpMethod = httpMethod; - ActionNameInUrl = actionNameInUrl; + HttpMethod = httpMethod; } } } \ No newline at end of file diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/UrlControllerNameNormalizerContext.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/UrlControllerNameNormalizerContext.cs new file mode 100644 index 0000000000..90bffe8df4 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/UrlControllerNameNormalizerContext.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Mvc.ApplicationModels; + +namespace Volo.Abp.AspNetCore.Mvc +{ + //TODO: Re-consider properties of this class. + public class UrlControllerNameNormalizerContext + { + public string RootPath { get; } + + public string ControllerName { get; } + + public ActionModel Action { get; } + + public string HttpMethod { get; } + + public UrlControllerNameNormalizerContext(string rootPath, string controllerName, ActionModel action, string httpMethod) + { + RootPath = rootPath; + ControllerName = controllerName; + Action = action; + HttpMethod = httpMethod; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Identity.HttpApi.Host/Volo.Abp.Identity.HttpApi.Host.csproj b/src/Volo.Abp.Identity.HttpApi.Host/Volo.Abp.Identity.HttpApi.Host.csproj index de04a68324..581749f373 100644 --- a/src/Volo.Abp.Identity.HttpApi.Host/Volo.Abp.Identity.HttpApi.Host.csproj +++ b/src/Volo.Abp.Identity.HttpApi.Host/Volo.Abp.Identity.HttpApi.Host.csproj @@ -39,6 +39,7 @@ + diff --git a/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/AbpIdentityHttpApiModule.cs b/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/AbpIdentityHttpApiModule.cs index 608523abdb..30e3996bc1 100644 --- a/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/AbpIdentityHttpApiModule.cs +++ b/src/Volo.Abp.Identity.HttpApi/Volo/Abp/Identity/AbpIdentityHttpApiModule.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.Modularity; @@ -13,7 +14,10 @@ namespace Volo.Abp.Identity services.Configure(options => { - options.AppServiceControllers.CreateFor(typeof(AbpIdentityApplicationModule).Assembly, "identity"); + options + .AppServiceControllers + .CreateFor(typeof(AbpIdentityApplicationModule).Assembly, "identity") + .NormalizeControllerNameInUrl(context => context.ControllerName.RemovePreFix("Identity")); }); } } diff --git a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/AbpAspNetCoreMvcTestModule.cs b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/AbpAspNetCoreMvcTestModule.cs index e95ed9d90d..a3d999671e 100644 --- a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/AbpAspNetCoreMvcTestModule.cs +++ b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/AbpAspNetCoreMvcTestModule.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Builder; +using System; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Modularity; using Volo.Abp.AspNetCore.Mvc; @@ -24,8 +25,15 @@ namespace Volo.Abp.AspNetCore.App services.Configure(options => { - options.AppServiceControllers.CreateFor(typeof(TestAppModule).Assembly); - options.AppServiceControllers.UrlActionNameNormalizers.Add(new PhoneBookUrlActionNameNormalizer()); + options + .AppServiceControllers + .CreateFor(typeof(TestAppModule).Assembly) + .NormalizeActionNameInUrl( + context => + string.Equals(context.ActionNameInUrl, "phone", StringComparison.OrdinalIgnoreCase) + ? "phones" + : context.ActionNameInUrl + ); }); services.AddAssemblyOf(); diff --git a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/PhoneBookUrlActionNameNormalizer.cs b/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/PhoneBookUrlActionNameNormalizer.cs deleted file mode 100644 index d497643932..0000000000 --- a/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/App/PhoneBookUrlActionNameNormalizer.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Volo.Abp.AspNetCore.Mvc; - -namespace Volo.Abp.AspNetCore.App -{ - public class PhoneBookUrlActionNameNormalizer : IUrlActionNameNormalizer - { - public void Normalize(UrlActionNameNormalizerContext context) - { - if (string.Equals(context.ActionNameInUrl, "phone", StringComparison.OrdinalIgnoreCase)) - { - context.ActionNameInUrl = "phones"; - return; - } - } - } -} \ No newline at end of file