WebAPI 放置请求生成 Http405方法不允许错误

下面是对我的 Web API 上的 PUT方法的调用——该方法的第三行(我从 ASP.NET MVC 前端调用 Web API) :

enter image description here

client.BaseAddresshttp://localhost/CallCOPAPI/

这里是 contactUri:

enter image description here

这里是 contactUri.PathAndQuery:

enter image description here

最后,这是我的405回复:

enter image description here

下面是我的 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);

我已经试过剥离的路径,得到传递到 PutAsJsonAsyncstring.Format("/api/department/{0}", department.Id)string.Format("http://localhost/CallCOPAPI/api/department/{0}", department.Id)没有运气。

有人知道为什么我会出现405错误吗?

更新

根据请求,下面是我的 Department 控制器代码(我将发布前端项目的 Department 控制器代码,以及 WebAPI 的 Department 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 });
}
}
}

部门

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);
}
}
}
206426 次浏览

把这个加到你的 web.config。您需要告诉 IIS 什么是 PUT PATCH DELETEOPTIONS。以及调用哪个 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。

因此,我检查了 Windows 功能,以确保我没有安装这个称为 WebDAV 的东西,它说我没有。无论如何,我继续在 web.config (前端和 WebAPI,只是为了确保)中放置了以下内容,现在它可以工作了。我把这个放在 <system.webServer>里面。

<modules runAllManagedModulesForAllRequests="true">
<remove name="WebDAVModule"/> <!-- add this -->
</modules>

此外,通常需要在处理程序的 web.config中添加以下内容

<handlers>
<remove name="WebDAV" />
...
</handlers>

确保正确创建带 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"}

这简直让我蛋疼了一辈子,彻底的尴尬。

客户端应用程序和服务器应用程序必须在同一域下,例如:

客户端-本地主机

Server-localhost 服务器-本地主机

而不是:

Client-localhost: 21234

Server-localhost 服务器-本地主机

我在 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,因为我没有管理员权限。还有,有时候我会打开 method not allowed。CSS 和。JS 文件。最后,随着上述配置的设置,一切都重新开始工作。

用[ FromBody ]装饰其中一个动作护手解决了我的问题:

public async Task<IHttpActionResult> SetAmountOnEntry(string id, [FromBody]int amount)

然而,如果在 method 参数中使用了复杂的对象,ASP.NET 可以正确地推断出:

public async Task<IHttpActionResult> UpdateEntry(string id, MyEntry entry)

造成这种情况的另一个原因可能是,如果您没有为“ id”使用默认的变量名,那么它实际上就是: id。

在我的例子中,由于路由(“ api/images”)与同名文件夹(“ ~/images”)冲突,静态处理程序调用了错误405。

您可以手动从 GUI 中删除 IIS 中特定的 webdav 模块。
1)进入第二阶段。
2)前往有关地点。
3)开放“处理程序映射”
4)向下滚动并选择 WebDav 模块,右键单击并删除它。 < br >

注意: 这也会更新 web 应用的 web.config。

这个简单的问题可以引起真正的头痛!

我可以看到您的控制器 EDIT(PUT)方法需要两个参数: a)一个 int id 和 b)一个 department 对象。

当您使用读/写选项从 VS > add 控制器生成此代码时,它是默认代码。但是,您必须记住使用这两个参数来使用此服务,否则将得到错误405。

在我的例子中,我不需要 PUT的 id 参数,所以我只是把它从头文件中删除了... ... 在几个小时没有注意到它之后!如果将它保留在那里,那么名称也必须保留为 id,除非您继续对配置进行必要的更改。