HTTP PUT не разрешен в веб-интерфейсе ASP.NET
В моем проекте веб-API я не могу выполнить HTTP PUT
для своих ресурсов. Я прочитал несколько похожих questions on проблема, и я следил за рекомендациями.
Во-первых, я полностью удалил WebDAV на своей машине (Windows 7 64-bit) и впоследствии перезагрузил свою машину.
Во-вторых, обработчики WebDAV были указаны как удаленные в моем web.config
, а глагол HTTP PUT
был указан как разрешенный для обработчика URL без расширения.
<modules runAllManagedModulesForAllRequests="false">
<remove name="WebDAVModule"/>
</modules>
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="WebDAV"/>
<add name="ExtensionlessUrlHandler-Integrated-4.0"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
type="System.Web.Handlers.TransferRequestHandler"
resourceType="Unspecified"
requireAccess="Script"
preCondition="integratedMode,runtimeVersionv4.0" />
<add name="AttributeRouting" path="routes.axd" verb="*" type="AttributeRouting.Web.Logging.LogRoutesHandler, AttributeRouting.Web" />
</handlers>
Я даже попробовал добавить обработчик URL-адресов без привязки ISAPI (32-разрядный и 64-разрядный) и сменить приложение из интегрированного пула приложений в классический пул приложений.
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness32"
responseBufferLimit="0" />
<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" />
В настоящее время я использую Thinktecture IdentityModel, чтобы включить поддержку Cross Origin Resource Sharing (CORS). Для моего здравомыслия я пошел с ядерным вариантом, позволяющим всем, чтобы убедиться, что HTTP PUT
действительно разрешено.
config.RegisterGlobal(httpConfig);
config.ForAllResources()
.ForAllOrigins()
.AllowAllMethods()
.AllowAllRequestHeaders();
Маршрутизация атрибутов Пакет NuGet настроен на выбор всех маршрутов из текущей сборки и любых подтипов ApiController
.
config.AddRoutesFromAssembly(Assembly.GetExecutingAssembly());
config.AddRoutesFromControllersOfType<ApiController>();
В моем ресурсе также правильно указан атрибут PUT
.
[PUT("/API/Authenticate/Link/{key}/{identifier}")]
public Boolean LinkUser(Guid key, String identifier) { ... }
Каждый ресурс, который я ищу по этому вопросу, рекомендует то же самое: удалить WebDAV, отключить обработчики WebDAV и убедиться, что обработчик URL без расширения настроен правильно. Я сделал все это, и он еще не работает.
В fiddler я получаю следующее:
PUT https://localhost/Test/API/Authenticate/Link/Foo/Bar
{"Message":"The requested resource does not support http method 'PUT'."}
Что я делаю неправильно?
Ответы
Ответ 1
По-видимому, в AttributeRouting
существует известная проблема, в которой методы HttpPut
в настоящее время не работают в ASP.NET Web API.
принятый в настоящее время обходной путь добавляет соответствующий глагол на маршрут до тех пор, пока не произойдет правильное исправление:
Web API RC закрепил жизненно важный интерфейс для обнаружения маршрута лежащей в основе. Хотя интерфейс теперь открыт, изменение не будет выпущен до vNext. Итак, вот некоторые обходные пути:
- Используйте атрибуты AR в сочетании с атрибутами HttpGet, HttpPost, HttpPut или HttpDelete из 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() {}
Ответ 2
Дважды проверьте, что вы используете [HttpPut] из System.Web.Http.
В некоторых случаях вы можете использовать атрибут из System.Web.Mvc.
Это привело к 405 году для нас.
Ответ 3
У меня была такая же ошибка, и я проследил ее до настраиваемого маршрута, который я определил так:
config.Routes.MapHttpRoute(
name: "SomeCall",
routeTemplate: "api/somecall/{id}",
defaults: new { controller = "SomeCall", action = "Get" }
);
Проблема здесь в action = "Get"
, которая мешала действию PUT
того же самого URI. Удаление действия по умолчанию устранило проблему.
Ответ 4
Что для меня работало, так это добавить атрибут маршрута, поскольку я уже определил его для запроса GET, который был перегружен, как показано ниже:
// 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;
}
Итак, я добавил для 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);
}
Ответ 5
Я думаю, что это уже не так, возможно, этот вопрос уже исправлен. ASP.NET MVC Web API теперь позволяет $http.put, и вот код для тестирования.
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-код
<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>
Метод действия контроллера веб-API ASP.NET MVC
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);
}
}
(Изменить URL-адрес для отправки запроса)
Когда мы нажимаем кнопку "Отправить", он отправляет запрос HttpPut на "/api/default" (DefaultController), где объявлен метод действия PutDataResponse. Этот метод будет вызван, и пользователь получит ответ.
Это решение изначально было написано здесь
Ответ 6
Для меня это было потому, что я не задал тип медиа в строке содержимого json для моего запроса http-клиента:
new StringContent (json, Encoding.UTF32, "application/json" );
Все виды странного поведения, если это не задано.