Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conventional Routing in ASP.NET Core API

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

like image 452
Paolo Crociati Avatar asked Feb 13 '20 10:02

Paolo Crociati


People also ask

What are the different types of routing in ASP NET Core?

ASP.NET Core apps can mix the use of conventional routing and attribute routing. It's typical to use conventional routes for controllers serving HTML pages for browsers, and attribute routing for controllers serving REST APIs. Actions are either conventionally routed or attribute routed.

How do I configure a route in ASP NET Core?

Inside the ConfigureRoute method, you can configure your routes; you can see that this method has to take a parameter of type IRouteBuilder. The goal of routing is to describe the rules that ASP.NET Core MVC will use to process an HTTP request and find a controller that can respond to that request.

Can I mix the use of conventional routing and attribute routing?

ASP.NET Core apps can mix the use of conventional routing and attribute routing. It's typical to use conventional routes for controllers serving HTML pages for browsers, and attribute routing for controllers serving REST APIs.

What is namespaceroutingconvention in ASP NET Core?

The NamespaceRoutingConvention can also be applied as an attribute on a controller: ASP.NET Core apps can mix the use of conventional routing and attribute routing. It's typical to use conventional routes for controllers serving HTML pages for browsers, and attribute routing for controllers serving REST APIs.


2 Answers

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";
    }
}
like image 181
Reza Aghaei Avatar answered Sep 23 '22 22:09

Reza Aghaei


Have you tried this?

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

like image 21
Miro Hudak Avatar answered Sep 25 '22 22:09

Miro Hudak