Web API Put Request bir Http 405 Yöntemine İzin Verilmez hatası oluşturur


134

İşte PUTbenim Web API yönteminde çağrı - yöntem üçüncü satır (Ben bir ASP.NET MVC ön ucundan Web API çağırıyorum):

resim açıklamasını buraya girin

client.BaseAddressolduğunu http://localhost/CallCOPAPI/.

İşte contactUri:

resim açıklamasını buraya girin

İşte contactUri.PathAndQuery:

resim açıklamasını buraya girin

Ve son olarak, 405 yanıtım:

resim açıklamasını buraya girin

İşte Web API projemdeki 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);

Ben parametre olarak aktarılıyor yolda sıyırma denedim PutAsJsonAsyncetmek string.Format("/api/department/{0}", department.Id)ve string.Format("http://localhost/CallCOPAPI/api/department/{0}", department.Id)hiç şansım.

405 hatasını neden aldığım konusunda bir fikriniz var mı?

GÜNCELLEME

İsteğe bağlı olarak, burada Departman denetleyici kodum (hem ön uç projem için Departman denetleyici kodunu hem de WebAPI için Departman ApiController kodunu göndereceğim):

Ön Uç Departman Denetleyicisi

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 Bölümü 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]İşlem yöntemi tanımından önce kullanmamalısınız ? ( [HttpPost]ve [HttpDelete]uygun olduğu yerde)
Chris Pratt

@ChrisPratt Açık olmak gerekirse [HttpPut], WebAPI denetleyicisini (ApiController) takmak istiyorsun, değil mi? Çünkü Departman için ön uç kontrolörü (Düzenle yöntemi) bir [HttpPost]özniteliğe sahiptir.
Mike Marks

1
@ChrisPratt ValuesController (WebAPI şablonuyla birlikte gelen) [HttpPut], Put / Post / Delete yöntemlerinde vb. Özelliklere sahip değildir .
Mike Marks

Evet, Web API tarafındakiler gerektirdiğinden eminim. Şahsen, ben her zaman sadece Web API şeyler için AttributeRouting kullandım, bu yüzden hatırlama biraz kabataslak.
Chris Pratt

Görünüşe göre WebDAV şeydi .. Yüklenmediğinden emin olmak için yerel IIS'mi (Windows Özellikleri) kontrol ettim ve olmadığını söyledi ... Her neyse, buna bir cevap gönderdim, temelde web'imdeki WebDAV modülünü kaldırdım .Config.
Mike Marks

Yanıtlar:


304

Bu nedenle, WebDAV adlı bu şeyin yüklü olmadığından emin olmak için Windows Özelliklerini kontrol ettim ve öyle olmadığını söyledim. Her neyse, devam ettim ve web.config dosyasına (hem ön uç hem de WebAPI, sadece emin olmak için) aşağıdakileri yerleştirdim ve şimdi çalışıyor. Bunu içine yerleştirdim <system.webServer>.

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

Ayrıca, genellikle web.configişleyicilere aşağıdakileri eklemek gerekir . Babak'a teşekkürler

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

2
Haha ... evet ... pes etmek üzereydim. Yani evet. WebDAV'nızda etkinleştirilmiş olmalıdır applicationhost.config. Düzeltmene sevindim.
Aron

9
Ayrıca şunu da eklemeniz gerekebilir:<handlers><remove name="WebDAV" />...
Babak

14
Bunu sadece WebApi web.config dosyasına ekledim ve çalıştı.
14'te Fordy

IE10'da bu yapılandırma olmadan bile iyi çalışmasına rağmen, Chrome tarayıcısında çalışmasını sağlamak için yalnızca WebApi web.config dosyasında yapmam gerekiyordu.
Dennis R

1
Bu gerçekten sinir bozucu sorunun cevabı için teşekkürler. Bu neden ilk etapta gerçekleşiyor?
Scott Wilson

23

WebDav-SchmebDav .. .. kimliğine sahip URL'yi doğru oluşturduğunuzdan emin olun. Gibi göndermeyin http://www.fluff.com/api/Fluff?id=MyID gibi göndermek http://www.fluff.com/api/Fluff/MyID .

Örneğin.

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

{"Data":"1"}

Bu toplarımı küçük bir sonsuzluk, tamamen utanç için yakıyordu.


3
Benim için ek bir top kırıcı: PUT eylemleri, verileri ilkel tip parametrelerine bağlayamaz. Ben değiştirmek zorunda public int PutFluffColor(int Id, int colorCode)içinpublic int PutFluffColor(int Id, UpdateFluffColorModel model)
Josh Noe

