0
votes

A client wants to be able to put a file extension on the end of our WebApi GET calls which will determine the output format.

For example, USE:

/api/v1.0/customers.xml

or

/api/v1.0/customers.json

or this URL with a header attribute of 'accept: application/xml' or 'accept: application/json'

/api/v1.0/customers

I have the correct format working with the passing the header attribute. I can also get the correct format to work with a file extension within the URL so long as it isn't the "default" route for the controller.

So adding attribute routing defined below as:

[HttpGet( ".{format?}" )]
public async Task<IActionResult> Get()
{ ... }

[HttpGet( "{id:long}.{format?}" )]
public async Task<IActionResult> Get( long id )
{ ... }

The first method (without any input parameters) will throw an error. The second method will work.

I can get around this by adding another HttpGet attribute to the "default" method like so:

[HttpGet]
[HttpGet( ".{format}" )]
public async Task<IActionResult> Get()
{ ... }

I've created a derived class from HttpGet. What I'd like to do is have this derived class add two routes to the routing table per the one attribute, one with the format and one without. I haven't figured out how to do this.

So I want it derived HttpGet to act normally and put a route in the routing table per its normal functionality but I'd also like it to add an additional route with the ".{format}" added to the end or the route. This should handle all of my situations.

I want the two methods to look like what is displayed below and the extra "format" route added automatically (because of the new functionality added with the derived HttpGet attribute):

[HttpGet()]
public async Task<IActionResult> Get()
{ ... }

[HttpGet( "{id:long}" )]
public async Task<IActionResult> Get( long id )
{ ... }

Anyone have any ideas? Should I maybe try a different approach?

For clarity, I need an additional route for every existing route with ".{format}" added on the end because adding the optional "?" character does not work if there is not action within the route.

1
Then just add the route to the action. the attribute allows multiple.Nkosi
This I know but I'd prefer it to happen automatically. I don't want to have to add two attributes for every action when I know that a single attribute should be able to do what I want. It just needs to add two routes instead of one.EL MOJO

1 Answers

0
votes

I created a derived class from the HttpGetAttribute that appends ".{format}" in the correct location of the routing string.

So the controller actions look like this:

[HttpGet]
[HttpGetWithFormat]
public async Task<IActionResult> Get()
{ ... }

[HttpGet( "{id:long}" )]
[HttpGetWithFormat( "{id:long}" )]
public async Task<IActionResult> Get( long id )
{ ... }

This works but again it's not my ideal solution. As I have stated in my question, I should be able to create one custom attribute that does both things (HttpGet and HttpGetWithFormat).