diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalControllerSetting.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalControllerSetting.cs
index d1b0eef6ab..bb2f7f1d6f 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalControllerSetting.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalControllerSetting.cs
@@ -33,6 +33,22 @@ public class ConventionalControllerSetting
}
}
private string _rootPath;
+
+ ///
+ /// Default value: null.
+ /// If not set, it uses
+ /// "api" for application services,
+ /// "integration-api" for integration services.
+ ///
+ [CanBeNull]
+ public string ApiRoutePrefix {
+ get => _apiRoutePrefix;
+ set {
+ Check.NotNull(value, nameof(value));
+ _apiRoutePrefix = value;
+ }
+ }
+ private string _apiRoutePrefix;
[NotNull]
public string RemoteServiceName {
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalRouteBuilder.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalRouteBuilder.cs
index 3891827c0f..aa809e0ef3 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalRouteBuilder.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Conventions/ConventionalRouteBuilder.cs
@@ -4,6 +4,7 @@ using System.Reflection;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.Extensions.Options;
+using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http;
using Volo.Abp.Reflection;
@@ -26,9 +27,11 @@ public class ConventionalRouteBuilder : IConventionalRouteBuilder, ITransientDep
string httpMethod,
[CanBeNull] ConventionalControllerSetting configuration)
{
- var controllerNameInUrl = NormalizeUrlControllerName(rootPath, controllerName, action, httpMethod, configuration);
+ var apiRoutePrefix = GetApiRoutePrefix(action, configuration);
+ var controllerNameInUrl =
+ NormalizeUrlControllerName(rootPath, controllerName, action, httpMethod, configuration);
- var url = $"api/{rootPath}/{NormalizeControllerNameCase(controllerNameInUrl, configuration)}";
+ var url = $"{apiRoutePrefix}/{rootPath}/{NormalizeControllerNameCase(controllerNameInUrl, configuration)}";
//Add {id} path if needed
var idParameterModel = action.Parameters.FirstOrDefault(p => p.ParameterName == "id");
@@ -69,6 +72,21 @@ public class ConventionalRouteBuilder : IConventionalRouteBuilder, ITransientDep
return url;
}
+ protected virtual string GetApiRoutePrefix(ActionModel actionModel, ConventionalControllerSetting configuration)
+ {
+ if (!configuration.ApiRoutePrefix.IsNullOrWhiteSpace())
+ {
+ return configuration.ApiRoutePrefix;
+ }
+
+ if (actionModel.Controller.ControllerType.IsDefined(typeof(IntegrationServiceAttribute), true))
+ {
+ return "integration-api";
+ }
+
+ return "api";
+ }
+
protected virtual string NormalizeUrlActionName(string rootPath, string controllerName, ActionModel action,
string httpMethod, [CanBeNull] ConventionalControllerSetting configuration)
{
@@ -108,7 +126,8 @@ public class ConventionalRouteBuilder : IConventionalRouteBuilder, ITransientDep
);
}
- protected virtual string NormalizeControllerNameCase(string controllerName, [CanBeNull] ConventionalControllerSetting configuration)
+ protected virtual string NormalizeControllerNameCase(string controllerName,
+ [CanBeNull] ConventionalControllerSetting configuration)
{
if (configuration?.UseV3UrlStyle ?? Options.UseV3UrlStyle)
{
@@ -120,7 +139,8 @@ public class ConventionalRouteBuilder : IConventionalRouteBuilder, ITransientDep
}
}
- protected virtual string NormalizeActionNameCase(string actionName, [CanBeNull] ConventionalControllerSetting configuration)
+ protected virtual string NormalizeActionNameCase(string actionName,
+ [CanBeNull] ConventionalControllerSetting configuration)
{
if (configuration?.UseV3UrlStyle ?? Options.UseV3UrlStyle)
{
@@ -132,13 +152,15 @@ public class ConventionalRouteBuilder : IConventionalRouteBuilder, ITransientDep
}
}
- protected virtual string NormalizeIdPropertyNameCase(PropertyInfo property, [CanBeNull] ConventionalControllerSetting configuration)
+ protected virtual string NormalizeIdPropertyNameCase(PropertyInfo property,
+ [CanBeNull] ConventionalControllerSetting configuration)
{
return property.Name;
}
- protected virtual string NormalizeSecondaryIdNameCase(ParameterModel secondaryId, [CanBeNull] ConventionalControllerSetting configuration)
+ protected virtual string NormalizeSecondaryIdNameCase(ParameterModel secondaryId,
+ [CanBeNull] ConventionalControllerSetting configuration)
{
return secondaryId.ParameterName;
}
-}
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PeopleIntegrationService_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PeopleIntegrationService_Tests.cs
new file mode 100644
index 0000000000..850eb12862
--- /dev/null
+++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PeopleIntegrationService_Tests.cs
@@ -0,0 +1,15 @@
+using System.Threading.Tasks;
+using Shouldly;
+using Xunit;
+
+namespace Volo.Abp.AspNetCore.Mvc;
+
+public class PeopleIntegrationService_Tests : AspNetCoreMvcTestBase
+{
+ [Fact]
+ public async Task GetValueAsync()
+ {
+ var result = await GetResponseAsStringAsync("/integration-api/app/people/value");
+ result.ShouldBe("42");
+ }
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleIntegrationService.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleIntegrationService.cs
new file mode 100644
index 0000000000..7e4c76daaa
--- /dev/null
+++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/IPeopleIntegrationService.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+
+namespace Volo.Abp.TestApp.Application;
+
+public interface IPeopleIntegrationService : IApplicationService
+{
+ Task GetValueAsync();
+}
\ No newline at end of file
diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleIntegrationService.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleIntegrationService.cs
new file mode 100644
index 0000000000..4501fdb16f
--- /dev/null
+++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Application/PeopleIntegrationService.cs
@@ -0,0 +1,13 @@
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+
+namespace Volo.Abp.TestApp.Application;
+
+[IntegrationService]
+public class PeopleIntegrationService : ApplicationService, IPeopleIntegrationService
+{
+ public async Task GetValueAsync()
+ {
+ return "42";
+ }
+}
\ No newline at end of file