4
WebDav-SchmebDav için iki kez bu oyu açabilseydim
Noel

1
8 saatten fazla çalışma çözümüne ulaştıktan sonra, her biri web.config'in o kadar şaşırtıcı olduğunu değiştirir ki, hiç kimse bu olasılık hakkında konuşmadı.
sairfan

22

Blogunuza bu ekleyin web.config. IIS ne anlatmak gerekir PUT PATCH DELETEve OPTIONSaraçlar. Ve hangisini IHttpHandlerçağırmak için.

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

Ayrıca WebDAV'ın etkin olmadığını kontrol edin.


Bende zaten var. Bunun ön uç MVC projeme değil, Web API projesine konulacağını varsayıyorum, değil mi?
Mike Marks

WebDAV yüklü değil. Ayrıca, yukarıdaki web.config kodunun Web API'sını çağıran projenin web.config dosyasına yerleştirilmesi gerektiğini mi söylüyorsunuz?
Mike Marks

Aslında her iki web.configs de ... :(
Mike Marks

Oh hayır ... Bir MVC projesinden bir Web API projesine başvurduğunuzu sanıyordum.
Aron

1
DepartmentController'ın kod listesini kaydedebilir misiniz? Hepsini. Sorun Web API projenizde yatıyor ve nasıl ele alınacağını bilmiyor PUT, 405'in anlamı bu. GET'in çalışıp çalışmadığını kontrol edin, yalnızca yönlendirmeyi dışlamak için. PS. Ekran görüntüsü yerine yapıştırma kodunu kopyalamaya çalışın. PPS, KULLANMAYIN Task.Result, bazı durumlarda ilgisiz iplik sorunları elde edersiniz. Bunun yerine tüm yöntemi zaman uyumsuz hale getirin. Senkronize değil, çok iş parçacıklı engellenmiş kod oluşturur (tek iş parçacıktan daha yavaş).
Aron

14

IIS 8.5 üzerinde bir ASP.NET MVC 5 uygulaması çalıştırıyorum. Burada yayınlanan tüm varyasyonları denedim ve bu benim web.configgibi görünüyor:

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

Yönetici ayrıcalıklarına sahip olmadığım için WebDav'ı Sunucumdan kaldıramadım. Ayrıca, bazen method not allowed.css ve .js dosyalarını alıyordum . Sonunda, yukarıdaki yapılandırma ile her şey tekrar çalışmaya başladı.


5

Eylem parametrelerinden birini [FromBody] ile süslemek sorunu benim için çözdü:

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

Ancak method parametresinde karmaşık bir nesne kullanılmışsa ASP.NET bunu doğru bir şekilde çıkarır:

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

1

Bunun bir başka nedeni, "id" için varsayılan değişken adını kullanmamanız olabilir.


0

Benim durumumda 405 hatası, aynı addaki ("~ / images") klasörüyle çakışan rota ("api / images") nedeniyle statik işleyici tarafından çağrıldı.


0

Webdav modülünü IIS'deki özel GUI'den manuel olarak kaldırabilirsiniz.
1) II'lere gidin.
2) İlgili bölgeye gidin.
3) "Handler Mappings" i açın
4) Aşağı kaydırın ve WebDav modülünü seçin. Üzerine sağ tıklayın ve silin.

Not: Bu işlem web uygulamasının web.config dosyasını da güncelleyecektir.


-1

İstemci uygulamanız ve sunucu uygulamanız aynı etki alanında olmalıdır, örneğin:

istemci - localhost

sunucu - localhost

ve yok :

istemci - localhost: 21234

sunucu - localhost


2
Ben öyle düşünmüyorum. Hizmet yaratmanın amacı başka bir alandan aramak
Ozan BAYRAM

Sunucudan 200 yanıt verecek bir etki alanları arası istek düşünüyorsunuz, ancak tarayıcı "etki alanları arası istek yok" kuralını uygulayacak ve yanıtı kabul etmeyecektir. Soru, farklı bir sorun olan 405 "Yönteme İzin Verilmiyor" yanıtıyla ilgili.
Josh Noe

CORS, 405 "Yönteme İzin Verilmiyor " verecek, örneğin: URL iste: testapi.nottherealsite.com/api/Reporting/RunReport İstek Yöntemi: SEÇENEKLER Durum Kodu: 405 Yönteme İzin Verilmiyor lütfen burayı okuyun stackoverflow.com/questions/12458444/…
Lev K.

CORS sorununa atıfta bulunuyorsunuz.
user3151766
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.