https://exceptionnotfound.net/using-http-methods-correctly-in-asp-net-web-api/
The algorithm ASP.NET uses to calculate the "default" method for a given action goes like this:
Action Selection
After selecting the controller, the framework selects the action by calling the IHttpActionSelector.SelectAction method. This method takes an HttpControllerContext and returns an HttpActionDescriptor.
The default implementation is provided by the ApiControllerActionSelector class. To select an action, it looks at the following:
- The HTTP method of the request.
- The "{action}" placeholder in the route template, if present.
- The parameters of the actions on the controller.
Before looking at the selection algorithm, we need to understand some things about controller actions.
Which methods on the controller are considered "actions"? When selecting an action, the framework only looks at public instance methods on the controller. Also, it excludes "special name" methods (constructors, events, operator overloads, and so forth), and methods inherited from the ApiController class.
HTTP Methods. The framework only chooses actions that match the HTTP method of the request, determined as follows:
- You can specify the HTTP method with an attribute: AcceptVerbs, HttpDelete, HttpGet, HttpHead, HttpOptions, HttpPatch, HttpPost, or HttpPut.
- Otherwise, if the name of the controller method starts with "Get", "Post", "Put", "Delete", "Head", "Options", or "Patch", then by convention the action supports that HTTP method.
- If none of the above, the method supports POST.
Parameter Bindings. A parameter binding is how Web API creates a value for a parameter. Here is the default rule for parameter binding:
- Simple types are taken from the URI.
- Complex types are taken from the request body.
Simple types include all of the .NET Framework primitive types, plus DateTime, Decimal, Guid, String, and TimeSpan. For each action, at most one parameter can read the request body.
Note:It is possible to override the default binding rules. See WebAPI Parameter binding under the hood.
微软官方的parameter binding文章
With that background, here is the action selection algorithm.
-
Create a list of all actions on the controller that match the HTTP request method.
-
If the route dictionary has an "action" entry, remove actions whose name does not match this value.
-
Try to match action parameters to the URI, as follows:
- For each action, get a list of the parameters that are a simple type, where the binding gets the parameter from the URI. Exclude optional parameters.
- From this list, try to find a match for each parameter name, either in the route dictionary or in the URI query string. Matches are case insensitive and do not depend on the parameter order.
- Select an action where every parameter in the list has a match in the URI.
- If more that one action meets these criteria, pick the one with the most parameter matches.
-
Ignore actions with the [NonAction] attribute.
Step #3 is probably the most confusing. The basic idea is that a parameter can get its value either from the URI, from the request body, or from a custom binding. For parameters that come from the URI, we want to ensure that the URI actually contains a value for that parameter, either in the path (via the route dictionary) or in the query string.