On my Web API project, I cannot perform an HTTP PUT
to my resources. I\'ve read through some similar questions on this problem and I\'ve followed the recommende
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);
}
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.
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() {}
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
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.