Conventional Routing in ASP.NET Core API
Asked Answered
P

4

14

Problem:

I'm creating an API Application with NET Core 3.1. I'd like to avoid to set route attribute over every ApiControllers and Actions. I tryed a lot of combinations over UseEndpoints to set a conventional route, but i'm failing.

With some configuration I can't get the Api working, with some others I get this exception during startup:

InvalidOperationException: Action 'ApiIsWorking' does not have an attribute route. Action methods on controllers annotated with ApiControllerAttribute must be attribute routed.

How can i set the startup.cs to auto map controllers with their class name and actions with their method name?

Thank you!

Some code:

startup.cs

...
services.AddControllers()
...

app.UseHttpsRedirection()
   .UseRouting()
   .UseAuthentication()
   .UseEndpoints(endpoints => ?? )
   .UseCoreHttpContext()
   .UseServerConfiguration();

controller.cs

[ApiController]
public class BaseAPI : ControllerBase 
{
        [HttpGet]
        public string ApiIsWorking()
        {
            return "API is working!";
        }
}

Solution:

As Reza Aghaei says in the solution, the error was to add the ApiController attribute. After I removed it, the command UseEndpoints start to work.

My mistake was to add the attribute to be able to recognize which classes should be exposed via API. It wasn't necessary because UseEndpoints maps only the classes that inherit from ControllerBase.

Warning:

1) Conventional Routing require [FromBody] attribute in actions params.

2) I highlight Zinov's response about conventional routing problems with Swashbuckle in .NET Core

Petrolatum answered 13/2, 2020 at 10:23 Comment(2)
To have conventional routing for your controllers and action, you need to remove [ApiController] attribute from controller and setup route in UseEndpoints.Uncloak
To make a long story short, platform architects sitting thousands of miles away have made the design decision for you to use attribute routing, and this is enforced by making it an incredible pain in the ass to use conventional routing.Waldgrave
U
19

To have conventional routing for your controllers and action, you need to remove [ApiController] attribute and [Route] attribute from your controller and actions and setup route in UseEndpoints.

It's already mentioned in the documentations:

The [ApiController] attribute makes attribute routing a requirement.

Actions are inaccessible via conventional routes defined by UseEndpoints, UseMvc, or UseMvcWithDefaultRoute in Startup.Configure.

Example

This is the working setup that I have for Startup:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    public IConfiguration Configuration { get; }
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

And a sample API controller:

public class ValuesController : ControllerBase
{
    // values/getall
    [HttpGet]
    public IEnumerable<string> GetAll()
    {
        return new string[] { "value1", "value2" };
    }

    // values/getitem/1
    [HttpGet]
    public string GetItem(int id)
    {
        return "value";
    }
}
Uncloak answered 16/2, 2020 at 0:1 Comment(0)
P
5

Here is my advice if you are going down this road of using conventional routing with .net core. After you finish your API implementation you are going to add some documentation to it. People normally use this nuget package Swashbuckle.AspNetCore, which implements the later standard of OpenAPI(Swagger). But here is the problem when you use conventional routing and you want to generate the documentation with this tool.

if you are using conventional routing (as opposed to attribute routing), any controllers and the actions on those controllers that use conventional routing will not be represented in ApiExplorer, which means Swashbuckle won't be able to find those controllers and generate Swagger operations from them

For more information refer to this link : Swashbuckle Hope this saves you a lot of headaches in the future with the documentation for your api

Platysma answered 16/2, 2020 at 16:47 Comment(0)
M
4

EDIT:

I tried to set it up on my machine. When I removed the Route attribute from controller I got below error:

InvalidOperationException: Action 'WebAPISample.Controllers.WeatherForecastController.Index (WebAPISample)' does not have an attribute route. Action methods on controllers annotated with ApiControllerAttribute must be attribute routed.

The error message itself is saying that the API controllers must use attribute routing.

I know this does not answer your question, but with .NET Core 3 APIs, this does not seem to be possible.

From Documentation:

The [ApiController] attribute makes attribute routing a requirement. For example:

[Route("api/[controller]")] 
[ApiController] 
public class ValuesController : ControllerBase

Actions are inaccessible via conventional routes defined by UseMvc or UseMvcWithDefaultRoute in Startup.Configure.

Refer this page on MSDN.

Maxama answered 13/2, 2020 at 10:30 Comment(1)
this does not seem to be possible. → It's possible, remove [ApiController] and [Route(...)]attribute from controller/actions and setup route in UseEndpoints. Take a look at this post for example.Uncloak
L
3

Have you tried this?

app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

Lw answered 13/2, 2020 at 13:2 Comment(2)
Yes, i got this exception on startup: "System.InvalidOperationException: 'Action ApiIsWorking' does not have an attribute route. Action methods on controllers annotated with ApiControllerAttribute must be attribute routed.'"Petrolatum
@Paolo crociati, Is your issue fixed. can you share your code here.Overscrupulous

© 2022 - 2024 — McMap. All rights reserved.