ASP Net Core Attribute routing and double forward slash
Asked Answered
D

1

6

As pointed out here, having a double slash in a URL is valid.

I have an ASP Net Core project that uses attribute routing, a controller named GroupController for handling operations on Groups and an action for PUTting RuleParts of a group, specified by its ImportId of type string.

[Route("/api/[controller]")]
public class GroupController : ControllerBase
{
    [HttpPut("{groupImportId?}/ruleParts")]
    public async Task<IActionResult> PutRuleParts(string groupImportId, [FromBody]List<RulePartDto> ruleParts)
    {
        return null; //actual code ommitted for brevity
    }
}

A URL like http://localhost/api/group/groupImportId/ruleParts matches as expected.

I would expect that null groupImportIds, i.e. URLs like http://localhost/api/group//ruleParts would call that same action, since the groupImportId route parameter has been marked as optional. However, when trying to call this URL, I get a 404 error and the action is not hit.

Is there a possibility to match an empty URL path segment in ASP Net Core?

Dirham answered 9/5, 2018 at 8:30 Comment(11)
Do not use the double slash. add another route so that http://localhost/api/group/ruleParts will also be valid.Zest
@Zest I don't get to choose what a web-client is going to call, hence I can't control if he's using a double slash. Please don't mark the question as dup when it's not actually a dup.Dirham
Also, optional parameters are suppose to be used at the end of a URL. wont work when embedded in the middle. What you expected and what the framework handles are different.Zest
Then please remove the dup-flag, reopen, write this as an answer along with some link for me to get more information about the expected placement of optional params in AspNet Core WebApi and I even get to mark an answer as accepted.Dirham
Curious though. Why would an import have an optional Id? what is the case for that scenario?Zest
Maybe I'm overengineering here, but I wanted to handle the case sketched out above: An error on the client side resulting in a call with an empty groupImportId (ie, double forward slash).Dirham
Ok. makes sense, but in that case getting a 404 would be the correct response. So I would say you do not even need the second route. Remove the optional parameter and thus any invalid calls will get the appropriate response.Zest
I'm currently returning a 404 with some extra information. But for that extra information, I need an action to manually populate the response.Dirham
Btw, would returning a 404 or a 400 (Bad request) be the "correct" (as far as correct goes with Status Codes) code to return here? After all, it's a malformed request.Dirham
404. If you were able to catch the request and assert that the id was null then you would have been able to say 400.Zest
Sounds right. Thanks.Dirham
Z
5

Do not use the optional parameter in the middle of the route template.

Optional parameters are supposed to be used at the end of a URL. Routes won't match when optional parameters embedded in the middle segments are omitted as this will result in not found errors.

Instead attribute routing allows for multiple routes to be mapped to the same action.

[HttpPut("ruleParts")] // PUT api/group/ruleParts
[HttpPut("{groupImportId}/ruleParts")] //PUT api/group/123456/ruleParts
public async Task<IActionResult> PutRuleParts([FromBody]List<RulePartDto> ruleParts, string groupImportId = null) {
    //...
}

The groupImportId argument of the action is made optional to allow the optional parameter to be omitted in the URL when the other route is requested.

Reference Routing to Controller Actions in ASP.NET Core

Zest answered 9/5, 2018 at 8:40 Comment(3)
So basically, the Asp Net Core framework is not able to handle all valid URLs? Thanks for the input, I'll have to work on my API then.Dirham
@Dirham testing a theory here. put the parameter back as optional like how you originally had it "{groupImportId?}/ruleParts", but use the action definition I provided in my answer string groupImportId = null. Lets see what happens now when you cll /api/group//rulePartsZest
Would have been nice to see that behaviour documented somewhere though.Dirham

© 2022 - 2024 — McMap. All rights reserved.