Legacy .net core frameworks used UseMvc()
for adding global route prefix. How to make it for asp.net core 3
without UseMvc()
?

- 4,953
- 5
- 20
- 34

- 2,544
- 5
- 18
- 27
-
1Asp.net core 3.0 uses `app.UseEndpoints()`, what global route prefix do you want to implement? – Ryan Oct 16 '19 at 04:31
4 Answers
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://learn.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"));

- 3,960
- 32
- 49
-
1This didn't work for me. I found a few variations on this here... https://forums.servicestack.net/t/net-core-3-1-custom-api-path-metadata/8155 but those didn't work for me either. – David Hoffman Feb 25 '21 at 11:40
-
5Because it's a middleware the order you add it matters. It works for me in core 3.1 if I add it right before the `UseRouting()` middleware. If added afterwards it will not work. – Timothy Jannace Jun 15 '21 at 22:22
-
This won't work if there's no explicit call to `UseRouting()` because then it's executed at the start of the pipeline, at least that's the case in .NET 6. Please refer to this issue for the right order of calls for this solution to work https://github.com/dotnet/aspnetcore/issues/38448#issuecomment-970882631 – Mohammed Ilyass NASR Apr 19 '22 at 11:26
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");
}
});

- 6,247
- 2
- 36
- 24
-
6At this moment I'm actually not sure whether this works correctly. In any case a downside of `UsePathBase` seems to be that both the prefixed and non-prefixed paths result in the endpoint. This may or may not be a problem, depending on your use case. Personally I switched to adding the prefix to every controller: `[Route("api/[controller]")]` – Mark Lagendijk Jul 28 '21 at 07:46
How to add global route prefix in asp.net core 6 Still works:
app.UsePathBase(new PathString("/api/service"));
app.UseRouting();

- 4,006
- 5
- 18
- 26