Route Prefix VS Controller Name ( Web api ) - c#

I was wondering that if we use RoutePrefix attribute in our web api controller with a different name from controller's actual name. So would it work or not?
As far as i did
[RouterPrefix("quotation")]
public class SaleOrderController : ApiController { ... }
if we define RoutePrefix like above we can't access it via /quotation but we can access it using saleorder.
So what is RoutePrefix for or am i doing something wrong ?

To use default route use Route("")
[RoutePrefix("quotation")]
public class SaleOrderController : ApiController {
//GET quotation
[Route("")]
[HttpGet]
public IHttpActionResult GetAll() { ... }
}
Source: Attribute Routing in ASP.NET Web API 2 : Route Prefix

In order for it to work, you need to call the code below inside your WebApiConfig.Register() method:
config.MapHttpAttributeRoutes();
So your RoutePrefix works as exptected:
[RoutePrefix("quotation")]
public class SaleOrderController : ApiController
{
[Route("example")]
[HttpGet]
public IHttpActionResult Example()
{
return Ok();
}
[Route("another")]
[HttpGet]
public IHttpActionResult Another()
{
return Ok();
}
}
So your could access your apis like this:
quotation/example
quotation/another

Related

.NET 6 best way to differentiate a route in the same controller class

I have an API controller say TestController.
I have the following route definition: api/[controller] on class level and I can call the default get method as follows: .../api/test
I want to have another method in the same controller, I also want to call it with Get and the link should be as follows: .../api/test-abc
What is the best way to differentiate this second method within the same controller class.
For test-abc, you can configure the Route attribute as ~/api/test-abc to override the controller base route. See this link for details.
[Route("api/[controller]")]
public class TestController : ControllerBase
{
public IActionResult Get()
{
// ...
}
[HttpGet]
[Route("~/api/test-abc")]
public IActionResult GetAbc()
{
// ...
}
}
This approach changes only the URL of the "test-abc"-action; all other actions of the controller use the base URL configured on class level.
In .Net 6 by following Minimal API's
app.MapGet("api/test", () =>
{
return "";
});
app.MapGet("api/test-abc", () =>
{
return "";
});
By following Traditional Method
[Route("api")]
public class TestController : ControllerBase
{
[HttpGet("test")]
public IActionResult Get()
{
// ...
return Ok();
}
[HttpGet("test-abc")]
public IActionResult GetAbc()
{
// ...
return Ok();
}
}
You can by defining the controllers route template like as below:
[Route("api/[controller]")]
public class TestController : Controller
{
...
}
So you can define a method like:
[HttpGet]
[Route("~/api/Test/Index")]
public IActionResult Index()
{
return Foo.Bar();
}
[HttpGet]
[Route("~/api/Test/Index2")]
public IActionResult Index2()
{
return Foo.Bar2();
}
[HttpGet]
public IActionResult Index3()
{
return Foo.Bar3();
}
You can call it by ../api/test/index2 to use the method Index2 or ../api/test to use Index3.
This is for the standardized way to do, in your case you would use - instead of / at the Route("...") attribute.
If you use - you need to call ../api/test-index2
For further information take a look at documentation.

Controller route attribute only relevant for root function?

