2013-10-03 119 views
102

下面是對我的Web API - 方法中的第三行(我從ASP.NET MVC前端調用Web API)PUT方法的調用:Web API Put請求生成HTTP 405方法不允許錯誤

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錯誤?

UPDATE

根據要求,這是我司控制器代碼(我將發佈兩個部門控制代碼爲我的前端項目,以及作爲的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); 
     } 
    } 
} 
+0

不應該在動作方法定義之前使用'[HttpPut]'嗎? ('[HttpPost]'和'[HttpDelete]'在適當的位置) –

+0

@ChrisPratt爲了清楚起見,你的意思是把'[HttpPut]'放在WebAPI控制器(ApiController)上,對吧?由於Department(Edit方法)的前端控制器具有'[HttpPost]'屬性。 –

+1

@ChrisPratt ValuesController(與WebAPI模板一起提供的)在Put/Post/Delete方法中沒有'[HttpPut]'等屬性.. –

回答

231

因此,我檢查了Windows功能,以確保我沒有安裝這個名爲WebDAV的東西,它說我沒有。無論如何,我繼續,並將以下內容放在我的web.config(前端和WebAPI,只是可以肯定),現在它可以工作。我把它放在<system.webServer>裏面。

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

此外,經常需要在處理程序中添加以下內容到web.config。感謝Babak

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

哈哈......是的......我正要放棄。嗯是的。 WebDAV必須已在你的'applicationhost.config'中啓用。很高興你解決了它。 – Aron

+9

您可能還需要添加此項:' ... – Babak

+10

將_only_添加到我的WebApi web.config中並且它工作正常。 – Fordy

19

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

同時檢查您沒有啓用WebDAV。

+0

我已經有了。我假設這是要放在Web API項目中,而不是我的前端MVC項目,對嗎? –

+0

你認爲是錯的。您的Web API web.config不執行任何操作。 – Aron

+0

我沒有安裝WebDAV。另外,你是否在說網絡。上面的配置代碼需要放在調用Web API的項目的web.config中? –

20

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"} 

這是一個小永恆我的球破壞,完全尷尬。

+1

對我來說,一個額外的ball buster:PUT動作無法將數據綁定到原始類型參數,我必須更改'public int PutFluffColor(int Id ,int colorCode)'to'public int PutFluffColor(int Id,UpdateFluffColorModel model)' –

+0

希望我可以爲WebDav-SchmebDav註冊這個兩次 – Noel

0

您的客戶端應用程序和服務器應用程序必須在同一個域,例如:

客戶 - 本地主機

服務器 - 本地主機

,而不是:

客戶 - 本地主機:21234

服務器 - localhost

+2

我不這麼認爲。創建服務的目的是從另一個域調用 –

+0

'想到一個跨域請求,它會給你200個來自服務器的響應,但是瀏覽器會強制執行它的「不允許跨域請求」規則並且不接受響應。問題是指405「不允許的方法「響應,另一個問題 –

+0

CORS將給405」不允許的方法「,例如: 要求est網址:http://testapi.nottherealsite.com/api/Reporting/RunReport 請求方法:選項 狀態代碼:405方法不允許 請在這裏閱讀http:// stackoverflow。分享-ON-IIS7使交產地資源COM /問題/ 12458444 / –

10

我在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。最後,隨着上面的配置設置一切再次開始工作。

5

裝飾用[FromBody]的動作則params的一個解決這個問題對我來說:

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

在我的情況下,由於route(「api/images」)與相同名稱的文件夾(「〜/ images」)衝突,靜態處理程序調用了錯誤405。

相關問題