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
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.
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.
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.
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.
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
, orUseMvcWithDefaultRoute
inStartup.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";
}
}
Have you tried this?
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With