I have a question about .NET Core controller routing. Recently I discovered that the controller route attribute (which you place just above the controller) only works for the root method, or at least it seems that way.
My code:
using KrabbelMicroservice.Models;
using KrabbelMicroservice.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace KrabbelMicroservice.Controllers;
[ApiController]
[Route("/profile")] // <-- This is the controller routing attribute I am talking about
public class ProfileKrabbelController : Controller
{
private readonly IProfileKrabbelService _krabbelService;
public ProfileKrabbelController(IProfileKrabbelService krabbelService)
{
_krabbelService = krabbelService;
}
[HttpGet]
public IActionResult Index()
{
// not relevant
}
[HttpGet]
[Route("/id/{krabbelId}")]
public IActionResult GetKrabbelById(long krabbelId)
{
// not relevant
}
[HttpGet]
[Route("/pid/to/{profileId}")]
public IActionResult GetKrabbelsToProfileId(long profileId)
{
// not relevant
}
[HttpGet]
[Route("/pid/from/{profileId}")]
public IActionResult GetKrabbelsFromProfileId(long profileId)
{
// not relevant
}
[HttpGet]
[Route("/pid/with/{profileId}")]
public IActionResult GetKrabbelsWithProfileId(long profileId)
{
// not relevant
}
[HttpPost]
[Route("/new")]
public IActionResult AddKrabbel(ProfileKrabbel krabbel)
{
// not relevant
}
[HttpPut]
[Route("/update")]
public IActionResult UpdateKrabbel(ProfileKrabbel krabbel)
{
// not relevant
}
[HttpDelete]
[Route("/delete")]
public IActionResult DeleteKrabbel(ProfileKrabbel krabbel)
{
// not relevant
}
}
In my swagger launch the requests look like this:
I expected that all paths would be prefixed by /profile/ but it seems like only the root function (which did not have its own route attribute) implemented the prefix.
I am not only trying to get a fix for this, but also looking for an explanation as to why my controller route attribute is ignored for the other requests. The only possibility I can think of is the specific route attributes for each endpoint overriding the controller route attribute but I would like to hear it from an expert.
Secondly I would of course also like to find a solution to this problem, preferrably not adding /profile before every seperate route but if that is the only solution so be it.
Thanks in advance!
you should be remove "/" if you have root route
ex:
[Route("test")]
[ApiController]
public class TestController3 : Controller
{
[HttpGet]
[Route("testobj")]
public TestObj Test()
{
return "test";
}
}
the even shorter in httpget
[HttpGet("testobj")]
the both output:
test/testobj

Global route for all ApiControllers in .Net 6

