.Net Core 2.2 Web API 405

只愿长相守 提交于 2020-01-14 04:25:15

问题


I am trying to setup a .net core 2.2 web api to use a post verb. Anything other than a get verb returns a 405 no matter if it is run on my local machine (w10 iis eXPRESS 10.0) or the windows server (2016 R2 IIS 8.0). I've read the other posts about disabling WebDav in your config file, adding a route, and completely removing the WebDav feature. I have done all of those to no avail. I'm just starting to develop in core and find this baffling, on the same server is a non-core web api that runs on .net framework 4.5 that processes GET,PUT,POST,DELETE without error. And yes, I have restarted the server after making changes to any of the configurations. The following are the web.config changes that I made, the last one coming directly from MS. Basic project that reproduces the same error on my machine and server is here https://github.com/FranciscanMedia/error405_core/tree/master it is just a standard web api project you get when you fire up VS2019.

<system.webServer>    
    <handlers accessPolicy="Read, Script">
       <remove name="WebDAV" />
       <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
       <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
          path="*."
          verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
          modules="IsapiModule"
          scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
          preCondition="classicMode,runtimeVersionv4.0,bitness64"
          responseBufferLimit="0" />
    </handlers>
</system.webServer>
<system.webServer>    
    <modules>        
        <remove name="WebDAVModule" />    
    </modules>    
    <handlers>        
        <remove name="WebDAV" />    
    </handlers>
</system.webServer>
<system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="false">
        <remove name="WebDAVModule"/>
    </modules>    
</system.webServer>
<system.webServer>
    <handlers accessPolicy="Read, Script">
        <remove name="WebDAV" />
        <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
        <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
           path="*."
           verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
           modules="IsapiModule"
           scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
           preCondition="classicMode,runtimeVersionv4.0,bitness64"
           responseBufferLimit="0" />
    </handlers>
</system.webServer>

回答1:


Short answer

It could be as simple as that. The reason is routing.

Just send your POST request to right URL like https://localhost:44327/api/values/123.


Detailed explanation

It's not the issue. It works as expected.

You make a GET request to https://localhost:44327/api/values/. It returns 200 OK.

But when you make a POST request to the same URL https://localhost:44327/api/values/. It says 405 Method not allowed.

However, you get 405. It is happening because you are hitting the GET endpoint with POST method.

Microsoft Docs says:

... the HTTP client sent a valid JSON request to the URL for a Web API application on a web server, but the server returned an HTTP 405 error message which indicates that the PUT method was not allowed for the URL. In contrast, if the request URI did not match a route for the Web API application, the server would return an HTTP 404 Not Found error.

https://docs.microsoft.com/en-us/aspnet/web-api/overview/testing-and-debugging/troubleshooting-http-405-errors-after-publishing-web-api-applications

If you simply remove the GET endpoint. The POST request will start returning 404 Not found. Which means that you are not hitting any registered route.

To send POST request you need to use different URL according to the routing rules.

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{

    // POST api/values
    [HttpPost("{val}")]
    public StatusCodeResult Post()
    {
        return Ok();
    }
}

This attribute-based configuration means that route of your POST endpoint is /api/Values/{val}. Where {val} is any value. It's not processed in the endpoint.

If you want to process it, you should pass it to the method:

[HttpPost("{val}")]
public StatusCodeResult Post(string val)
{
    return Ok();
}



回答2:


I think that in your controller you have to import another library. Try

using System.Web.Http;

Instead of

using Microsoft.AspNetCore.Mvc



回答3:


Looking at what you have defined:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase

Then for the action:

[HttpPost("{val}")]
public StatusCodeResult Post()
{
        return Ok();
}

Your routing matches the following url:

https://localhost:44327/api/values/StatusCodeResult

It is going to take your main route defined on your controller [Route("api/[controller]")]

Then you are defining the "template" to use "{val}"

This is telling it to use the ActionResult specific name and to expect var val to be passed/appened.

Checking out the official documentation here: https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.2

under section "Token replacement in route templates ([controller], [action], [area])"

They specifiy:

For convenience, attribute routes support token replacement by enclosing a token in square-braces ([, ]). The tokens [action], [area], and [controller] are replaced with the values of the action name, area name, and controller name from the action where the route is defined. In the following example, the actions match URL paths as described in the comments:

[Route("[controller]/[action]")]
public class ProductsController : Controller
{
  [HttpGet] // Matches '/Products/List'
  public IActionResult List() {
    // ...
  }

  [HttpGet("{id}")] // Matches '/Products/Edit/{id}'
  public IActionResult Edit(int id) {
    // ...
  }
}

If you want it to just route based on just verbs (follow a pattern where each api endpoint just handles operations for that specific object) then you would change your post method to just

    [HttpPost]
    public ActionResult Post(string val)
    {
        return Ok();
    }



回答4:


I totally agree with @Vladimir's answer. I dont have enough points to add comments to the answer by @vlaimir so i am adding my thoughts and suggestions.

The code you have on your github,

// POST api/values
[HttpPost("{val}")]
public StatusCodeResult Post()
{
     return Ok();
}

This is a post and it would expect a value {val} per the route action configuration. Since you may try to hit the post without any value, thats not permitted. Ensure you supply some value and then do the POST. If you are using POSTMAN, you may have to supply the BODY of your request with some value. Swagger is a great util tool to embed into the web api's and that comes with excellent intuitive UI for our routes/resources. That might be even ideal to help determine and ensure you supply the right value.

Otherwise, you dont need to modify or worry about your IIS or IIS Express settings. or webdav.



来源:https://stackoverflow.com/questions/57149312/net-core-2-2-web-api-405

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!