C# Web API Put 请求生成 Http 405 Method Not Allowed 错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19162825/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 14:16:12  来源:igfitidea点击:

Web API Put Request generates an Http 405 Method Not Allowed error

c#asp.net-mvcjsonasp.net-web-apihttp-status-code-405

提问by Mike Marks

Here's the call to the PUTmethod on my Web API - the third line in the method (I am calling the Web API from an ASP.NET MVC front end):

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

enter image description here

在此处输入图片说明

client.BaseAddressis http://localhost/CallCOPAPI/.

client.BaseAddresshttp://localhost/CallCOPAPI/

Here's contactUri:

这是contactUri

enter image description here

在此处输入图片说明

Here's contactUri.PathAndQuery:

这是contactUri.PathAndQuery

enter image description here

在此处输入图片说明

And finally, here's my 405 response:

最后,这是我的 405 响应:

enter image description here

在此处输入图片说明

Here's the WebApi.config in my Web API project:

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

I've tried stripping down the path that gets passed into PutAsJsonAsyncto string.Format("/api/department/{0}", department.Id)and string.Format("http://localhost/CallCOPAPI/api/department/{0}", department.Id)with no luck.

我试着剥离下来获取传递到路径PutAsJsonAsync,以string.Format("/api/department/{0}", department.Id)string.Format("http://localhost/CallCOPAPI/api/department/{0}", department.Id)没有运气。

Does anyone have any ideas why I'm getting the 405 error?

有没有人知道为什么我会收到 405 错误?

UPDATE

更新

As per request, here's my Department controller code (I will post both the Department controller code for my front end project, as well as the Department ApiController code for the WebAPI):

根据请求,这是我的部门控制器代码(我将发布前端项目的部门控制器代码以及 WebAPI 的部门 ApiController 代码):

Front End Department Controller

前端部门主管

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 Department ApiController

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);
        }
    }
}

采纳答案by Mike Marks

So, I checked Windows Features to make sure I didn't have this thing called WebDAV installed, and it said I didn't. Anyways, I went ahead and placed the following in my web.config (both front end and WebAPI, just to be sure), and it works now. I placed this inside <system.webServer>.

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

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

Additionally, it is often required to add the following to web.configin the handlers. Thanks to Babak

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

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

回答by Aron

Add this to your web.config. You need to tell IIS what PUTPATCHDELETEand OPTIONSmeans. And which IHttpHandlerto invoke.

将此添加到您的web.config. 您需要告诉 IIS 是什么PUTPATCHDELETEOPTIONS意味着什么。以及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>

Also check you don't have WebDAV enabled.

还要检查您没有启用 WebDAV。

回答by Molibar

WebDav-SchmebDav.. ..make sure you create the url with the ID correctly. Don't send it like http://www.fluff.com/api/Fluff?id=MyID, send it like http://www.fluff.com/api/Fluff/MyID.

WebDav-SchmebDav .. ..确保您使用正确的 ID 创建了 url。不要把它像http://www.fluff.com/api/Fluff?id=MyID,把它像http://www.fluff.com/api/Fluff/MyID

Eg.

例如。

PUT http://www.fluff.com/api/Fluff/123 HTTP/1.1
Host: www.fluff.com
Content-Length: 11

{"Data":"1"}

This was busting my balls for a small eternity, total embarrassment.

这让我的球在短暂的永恒中彻底崩溃,完全尴尬。

回答by Lev K.

Your client application and server application must be under same domain, for example :

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

client - localhost

客户端 - 本地主机

server - localhost

服务器 - 本地主机

and not :

并不是 :

client - localhost:21234

客户端 - 本地主机:21234

server - localhost

服务器 - 本地主机

回答by jpgrassi

I'm running an ASP.NET MVC 5 application on IIS 8.5. I tried all the variations posted here, and this is what my web.configlooks like:

我正在 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>

I couldn't uninstall WebDav from my Server because I didn't have admin privileges. Also, sometimes I was getting the method not allowedon .css and .js files. In the end, with the configuration above set up everything started working again.

我无法从我的服务器上卸载 WebDav,因为我没有管理员权限。此外,有时我会收到method not allowed.css 和 .js 文件。最后,有了上面的配置,一切又开始工作了。

回答by Владимiръ

Decorating one of the action params with [FromBody] solved the issue for me:

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

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

However ASP.NET would infer it correctly if complex object was used in the method parameter:

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

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

回答by Adam Levitt

Another cause of this could be if you don't use the default variable name for the "id" which is actually: id.

另一个原因可能是如果您不使用“id”的默认变量名称,实际上是:id。

回答by Petr ?ugar

In my case the error 405 was invoked by static handler due to route ("api/images") conflicting with the folder of the same name ("~/images").

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

回答by Naveen Kumar G C

You can remove webdav module manually from GUI for the particular in IIS.
1) Goto the IIs.
2) Goto the respective site.
3) Open "Handler Mappings"
4) Scroll downn and select WebDav module. Right click on it and delete it.

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

Note: this will also update your web.config of the web app.

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