Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unhandled exception when you call an HTTP POST action with GET #52

Closed
BillDines opened this issue Nov 8, 2016 · 4 comments
Closed

Unhandled exception when you call an HTTP POST action with GET #52

BillDines opened this issue Nov 8, 2016 · 4 comments
Assignees
Labels

Comments

@BillDines
Copy link

BillDines commented Nov 8, 2016

A bit obscure I know, but I came across this bug when I was doing daft things to my Api to see if it reacted OK (users do daft things occasionally!)

Its easy to reproduce with the Asp.Net Core samples HelloWorldController. Just add an HttpPost action that does anything you like - I have added one called "NotAGet"

`[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class HelloWorldController : Controller
{
// GET api/v{version}/helloworld
[HttpGet]
public IActionResult Get() => Ok(new { Controller = GetType().Name, Version = HttpContext.GetRequestedApiVersion().ToString() });

  // GET api/v{version}/helloworld/{id}
  [HttpGet("{id:int}", Name = "GetMessageById")]
  public IActionResult Get(int id) => Ok(new { Controller = GetType().Name, Id = id, Version = HttpContext.GetRequestedApiVersion().ToString() });

  // POST api/v{version}/helloworld
  [HttpPost]
  public IActionResult Post() => CreatedAtRoute("GetMessageById", new { id = 42 }, null);

  [HttpPost("notAGet")]
  public IActionResult NotAGet() => CreatedAtRoute("notAGet", new { id = 43 }, null);
}`

Run the project and paste the following into a browser address bar:

http:///api/v1/helloworld/notAGet

You will get an unhandled ArgumentNullException in the application, ultimately resulting in an HTTP 500 being returned to the browser.

Obviously this is a pretty low priority as it only occurs when someone does something silly, but ideally it still shouldn't throw an unhandled exception...

@commonsensesoftware
Copy link
Collaborator

This looks like a possible false positive. In the new POST action, it is returning the location header that is generated by using the route template with the key notAGet and the values new { id = 43 }. Since the route template defined by [HttpPost("notAGet")] does not have an {id} template parameter, I would expect some type of failure.

To test the theory, I added and modified your example as:

[HttpPost("notAGet")]
public IActionResult NotAGet() => CreatedAtRoute("GetMessageById", new { id = 43 }, null );

The request looks like:

POST /api/v1/helloworld/notAGet HTTP/1.1
Host: localhost

The operation succeeds with the response:

HTTP/1.1 201 Created
api-supported-versions: 1.0
Location: http://localhost/api/v1/HelloWorld/43

In addition, the 500 response that I received clearly indicated that one or more of the route values were not present in the template. Maybe that information is only disclosed during debugging. Let me know if this is not the behavior you are expecting.

@BillDines
Copy link
Author

BillDines commented Nov 8, 2016

@commonsensesoftware - sorry, my example is probably a bit confusing, so I'll strip it down to the simplest case. Take this controller

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class HelloWorldController : Controller
{
[HttpPost("notAGet")]
public IActionResult NotAGet() => Ok();
}

if you issue a GET request as follows:
GET /api/v1/helloworld/notAGet HTTP/1.1
Host: localhost

You get an unhandled ArgumentNullException from the ApiVersioning middleware. It throws at line 26 of Microsoft.AspNetCore.Mvc.Versioning.ActionSelectionContext.cs. This will end up being an Http 500 response.

I think you should get an Http 404 in this instance because there is no matching route for the GET request. At least that is what happens if you do the same thing to a controller in a project without any Api versioning e.g.

[Route("api/[controller]")]
public class HelloWorldController : Controller
{
  [HttpPost("notAGet")]
  public IActionResult NotAGet() => Ok();

}

GET /api/helloworld/notAGet HTTP/1.1
Host: localhost

Gives a 404...

Hope that makes sense...

@commonsensesoftware
Copy link
Collaborator

I see. Yes, this is a bug. The original implementation of the ActionSelector class returns null when no actions are satisfied and I didn't account for that. I've tracked down the issue and will have a published fix in soon. Thanks for reporting this.

@BillDines
Copy link
Author

No problem. Thanks for fixing!

commonsensesoftware pushed a commit that referenced this issue Nov 9, 2016
…actions are matched and return HTTP 404 instead. Fixes #52.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants