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.

36 Answer(s)
-
0
The idea is not to use reverse proxy, can we rename host api server ?
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
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.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
-
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
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
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(); }}
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Transferred file. Thank you, Sudha
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
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
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
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.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Did you see any files under https://wetransfer.com/ ? Sudha
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
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,
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
created new project, pls check https://localhost:44390/api/approach
Uploading to that trasfer folder
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
DELETED
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
-
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
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
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.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
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
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)






