How to add global route prefix in asp.net core 3?

You could refer to below demo in asp.net core 3.0 to set global route prefix with api version.You could set any prefix as you like by changing services.AddControllersWithViews(o => { o.UseGeneralRoutePrefix("api/v{version:apiVersion}"); });

1.Create a custom MvcOptionsExtensions

public static class MvcOptionsExtensions
{
    public static void UseGeneralRoutePrefix(this MvcOptions opts, IRouteTemplateProvider routeAttribute)
    {
        opts.Conventions.Add(new RoutePrefixConvention(routeAttribute));
    }

    public static void UseGeneralRoutePrefix(this MvcOptions opts, string 
    prefix)
    {
        opts.UseGeneralRoutePrefix(new RouteAttribute(prefix));
    }
}

public class RoutePrefixConvention : IApplicationModelConvention
{
    private readonly AttributeRouteModel _routePrefix;

    public RoutePrefixConvention(IRouteTemplateProvider route)
    {
        _routePrefix = new AttributeRouteModel(route);
    }

    public void Apply(ApplicationModel application)
    {
        foreach (var selector in application.Controllers.SelectMany(c => c.Selectors))
        {
            if (selector.AttributeRouteModel != null)
            {
                selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_routePrefix, selector.AttributeRouteModel);
            }
            else
            {
                selector.AttributeRouteModel = _routePrefix;
            }
        }
    }
}

2.Register in Startup.cs( you need to install package Microsoft.AspNetCore.Mvc.Versioning ,current version for 3.0 is 4.0.0-preview8.19405.7)

public void ConfigureServices(IServiceCollection services) {
    //MVC service registration
    //https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio#mvc-service-registration
    services.AddControllersWithViews(o = >{
        o.UseGeneralRoutePrefix("api/v{version:apiVersion}");
    });

    services.AddApiVersioning(o = >o.ReportApiVersions = true);
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {

    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints = >{
        endpoints.MapControllerRoute(
        name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
        endpoints.MapRazorPages();
    });
}

3.Controller:

[ApiVersion("1")]
[ApiVersion("2")]
[Route("test")]
[ApiController]
public class TestController : ControllerBase
{
    [HttpGet("version"), MapToApiVersion("1")]
    public IActionResult GetV1()
    {
        return new OkObjectResult("Version One");
    }
}

4.Result

Calling /api/v1/test/version results in "Version One".


I solved this in 3.1 with just the below in my startup Configure():

app.UsePathBase(new PathString("/api"));

As @alastairtree answered you can use app.UsePathBase to achieve this.

You need to place this call before registering the middleware that needs to be prefixed.

If you need to register other middleware after that, that should not be prefixed, you can reset the prefix to /.

Full example:

app.UsePathBase(new PathString("/api"));
app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller}/{action=Index}/{id?}");
});

app.UsePathBase(new PathString("/"));
app.UseSpa(spa =>
{
    spa.Options.SourcePath = "ClientApp";

    if (env.IsDevelopment())
    {
        spa.UseAngularCliServer(npmScript: "start");
    }
});