Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is "name" property in the constructor for HttpGetAttribute?

When I use HttpGet(...), intellisense tells me that besides the first argument, i.e. pattern, I also have name and order. While the latter is obvious to me, I got a bit uncertain on what the parameter name had as its purpose.

Heading over to the docs, I see that the constructor of HttpGet only declares a single parameter. That confused me and I suspect that I'm missing something or using the Framework's version instead of Core, or something.

like image 487
Konrad Viltersten Avatar asked Nov 17 '25 12:11

Konrad Viltersten


1 Answers

As I can see the biggest advantage of the Name property of the HttpMethodAttribute (which is the base class of HttpGetAttribute) is that you can distinguish method overloads:

[HttpGet(Name="ById"]
public IActionResult GetBy(int id)
{

}

[HttpGet(Name="ByExternalId"]
public IActionResult GetBy(Guid id)
{

}  

UPDATE #1: I've revised my answer

The above sample code would result in an AmbiguousMatchException, where it is stating the same Template has been registered for different action.

I had put together another sample and used the following RouteDebugger to get insight. In the Configure method I've called the app.UseRouteDebugger() method to be able to see the registered routes in json format under the /route-debugger url.

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    [HttpGet()] 
    public IActionResult GetA(string a)
    {
        return Ok(nameof(GetA));
    }

    [HttpGet(template: "GetB")]
    public IActionResult GetB(string b)
    {
        return Ok(nameof(GetB));
    }

    [HttpGet(template: "GetC", Name= "GetD")]
    public IActionResult GetD(string d, string e)
    
    {
        return CreatedAtRoute(routeName:"GetC", routeValues: new { c = "v"}, value: null);
    }

    [HttpGet(template: "GetC/{c}", Name = "GetC")]
    public IActionResult GetC(string c)
    {
        return Ok(nameof(GetC));
    }
}

The route table would look like this:

[
   {
      "Action":"GetA",
      "Controller":"Test",
      "Name":null,
      "Template":"api/Test",
      "Contraint":[{}]
   },
   {
      "Action":"GetB",
      "Controller":"Test",
      "Name":null,
      "Template":"api/Test/GetB",
      "Contraint":[{}]
   },
   {
      "Action":"GetD",
      "Controller":"Test",
      "Name":"GetD",
      "Template":"api/Test/GetC",
      "Contraint":[{}]
   },
   {
      "Action":"GetC",
      "Controller":"Test",
      "Name":"GetC",
      "Template":"api/Test/GetC/{c}",
      "Contraint":[{}]
   }
]

As you seen the following happened:

GetA method

  • It is exposed under the controller route because not Template has been specified.
  • The route itself does not have a Name so you can't refer to this route via its name inside ActionLink or CreatedAtRoute, etc.

GetB method

  • It is exposed under the api/test/getb, because the controller's and the action's Template properties are combined.
  • The route itself does not have a Name so you can't refer to this route via its name inside ActionLink or CreatedAtRoute, etc.

GetC method

  • It is exposed under the api/test/getc/{c}, because the controller's and the action's Template properties are combined. The c parameter can accept any value. If it is not provided then GetD will be called, because that was registered first.
  • The route has a Name (GetC) so you can refer to this route via its name inside ActionLink or CreatedAtRoute, etc. Like as we did it inside GetD

GetD method

  • It is exposed under the api/test/getc, because the controller's and the action's Template properties are combined. Because it was registered prior GetC method's route that's why it will called if no further path is provided.
  • The route has a Name (GetD). In the CreatedAtRoute we are referring to GetC via its name not through its route. If we are replacing the Name to GetC then it would throw the following exception at runtime:

InvalidOperationException: The following errors occurred with attribute routing information:

Error 1: Attribute routes with the same name 'GetC' must have the same template: Action: 'Controllers.TestController.GetD ()' - Template: 'api/Test/GetC' Action: 'Controllers.TestController.GetC ()' - Template: 'api/Test/GetC/{c}

Summary

  1. If you register two routes with the same Template it will throw an AmbiguousMatchException at runtime when you make a call against that route. (So, other routes will work perfectly fine)
  2. If you register two routes with the same Name it will throw an InvalidOperationException at runtime when you make any call. (So, other routes will not work)
  3. Route's Name provides the ability to refer them easily without knowing the exact Template. This separation allows us to change the Template without affecting referring links.
like image 108
Peter Csala Avatar answered Nov 19 '25 04:11

Peter Csala



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!