Web API放置请求生成Http 405方法不允许错误


134

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

在此处输入图片说明

client.BaseAddresshttp://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);
        }
    }
}

[HttpPut]在动作方法定义之前不应该使用吗?([HttpPost]以及[HttpDelete]适当的地方)
克里斯·普拉特

@ChrisPratt要清楚一点,您的意思是放在[HttpPut]WebAPI控制器(ApiController)上,对吗?因为Department的前端控制器(Edit方法)具有[HttpPost]属性。
Mike Marks

1
@ChrisPratt ValuesController(WebAPI模板随附的那个)[HttpPut]在Put / Post / Delete方法上没有等等属性。–
Mike Marks

是的,我有理由确定它需要Web API方面的支持。就个人而言,我一直只将AttributeRouting用于Web API,所以我的回忆有点粗略。
克里斯·普拉特

显然,这是WebDAV的问题。.我检查了本地IIS(Windows功能)以确保未安装它,并说它没有……反正我发布了一个答案,基本上从我的网络中删除了WebDAV模块.config。
Mike Marks 2013年

Answers:


304

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

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

此外,通常需要web.config在处理程序中添加以下内容。感谢巴巴克

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

2
哈哈...是的...我要放弃了。嗯是的。您必须已启用WebDAV applicationhost.config。很高兴您已解决问题。
阿隆(Aron)2013年

9
您可能还需要添加以下内容:<handlers><remove name="WebDAV" />...
Babak 2014年

14
将此添加到我的WebApi web.config中,并且可以正常工作。
福迪2014年

即使在IE10中,即使没有此配置也可以正常工作,但我只需要在WebApi web.config中执行操作,即可使其在Chrome浏览器中运行。
丹尼斯·R

1
感谢您回答这个非常烦人的问题。为什么首先发生这种情况?
斯科特·威尔逊

23

WebDav-SchmebDav ....请确保您正确创建带有ID的网址。不要像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"}

这使我的球陷入了永恒的小尴尬境地。


3
对我来说,另一个麻烦是:PUT操作无法将数据绑定到原始类型参数。我不得不改变public int PutFluffColor(int Id, int colorCode),以public int PutFluffColor(int Id, UpdateFluffColorModel model)
乔希诺埃

4
希望我能为WebDav-SchmebDav投票两次
Noel

1
经过8个多小时的解决方案工作后,每个人都建议web.config对其进行更改,以至于没有人甚至没有谈论这种可能性。
sairfan '18 -10-29

22

将此添加到您的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。


我已经有 我假设这将放在Web API项目中,而不是在前端MVC项目中,对吗?
Mike Marks,

我没有安装WebDAV。另外,您是说上面的web.config代码需要放在调用Web API的项目的web.config中吗?
Mike Marks,

实际上在两个web.configs中都... :(
Mike Marks,

哦,不...我以为您是从MVC项目中引用Web API项目的。
阿隆(Aron)2013年

1
您可以发布DepartmentController的代码清单吗?所有的。问题出在您的Web API项目中,并且它不知道如何处理PUT,这就是405的含义。检查GET是否有效,只是为了排除路由。PS。尝试复制粘贴代码而不是屏幕截图。PPS,请勿使用Task.Result,在某些情况下会出现不相关的线程问题。只需将整个方法改为异步等待即可。更不用说它会创建同步的多线程阻塞代码(比单线程慢)。
阿隆(Aron)2013年

14

我正在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文件。最后,通过上面的配置,一切都重新开始了。


5

用[FromBody]装饰动作参数之一为我解决了这个问题:

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

但是,如果在方法参数中使用了复杂对象,则ASP.NET可以正确推断出它:

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

1

造成这种情况的另一个原因可能是,如果您未对“ id”使用默认的变量名,实际上是:id。


0

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


0

您可以针对特定的IIS从GUI手动删除webdav模块。
1)转到II。
2)转到相应站点。
3)打开“处理程序映射”
。4)向下滚动并选择WebDav模块。右键单击它并删除它。

注意:这还将更新您的Web应用程序的web.config。


-1

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

客户端-本地主机

服务器-本地主机

并不是 :

客户端-本地主机:21234

服务器-本地主机


2
我不这么认为。创建服务的目的是从另一个域呼叫
Ozan拜拉姆

您正在考虑一个跨域请求,它将从服务器收到200响应,但是浏览器将强制执行其“无跨域请求”规则,并且不接受响应。问题是指向405“方法不允许”响应,这是一个不同的问题。
2015年

CORS将提供405“不允许的方法”,例如:请求URL:testapi.nottherealsite.com/api/Reporting/RunReport请求方法:OPTIONS状态码:405方法不允许请在此处阅读stackoverflow.com/questions/12458444/…
Lev K.

您指的是CORS问题。
user3151766
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.