[英]Web API Put Request generates an Http 405 Method Not Allowed error
这是对我的 Web API 上的PUT
方法的调用 - 方法中的第三行(我从 ASP.NET MVC 前端调用 Web API):
client.BaseAddress
是http://localhost/CallCOPAPI/
。
这是contactUri
:
这是contactUri.PathAndQuery
:
最后,这是我的 405 响应:
这是我的 Web API 项目中的 WebApi.config:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApiGet",
routeTemplate: "api/{controller}/{action}/{regionId}",
defaults: new { action = "Get" },
constraints: new { httpMethod = new HttpMethodConstraint("GET") });
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
我尝试将传递到PutAsJsonAsync
的路径剥离到string.Format("/api/department/{0}", department.Id)
和string.Format("http://localhost/CallCOPAPI/api/department/{0}", department.Id)
没有运气。
有没有人知道为什么我会收到 405 错误?
更新
根据请求,这是我的部门控制器代码(我将发布前端项目的部门控制器代码以及 WebAPI 的部门 ApiController 代码):
前端部门主管
namespace CallCOP.Controllers
{
public class DepartmentController : Controller
{
HttpClient client = new HttpClient();
HttpResponseMessage response = new HttpResponseMessage();
Uri contactUri = null;
public DepartmentController()
{
// set base address of WebAPI depending on your current environment
client.BaseAddress = new Uri(ConfigurationManager.AppSettings[string.Format("APIEnvBaseAddress-{0}", CallCOP.Helpers.ConfigHelper.COPApplEnv)]);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
// need to only get departments that correspond to a Contact ID.
// GET: /Department/?regionId={0}
public ActionResult Index(int regionId)
{
response = client.GetAsync(string.Format("api/department/GetDeptsByRegionId/{0}", regionId)).Result;
if (response.IsSuccessStatusCode)
{
var departments = response.Content.ReadAsAsync<IEnumerable<Department>>().Result;
return View(departments);
}
else
{
LoggerHelper.GetLogger().InsertError(new Exception(string.Format(
"Cannot retrieve the list of department records due to HTTP Response Status Code not being successful: {0}", response.StatusCode)));
return RedirectToAction("Index");
}
}
//
// GET: /Department/Create
public ActionResult Create(int regionId)
{
return View();
}
//
// POST: /Department/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(int regionId, Department department)
{
department.RegionId = regionId;
response = client.PostAsJsonAsync("api/department", department).Result;
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Edit", "Region", new { id = regionId });
}
else
{
LoggerHelper.GetLogger().InsertError(new Exception(string.Format(
"Cannot create a new department due to HTTP Response Status Code not being successful: {0}", response.StatusCode)));
return RedirectToAction("Edit", "Region", new { id = regionId });
}
}
//
// GET: /Department/Edit/5
public ActionResult Edit(int id = 0)
{
response = client.GetAsync(string.Format("api/department/{0}", id)).Result;
Department department = response.Content.ReadAsAsync<Department>().Result;
if (department == null)
{
return HttpNotFound();
}
return View(department);
}
//
// POST: /Department/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int regionId, Department department)
{
response = client.GetAsync(string.Format("api/department/{0}", department.Id)).Result;
contactUri = response.RequestMessage.RequestUri;
response = client.PutAsJsonAsync(string.Format(contactUri.PathAndQuery), department).Result;
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index", new { regionId = regionId });
}
else
{
LoggerHelper.GetLogger().InsertError(new Exception(string.Format(
"Cannot edit the department record due to HTTP Response Status Code not being successful: {0}", response.StatusCode)));
return RedirectToAction("Index", new { regionId = regionId });
}
}
//
// GET: /Department/Delete/5
public ActionResult Delete(int id = 0)
{
response = client.GetAsync(string.Format("api/department/{0}", id)).Result;
Department department = response.Content.ReadAsAsync<Department>().Result;
if (department == null)
{
return HttpNotFound();
}
return View(department);
}
//
// POST: /Department/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int regionId, int id)
{
response = client.GetAsync(string.Format("api/department/{0}", id)).Result;
contactUri = response.RequestMessage.RequestUri;
response = client.DeleteAsync(contactUri).Result;
return RedirectToAction("Index", new { regionId = regionId });
}
}
}
Web API 部门 ApiController
namespace CallCOPAPI.Controllers
{
public class DepartmentController : ApiController
{
private CallCOPEntities db = new CallCOPEntities(HelperClasses.DBHelper.GetConnectionString());
// GET api/department
public IEnumerable<Department> Get()
{
return db.Departments.AsEnumerable();
}
// GET api/department/5
public Department Get(int id)
{
Department dept = db.Departments.Find(id);
if (dept == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return dept;
}
// this should accept a contact id and return departments related to the particular contact record
// GET api/department/5
public IEnumerable<Department> GetDeptsByRegionId(int regionId)
{
IEnumerable<Department> depts = (from i in db.Departments
where i.RegionId == regionId
select i);
return depts;
}
// POST api/department
public HttpResponseMessage Post(Department department)
{
if (ModelState.IsValid)
{
db.Departments.Add(department);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, department);
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
// PUT api/department/5
public HttpResponseMessage Put(int id, Department department)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
if (id != department.Id)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
db.Entry(department).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
// DELETE api/department/5
public HttpResponseMessage Delete(int id)
{
Department department = db.Departments.Find(id);
if (department == null)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
db.Departments.Remove(department);
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK, department);
}
}
}
所以,我检查了 Windows 功能以确保我没有安装这个叫做 WebDAV 的东西,它说我没有。 无论如何,我继续将以下内容放入我的 web.config(前端和 WebAPI,只是为了确定),现在它可以工作了。 我把它放在<system.webServer>
里面。
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/> <!-- add this -->
</modules>
此外,通常需要将以下内容添加到处理程序中的web.config
。 感谢巴巴克
<handlers>
<remove name="WebDAV" />
...
</handlers>
WebDav-SchmebDav .. ..确保您使用正确的 ID 创建了 url。 不要把它像http://www.fluff.com/api/Fluff?id=MyID ,把它像http://www.fluff.com/api/Fluff/MyID 。
例如。
PUT http://www.fluff.com/api/Fluff/123 HTTP/1.1
Host: www.fluff.com
Content-Length: 11
{"Data":"1"}
这让我的球在短暂的永恒中彻底崩溃,完全尴尬。
将此添加到您的web.config
。 您需要告诉 IIS PUT
PATCH
DELETE
和OPTIONS
是什么意思。 以及调用哪个IHttpHandler
。
<configuation>
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<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" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
</configuration>
还要检查您没有启用 WebDAV。
我正在 IIS 8.5 上运行 ASP.NET MVC 5 应用程序。 我尝试了这里发布的所有变体,这就是我的web.config
样子:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/> <!-- add this -->
</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-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" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
我无法从我的服务器上卸载 WebDav,因为我没有管理员权限。 另外,有时我会在 .css 和 .js 文件中method not allowed
的method not allowed
。 最后,有了上面的配置,一切又开始工作了。
用 [FromBody] 装饰其中一个动作参数为我解决了这个问题:
public async Task<IHttpActionResult> SetAmountOnEntry(string id, [FromBody]int amount)
但是,如果在方法参数中使用了复杂对象,ASP.NET 将正确推断它:
public async Task<IHttpActionResult> UpdateEntry(string id, MyEntry entry)
另一个原因可能是如果您不使用“id”的默认变量名称,实际上是:id。
在我的情况下,由于路由(“api/images”)与同名文件夹(“~/images”)冲突,静态处理程序调用了错误 405。
您可以从 GUI 中手动删除 webdav 模块,以便在 IIS 中进行特定操作。
1) 转到 IIs。
2) 转到相应的站点。
3)打开“处理程序映射”
4) 向下滚动并选择 WebDav 模块。 右键单击它并删除它。
注意:这也将更新您的 web 应用程序的 web.config。
这个简单的问题可能会引起真正的头痛!
我可以看到您的控制器EDIT
( PUT
) 方法需要 2 个参数:a) 一个 int id,以及 b) 一个部门对象。
当您从 VS > 添加带有读/写选项的控制器生成此代码时,它是默认代码。 但是一定要记得使用这两个参数消费这个服务,否则会报405错误。
就我而言,我不需要PUT
的 id 参数,所以我只是将它从标题中删除......几个小时后没有注意到它! 如果您将其保留在那里,则该名称也必须保留为 id,除非您继续对配置进行必要的更改。
您的客户端应用程序和服务器应用程序必须在同一个域下,例如:
客户端 - 本地主机
服务器 - 本地主机
而不是:
客户端 - 本地主机:21234
服务器 - 本地主机
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.