HTTP PUT not allowed in ASP.NET Web API

流过昼夜 提交于 2019-11-27 03:58:11

Apparently, there is a known problem within AttributeRouting wherein the HttpPut methods are currently non-functional in ASP.NET Web API.

The currently accepted workaround is add the appropriate verb onto the route until a proper fix comes along:

Web API RC sealed a vital interface for route detection by the underlying framework. Though the interface is now public, the change won't be released until vNext. So here are some workarounds:

  • Use AR attributes in combination with HttpGet, HttpPost, HttpPut, or HttpDelete attributes from System.Web.Http:
[GET("some/url"), HttpGet]
public string Method1() {}

[PUT("some/url"), HttpPut]
public string Method2() {}

[POST("some/url"), HttpPost]
public string Method3() {}

[DELETE("some/url"), HttpDelete]
public string Method4() {}

Double check that you're using [HttpPut] from System.Web.Http.

Under some circumstances you can end up using the attribute from System.Web.Mvc.

This was resulting in 405s for us.

I had the same error, and traced it to a custom route that I'd defined like so:

config.Routes.MapHttpRoute(
    name: "SomeCall",
    routeTemplate: "api/somecall/{id}",
    defaults: new { controller = "SomeCall", action = "Get" }
);

The problem here is the action = "Get" which prevented the PUT action of the same URI to respond. Removing the default action fixed the issue.

What worked for me was to add a Route Attribute as I already had one defined for a GET request that was overloaded as below:

    // GET api/Transactions/5
    [Route("api/Transactions/{id:int}")]
    public Transaction Get(int id)
    {
        return _transactionRepository.GetById(id);
    }

    [Route("api/Transactions/{code}")]
    public Transaction Get(string code)
    {
        try
        {
            return _transactionRepository.Search(p => p.Code == code).Single();
        }
        catch (Exception Ex)
        {
            System.IO.File.WriteAllText(@"C:\Users\Public\ErrorLog\Log.txt",
                Ex.Message + Ex.StackTrace + Ex.Source + Ex.InnerException.InnerException.Message);
        }

        return null;
    }

So I added for the PUT:

    // PUT api/Transactions/5
    [Route("api/Transactions/{id:int}")]
    public HttpResponseMessage Put(int id, Transaction transaction)
    {
        try
        {
            if (_transactionRepository.Save(transaction))
            {
                return Request.CreateResponse<Transaction>(HttpStatusCode.Created, transaction);
            }
        }
        catch (Exception Ex)
        {
            System.IO.File.WriteAllText(@"C:\Users\Public\ErrorLog\Log.txt",
                Ex.Message + Ex.StackTrace + Ex.Source + Ex.InnerException.InnerException.Message);
        }

        return Request.CreateResponse<Transaction>(HttpStatusCode.InternalServerError, transaction);
    }

I think this is no more the case, perhaps this issue has been fixed now. ASP.NET MVC Web API now allows $http.put and here is the code to test.

AngularJS Script code

$scope.UpdateData = function () {
        var data = $.param({
            firstName: $scope.firstName,
            lastName: $scope.lastName,
            age: $scope.age
        });

        $http.put('/api/Default?'+ data)
        .success(function (data, status, headers) {
            $scope.ServerResponse = data;
        })
        .error(function (data, status, header, config) {
            $scope.ServerResponse =  htmlDecode("Data: " + data +
                "\n\n\n\nstatus: " + status +
                "\n\n\n\nheaders: " + header +
                "\n\n\n\nconfig: " + config);
        });
    };

Html code

<div ng-app="myApp" ng-controller="HttpPutController">
<h2>AngularJS Put request </h2>
<form ng-submit="UpdateData()">
    <p>First Name: <input type="text" name="firstName" ng-model="firstName" required /></p>
    <p>Last Name: <input type="text" name="lastName" ng-model="lastName" required /></p>
    <p>Age : <input type="number" name="age" ng-model="age" required /></p>
    <input type="submit" value="Submit" />
    <hr />
    {{ ServerResponse }}
</form></div>

ASP.NET MVC Web API Controller action method

 public class DefaultController : ApiController
{

    public HttpResponseMessage PutDataResponse(string firstName, string lastName, int age)
    {
        string msg =  "Updated: First name: " + firstName +
            " | Last name: " + lastName +
            " | Age: " + age;

        return Request.CreateResponse(HttpStatusCode.OK, msg);
    }
}

(Change the url to send request to) When we click on the Submit button, it sends HttpPut request to '/api/default' (DefaultController) where PutDataResponse action method is declared. This method will be called and user gets its response.

This solution was originally written here

For me it was because I had not set the media type in the json content string for my http client request:

new StringContent(json, Encoding.UTF32, "application/json");

All sorts of weird behavior if this is not set.

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