Check the docs before asking a question: https://abp.io/docs/latest Check the samples to see the basic tasks: https://abp.io/docs/latest/samples The exact solution to your question may have been answered before, and please first use the search on the homepage.
Provide us with the following info:
🧐 Hint: If you are using the ABP Studio, you can see all the information about your solution from the configuration window, which opens when you right-click on the solution and click on the Solution Configuration button.
- Exception message and full stack trace:
- Steps to reproduce the issue:
I am trying to rename host api from https://localhost:44320/ to https://localhost:44320/api/auth using appsettings.json, launchsettings.json. I am getting swagger error 404 because it cannot find the path. I am using sample project. Can you suggest a method ? I changed swagger endpoint and swagger base path and it does not work.

30 Answer(s)
-
0
The idea is not to use reverse proxy, can we rename host api server ?
-
0
- Solution You don’t need a reverse proxy to serve your HttpApi.Host under /api/auth, but you must consistently set a PathBase and align ALL generated URLs, route prefixes, and Swagger paths with it.
Goal: https://localhost:44320/api/auth should be the app’s base URL. Key rule: When you use app.UsePathBase("/api/auth"), every incoming request path and every generated URL must include /api/auth.
Apply these steps to your HttpApi.Host:
- Set PathBase early in the pipeline
public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); app.UsePathBase("/api/auth"); app.UseRouting(); app.UseStaticFiles(); app.UseAbpStudioLink(); app.UseAbpSecurityHeaders(); app.UseCors(); app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } app.UseUnitOfWork(); app.UseDynamicClaims(); app.UseAuthorization(); app.UseSwagger(); app.UseAbpSwaggerUI(options => { // Swagger endpoint MUST include the PathBase prefix options.SwaggerEndpoint("/api/auth/swagger/v1/swagger.json", "API"); // And make Swagger UI itself available under /api/auth/swagger options.RoutePrefix = "api/auth/swagger"; }); app.UseConfiguredEndpoints(); }- Make the app’s own “self” URL include the PathBase In your appsettings.json of HttpApi.Host:
{ "App": { "SelfUrl": "https://localhost:44320/api/auth" } }ABP uses App:SelfUrl for various generated links. If you keep it without the prefix, some URLs will be wrong.
Keep controller routes as-is You do NOT need to change [Route("api/...")] attributes or conventional controller prefixes. PathBase sits in front of the entire app, so /api/auth/api/values would be wrong. Correct request is /api/auth/api/values, which is “/api/auth” (PathBase) + “/api/values” (your controller route). Don’t double-prefix routes.
Swagger JSON endpoint path With PathBase, the JSON is served at /api/auth/swagger/v1/swagger.json. Ensure:
- app.UseSwagger() is after UsePathBase.
- SwaggerEndpoint uses the full path including /api/auth.
- If you view Swagger UI at https://localhost:44320/api/auth/swagger, the UI can fetch /api/auth/swagger/v1/swagger.json.
Anti-forgery and ABP Swagger UI script ABP’s Swagger integration injects abp.js to handle CSRF. With PathBase, the SetCsrfCookie endpoint will resolve correctly as long as App:SelfUrl and PathBase are consistent and the Swagger UI page is under the same PathBase.
If you also expose static assets under the same site Call app.UseStaticFiles() after UsePathBase so static files are served via /api/auth/… when requested from this host.
Common pitfalls that cause 404 in Swagger:
- PathBase set but SwaggerEndpoint missing the prefix. Correct: options.SwaggerEndpoint("/api/auth/swagger/v1/swagger.json", ...).
- Setting RoutePrefix to “swagger” while PathBase is “/api/auth”, then browsing https://localhost:44320/swagger (wrong). With RoutePrefix = "api/auth/swagger", browse https://localhost:44320/api/auth/swagger.
- Changing controller route prefixes to include “auth” while also using PathBase, which doubles the segment.
Optional (only if you must run the UI at root /swagger while API is under /api/auth):
- Keep PathBase("/api/auth").
- Set options.RoutePrefix = "swagger" and options.SwaggerEndpoint("/api/auth/swagger/v1/swagger.json", ...).
- You will browse Swagger at https://localhost:44320/swagger, but the JSON still resolves under /api/auth/… This is valid if you prefer Swagger at root.
- Sources
- ABP Swagger integration (validated):
- https://abp.io/docs/latest
- ABP Framework GitHub (for reference of Swagger integration and middleware ordering patterns) (validated):
- https://github.com/abpframework/abp
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
-
0
-
0
-
0
hi
Can you share a template project to reproduce it?
liming.ma@volosoft.com
Thanks.
-
0
I cannot send via email due to project size. Please let me know which files you need in ABP MVC multi layer sample project and trying to change host api link from https://localhost:44320/ to https://localhost:44320/api/approach
-
0
[sghorakavi@cpat.com] said: I cannot send via email due to project size. Please let me know which files you need in ABP MVC multi layer sample project and trying to change host api link from https://localhost:44320/ to https://localhost:44320/api/approach
Program.cs using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Serilog; using Serilog.Events;
namespace Approach;
public class Program { public async static Task Main(string[] args) { Log.Logger = new LoggerConfiguration() .WriteTo.Async(c => c.File("Logs/logs.txt")) .WriteTo.Async(c => c.Console()) .CreateBootstrapLogger();
try { Log.Information("Starting Approach.HttpApi.Host."); var builder = WebApplication.CreateBuilder(args); builder.Host .AddAppSettingsSecretsJson() .UseAutofac() .UseSerilog((context, services, loggerConfiguration) => { loggerConfiguration #if DEBUG .MinimumLevel.Debug() #else .MinimumLevel.Information() #endif .MinimumLevel.Override("Microsoft", LogEventLevel.Information) .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) .Enrich.FromLogContext() .WriteTo.Async(c => c.File("Logs/logs.txt")) .WriteTo.Async(c => c.Console()) .WriteTo.Async(c => c.AbpStudio(services)); }); await builder.AddApplicationAsync<ApproachHttpApiHostModule>(); // builder.Services.AddEndpointsApiExplorer(); // builder.Services.AddSwaggerGen(); var app = builder.Build(); /// app.Use(async (context, next) => { if (context.Request.Path.Value?.Contains("_framework/aspnetcore-browser-refresh.js") == true) { context.Response.Redirect("/api/approach/_framework/aspnetcore-browser-refresh.js"); return; } await next(); }); // standard ABP pipeline app.UseStaticFiles(); await app.InitializeApplicationAsync(); app.MapControllers(); var apiRoot = builder.Configuration["App:ApiRoot"] ?? ""; if (!string.IsNullOrWhiteSpace(apiRoot)) { app.UsePathBase(apiRoot); } //app.UseSwagger(); /*app.UseSwaggerUI(options => { options.RoutePrefix = "api/approach/swagger"; options.SwaggerEndpoint("/api/approach/swagger/v1/swagger.json", "Approach API"); }); */ await app.RunAsync(); return 0; } catch (Exception ex) { if (ex is HostAbortedException) { throw; } Log.Fatal(ex, "Host terminated unexpectedly!"); return 1; } finally { Log.CloseAndFlush(); } }} ApproachHttpHostModule.cs using System; using System.Collections.Generic; using System.IO; using System.Linq; using Medallion.Threading; using Medallion.Threading.Redis; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.MicrosoftAccount; using Microsoft.AspNetCore.Authentication.Twitter; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Volo.Abp.PermissionManagement; using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Approach.EntityFrameworkCore; using Approach.MultiTenancy; using StackExchange.Redis; using Microsoft.OpenApi.Models; using Approach.HealthChecks; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.DistributedLocking; using Volo.Abp; using Volo.Abp.Studio; using Volo.Abp.Account; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; using Volo.Abp.Caching; using Volo.Abp.Identity.AspNetCore; using Volo.Abp.Modularity; using Volo.Abp.Security.Claims; using Volo.Abp.Swashbuckle; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; using Volo.Abp.Studio.Client.AspNetCore; using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; using Volo.Abp.AspNetCore.Mvc.Libs;
namespace Approach;
[DependsOn( typeof(ApproachHttpApiModule), typeof(AbpAutofacModule), typeof(AbpStudioClientAspNetCoreModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpDistributedLockingModule), typeof(AbpAspNetCoreMvcUiMultiTenancyModule), typeof(AbpIdentityAspNetCoreModule), typeof(ApproachApplicationModule), typeof(ApproachEntityFrameworkCoreModule), typeof(AbpSwashbuckleModule), typeof(AbpAspNetCoreSerilogModule) )] public class ApproachHttpApiHostModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); var hostingEnvironment = context.Services.GetHostingEnvironment();
if (!configuration.GetValue<bool>("App:DisablePII")) { Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; Microsoft.IdentityModel.Logging.IdentityModelEventSource.LogCompleteSecurityArtifact = true; } ConfigureUrls(configuration); ConfigureConventionalControllers(); ConfigureAuthentication(context, configuration); ConfigureSwagger(context, configuration); ConfigureCache(configuration); ConfigureVirtualFileSystem(context); ConfigureDataProtection(context, configuration, hostingEnvironment); ConfigureDistributedLocking(context, configuration); ConfigureCors(context, configuration); ConfigureExternalProviders(context); ConfigureHealthChecks(context); Configure<PermissionManagementOptions>(options => { options.IsDynamicPermissionStoreEnabled = true; }); Configure<AbpMvcLibsOptions>(options => { options.CheckLibs = false; }); } private void ConfigureHealthChecks(ServiceConfigurationContext context) { context.Services.AddApproachHealthChecks(); } private void ConfigureUrls(IConfiguration configuration) { Configure<AppUrlOptions>(options => { }); } private void ConfigureCache(IConfiguration configuration) { Configure<AbpDistributedCacheOptions>(options => { options.KeyPrefix = "Approach:"; }); } private void ConfigureVirtualFileSystem(ServiceConfigurationContext context) { var hostingEnvironment = context.Services.GetHostingEnvironment(); if (hostingEnvironment.IsDevelopment()) { Configure<AbpVirtualFileSystemOptions>(options => { options.FileSets.ReplaceEmbeddedByPhysical<ApproachDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}Approach.Domain.Shared", Path.DirectorySeparatorChar))); options.FileSets.ReplaceEmbeddedByPhysical<ApproachDomainModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}Approach.Domain", Path.DirectorySeparatorChar))); options.FileSets.ReplaceEmbeddedByPhysical<ApproachApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}Approach.Application.Contracts", Path.DirectorySeparatorChar))); options.FileSets.ReplaceEmbeddedByPhysical<ApproachApplicationModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}Approach.Application", Path.DirectorySeparatorChar))); options.FileSets.ReplaceEmbeddedByPhysical<ApproachHttpApiModule>(Path.Combine(hostingEnvironment.ContentRootPath, string.Format("..{0}..{0}src{0}Approach.HttpApi", Path.DirectorySeparatorChar))); }); } } private void ConfigureConventionalControllers() { Configure<AbpAspNetCoreMvcOptions>(options => { options.ConventionalControllers.Create(typeof(ApproachApplicationModule).Assembly); }); } /*private void ConfigureConventionalControllers() { Configure<AbpAspNetCoreMvcOptions>(options => { options.ConventionalControllers.Create(typeof(TMS_MVCApplicationModule).Assembly); }); } */ private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) { var key = Encoding.UTF8.GetBytes(configuration["LMSJWTKey"]); context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddAbpJwtBearer(options => { options.Authority = configuration["AuthServer:Authority"]; options.RequireHttpsMetadata = configuration.GetValue<bool>("AuthServer:RequireHttpsMetadata"); options.Audience = "Approach"; }) .AddJwtBearer("LMSAPI", options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false }; }); context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options => { options.IsDynamicClaimsEnabled = true; }); } private static void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration) { /* context.Services.AddAbpSwaggerGenWithOidc( configuration["AuthServer:Authority"]!, ["Approach"], [AbpSwaggerOidcFlows.AuthorizationCode], configuration["AuthServer:MetaAddress"], options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "Approach API", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); });*/ context.Services.AddAbpSwaggerGenWithOidc( configuration["AuthServer:Authority"]!, new[] { "Approach" }, // API resource name(s) new[] { AbpSwaggerOidcFlows.AuthorizationCode }, // OIDC flow(s) configuration["AuthServer:MetaAddress"], options => { options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "Approach API", Version = "v1" }); /* options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "Enter: Bearer {your JWT token}", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = "bearer", BearerFormat = "JWT" });*/ options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); }); } private void ConfigureDataProtection( ServiceConfigurationContext context, IConfiguration configuration, IWebHostEnvironment hostingEnvironment) { if (AbpStudioAnalyzeHelper.IsInAnalyzeMode) { return; } var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("Approach"); if (!hostingEnvironment.IsDevelopment()) { var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!); dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "Approach-Protection-Keys"); } } private void ConfigureDistributedLocking( ServiceConfigurationContext context, IConfiguration configuration) { if (AbpStudioAnalyzeHelper.IsInAnalyzeMode) { return; } context.Services.AddSingleton<IDistributedLockProvider>(sp => { var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!); return new RedisDistributedSynchronizationProvider(connection.GetDatabase()); }); } private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddCors(options => { options.AddDefaultPolicy(builder => { builder .WithOrigins( configuration["App:CorsOrigins"]? .Split(",", StringSplitOptions.RemoveEmptyEntries) .Select(o => o.Trim().RemovePostFix("/")) .ToArray() ?? Array.Empty<string>() ) .WithAbpExposedHeaders() .SetIsOriginAllowedToAllowWildcardSubdomains() .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); } private void ConfigureExternalProviders(ServiceConfigurationContext context) { context.Services .AddDynamicExternalLoginProviderOptions<GoogleOptions>( GoogleDefaults.AuthenticationScheme, options => { options.WithProperty(x => x.ClientId); options.WithProperty(x => x.ClientSecret, isSecret: true); } ) .AddDynamicExternalLoginProviderOptions<MicrosoftAccountOptions>( MicrosoftAccountDefaults.AuthenticationScheme, options => { options.WithProperty(x => x.ClientId); options.WithProperty(x => x.ClientSecret, isSecret: true); } ) .AddDynamicExternalLoginProviderOptions<TwitterOptions>( TwitterDefaults.AuthenticationScheme, options => { options.WithProperty(x => x.ConsumerKey); options.WithProperty(x => x.ConsumerSecret, isSecret: true); } ); } public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); var env = context.GetEnvironment(); app.UsePathBase("/api/approach"); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseAbpRequestLocalization(); app.UseRouting(); app.MapAbpStaticAssets(); app.UseAbpStudioLink(); app.UseAbpSecurityHeaders(); app.UseCors(); app.UseAuthentication(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } app.UseUnitOfWork(); app.UseDynamicClaims(); app.UseAuthorization(); app.UseSwagger(); app.UseAbpSwaggerUI(options => { options.SwaggerEndpoint("/api/approach/swagger/v1/swagger.json", "Approach API"); //options.RoutePrefix = "api/approach/swagger"; var configuration = context.GetConfiguration(); options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); }); app.UseAuditing(); app.UseAbpSerilogEnrichers(); app.UseConfiguredEndpoints(); }}
-
0
hi
Can you share the project via https://wetransfer.com/
Run
abp cleanand zip the project.Thanks.
-
0
Transferred file. Thank you, Sudha
-
0
hi
Can you add your test code to a new template project? It would be very simple to run it
Thanks
-
0
plsease compile the code and run https://localhost:44320/api/approach it goes to https://localhost:44320/api/approach/swagger/index.html and does not see json file. pls check
-
0
hi
I can't access the https://pkgs.dev.azure.com/CPaT/_packaging/CPaT/nuget/v3/index.json
Can you add your code to a new template project?
Thanks.
-
0
Did you see any files under https://wetransfer.com/ ? Sudha
-
0
-
0
We do not need that nuget package. The issue is in Hostapi. Can you compile that by itself ?
Approach.HttpApi.Host project can you run that ? Thank you,
-
0
hi
Still cant restore and build
Approach.HttpApi.HostCan you add the test Swagger code to a new project?
Thanks
-
0
created new project, pls check https://localhost:44390/api/approach
Uploading to that trasfer folder
-
0
hi
Can you upload it to wetransfer and share the download link again?
Thanks
-
0
DELETED
-
0
-
0
Sorry about number of files. Question, is there any cache that will not allow me to launch my host swagger ?
I ran: abp clean, dotnet clean redis-cli flishall cleared all browser cache.
Did I miss anything else ? Thank you very much, Sudha
-
0
hi
Have you started the
AuthServerproject?Can you share the API debug logs and the HAR file for your Swagger page?
https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems#answer-3a1a1c4b-691e-3403-98b9-5f23fa024759
Thanks.
-
0
[maliming] said: hi
Have you started the
AuthServerproject?Can you share the API debug logs and the HAR file for your Swagger page?
https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems#answer-3a1a1c4b-691e-3403-98b9-5f23fa024759
Thanks.
Yes, started authserver. Sending you logs via email.
Thank you, Sudha
-
0
hi
Thanks. You can share the logs via https://wetransfer.com/
-
0
hi
I got the har files, Can you share the debug logs?
Thanks.