In all of my projects i put this code in top my controllers :
[Route("api/[controller]/[action]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public IActionResult GetTest1()
{
return Ok();
}
[HttpGet]
public IActionResult GetTest2()
{
return Ok();
}
[HttpPost]
public IActionResult PostTest1(string Request)
{
return Ok("value was " + Request);
}
}
So i can call my APIs with action name without specify each action route, Like below picture from my swagger :
This work fine but i need to put this route top of all my ApiControllers in my project, When i decide to change all of my route to new one, i need to replace all RouteAttributes in my project.
I look for global solution, for Example something like this in my program.cs file :
app.MapControllerRoute(
name: "default",
pattern: "api/{controller}/{action}");
Problem is i can't make this code work when i delete RouteAttribute from my APIs.
Just followed this simple tutorial on Global route Prefix You will as well have to remove the route prefix on top of the controller after adding the global route prefix to your program.cs file.
my swagger :
my progam.cs
builder.Services.AddMvc(opt =>
{
opt.UseCentralRoutePrefix(new RouteAttribute("core/v1/[controller]/[action]"));
}
).AddControllersAsServices().AddNewtonsoftJson();
I search few hours for this and after all i didn't find any simple solution for creating good, simple, fast global route for APIs, Then i tried on my own.
Solution 1 :
You can create a base class for your APIs and put your route in that file, Then you only inherit from that class in all of your APIs.
APIBase.cs file :
[ApiController]
[Route("api/[controller]/[action]")]
public class APIBase: ControllerBase
{
}
Next step : If you need have id (or any other parameter) in your URL so you should add RouteAttribute only for that method.
ValuesController.cs file :
public class ValuesController : APIBase
{
[HttpGet]
public IActionResult GetTest1()
{
return Ok();
}
[HttpGet]
[Route("{id?}")]
public IActionResult GetTest2(int id)
{
return Ok("value was " + id);
}
[HttpPost]
public IActionResult PostTest1(string Request)
{
return Ok("value was " + Request);
}
}
Edit :
Solution 2 : You can create a string const in your project and use it in all APIs (Suggested by #Serge)
HelperStatic.cs file :
public static class HelperStatic
{
public const string BaseAPIRoute = "api/[controller]/[action]";
}
ValuesController.cs file :
[ApiController]
[Route(HelperStatic.BaseAPIRoute)]
public class ValuesController : ControllerBase
{
[HttpGet]
public IActionResult GetTest1()
{
return Ok();
}
[HttpGet]
[Route("{id?}")]
public IActionResult GetTest2(int id)
{
return Ok("value was " + id);
}
[HttpPost]
public IActionResult PostTest1(string Request)
{
return Ok("value was " + Request);
}
}
And your swagger will be like this (on both solution) :

Creating a different route to a specific action

I am working on an asp.net 5 mvc api, and I am currently working on the Accounts Controller.
since I saw in many different places that there is a convention of using /api/Tokenrouting to a login in a web api. I would like to route to that specific method without the accounts prefix, I would prefer not using a different controller, and I would prefer using Attributes over routing in Startup.cs to avoid confusion in the future.
this is what I have currently
[Route("api/[controller]")]
public class AccountsController : Controller
{
[HttpPost("login")]
public async Task<JwtToken> Token([FromBody]Credentials credentials)
{
...
}
[HttpPost]
public async Task CreateUser([FromBody] userDto)
{
...
}
}
With attribute routing you can use a tilde (~) on the Action's route attribute to override the default route of the Controller if needed:
[Route("api/[controller]")]
public class AccountsController : Controller {
[HttpPost]
[Route("~/api/token")] //routes to `/api/token`
public async Task<JwtToken> Token([FromBody]Credentials credentials) {
...
}
[HttpPost]
[Route("users")] // routes to `/api/accounts/users`
public async Task CreateUser([FromBody] userDto) {
...
}
}
For ASP.NET Core it seems that the tilde ~ symbol (see accepted answer) is not needed anymore to override the controller's route prefix – instead, the following rule applies:
Route templates applied to an action that begin with a / don't get combined with route templates applied to the controller. This example matches a set of URL paths similar to the default route.
Here is an example:
[Route("foo")]
public class FooController : Controller
{
[Route("bar")] // combined with "foo" to map to route "/foo/bar"
public IActionResult Bar()
{
// ...
}
[Route("/hello/world")] // not combined; maps to route "/hello/world"
public IActionResult HelloWorld()
{
}
}
from https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing
[Route("[controller]/[action]")]
public class HomeController : Controller
{
[Route("~/")]
[Route("/Home")]
[Route("~/Home/Index")]
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
public IActionResult About()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
In the preceding code, the Index method templates must prepend / or ~/ to the route templates. Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller.

OData v4 Routing Prefix?

I have a side-by-side Web API 2.2 APIController and OData v4 ODataController. My APIController uses routing attributes internally like this (there are no predefined routing defaults):
[RoutePrefix("api")]
public class MyController : ApiController
{
[HttpGet]
[Route("My")]
public IHttpActionResult Get()
{
//Code Here
}
[HttpGet]
[Route("My")]
public IHttpActionResult Get([FromUri] String mykey)
{
//Code Here
}
}
and as such are routed to through ./api/My and ./api/My/?mykey=value
and I've tried setting up my ODataController to follow a similar suit with:
[ODataRoutePrefix("My")]
public class oMyController : ODataController {
[HttpGet]
public IHttpActionResult Get(ODataQueryOptions<FileModel> queryOptions) {
//Code Here
}
[HttpGet]
[ODataRoute("({mykey})")]
public IHttpActionResult Get([FromODataUri] String mykey) {
//Code Here
}
}
defining odata route ahead of time like this:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<MyModel>("My");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: "odata",
model: builder.GetEdmModel()
);
but attempts to access ./odata/My and ./odata/My(value) end up going into my APIController instead of the ODataController.
How can I route these using the different prefixes, but the same name, and have them go to the appropriate controllers. I don't want to have a different name for each route if I can prevent it, the prefixes should take care of everything, but for some reason they're not.
You need to specify the ODataRoute attribute, even if it's empty:
[ODataRoutePrefix("My")]
public class oMyController : ODataController {
[HttpGet]
[ODataRoute()] // <---<< This was the key to proper OData routing
public IHttpActionResult Get(ODataQueryOptions<FileModel> queryOptions) {
//Code Here
}
[HttpGet]
[ODataRoute("({mykey})")]
public IHttpActionResult Get([FromODataUri] String mykey) {
//Code Here
}
}

Categories

Resources