Yêu cầu đặt API Web tạo ra lỗi Phương thức http 405 Không được phép


134

Đây là lời gọi đến PUTphương thức trên API Web của tôi - dòng thứ ba trong phương thức (Tôi đang gọi API Web từ giao diện ASP.NET MVC):

nhập mô tả hình ảnh ở đây

client.BaseAddresshttp://localhost/CallCOPAPI/.

Đây là contactUri:

nhập mô tả hình ảnh ở đây

Đây là contactUri.PathAndQuery:

nhập mô tả hình ảnh ở đây

Và cuối cùng, đây là phản hồi 405 của tôi:

nhập mô tả hình ảnh ở đây

Đây là WebApi.config trong dự án API Web của tôi:

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

Tôi đã cố gắng tước xuống con đường đó được thông qua vào PutAsJsonAsyncđể string.Format("/api/department/{0}", department.Id)string.Format("http://localhost/CallCOPAPI/api/department/{0}", department.Id)không có may mắn.

Có ai có ý tưởng tại sao tôi nhận được lỗi 405 không?

CẬP NHẬT

Theo yêu cầu, đây là mã bộ điều khiển Bộ của tôi (tôi sẽ đăng cả mã bộ điều khiển Bộ cho dự án giao diện người dùng của tôi, cũng như mã ApiContoder của Bộ cho WebAPI):

Kiểm soát viên phòng trước

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

Bộ phận API Web API ApiControll

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

Bạn không nên sử dụng [HttpPut]trước khi định nghĩa phương thức hành động? ( [HttpPost][HttpDelete]khi thích hợp là tốt)
Chris Pratt

@ChrisPratt Để rõ ràng, ý bạn là đặt [HttpPut]bộ điều khiển WebAPI (ApiControll), phải không? Bởi vì bộ điều khiển giao diện người dùng cho Cục (phương thức Chỉnh sửa) có [HttpPost]thuộc tính.
Mike Marks

1
@ChrisPratt ValuesControll (cái đi kèm với mẫu WebAPI) không có [HttpPut] , v.v. các thuộc tính trên phương thức Đặt / Đăng / Xóa ..
Mike Marks

Có, tôi chắc chắn chắc chắn rằng nó cần những thứ ở phía API Web. Cá nhân, tôi luôn chỉ sử dụng AttributionRouting cho các công cụ API Web, vì vậy hồi ức của tôi hơi sơ sài.
Chris Pratt

Rõ ràng đó là điều WebDAV .. Tôi đã kiểm tra IIS (Tính năng Windows) cục bộ của mình để đảm bảo nó không được cài đặt và nó nói rằng ... dù sao tôi cũng đã đăng câu trả lời cho điều này, về cơ bản là gỡ bỏ mô-đun WebDAV bên trong web của tôi .config.
Mike Marks

Câu trả lời:


304

Vì vậy, tôi đã kiểm tra các Tính năng của Windows để đảm bảo rằng tôi đã không cài đặt thứ gọi là WebDAV và nó nói rằng tôi không có. Dù sao, tôi đã đi trước và đặt phần sau vào web.config của tôi (cả giao diện người dùng và WebAPI, để chắc chắn), và nó hoạt động ngay bây giờ. Tôi đặt cái này bên trong <system.webServer>.

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

Ngoài ra, thường phải thêm các mục sau vào web.config vào trình xử lý. Cảm ơn Babak

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

2
Haha ... vâng ... tôi sắp bỏ cuộc. Vì vậy, vâng. WebDAV phải được kích hoạt trong của bạn applicationhost.config. Rất vui vì bạn đã sửa nó.
Aron

9
Bạn cũng có thể cần phải thêm điều này:<handlers><remove name="WebDAV" />...
Babak

14
Thêm này chỉ để tôi WebAPI web.config và nó làm việc.
Fordy

Mặc dù trong IE10 nó vẫn hoạt động tốt ngay cả khi không có cấu hình này, tôi chỉ phải làm trong WebApi web.config để làm cho nó hoạt động trong trình duyệt Chrome.
Dennis R

1
Cảm ơn câu trả lời cho vấn đề thực sự khó chịu này. Tại sao điều này xảy ra ở nơi đầu tiên?
Scott Wilson

23

WebDav-SchmebDav .. .. hãy chắc chắn rằng bạn tạo url với ID chính xác. Đừng gửi nó như http://www.fluff.com/api/Fluff?id=MyID , hãy gửi nó như http://www.fluff.com/api/Fluff/MyID .

Ví dụ.

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

{"Data":"1"}

Điều này đã phá vỡ những quả bóng của tôi trong một thời gian nhỏ, bối rối hoàn toàn.


3
Một buster bóng bổ sung cho tôi: Các hành động PUT không thể liên kết dữ liệu với các tham số kiểu nguyên thủy. Tôi phải đổi public int PutFluffColor(int Id, int colorCode)thànhpublic int PutFluffColor(int Id, UpdateFluffColorModel model)
Josh Noe

4
Ước gì tôi có thể nâng cấp điều này hai lần cho WebDav-SchmebDav
Noel

1
sau hơn 8 giờ tiếp cận với giải pháp, mọi người đều khuyến nghị web.config thay đổi rất tuyệt vời, thậm chí không có ai nói về khả năng này.
sairfan

22

Thêm phần này vào bạn web.config. Bạn cần nói với IIS những gì PUT PATCH DELETEOPTIONSphương tiện. Và mà IHttpHandlergọi.

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

Đồng thời kiểm tra xem bạn chưa kích hoạt WebDAV.


Tôi đã có điều đó. Tôi giả sử điều này sẽ được đưa vào dự án API Web, không phải dự án MVC mặt trước của tôi, phải không?
Mike Marks

Tôi chưa cài đặt WebDAV. Ngoài ra, bạn có nói rằng mã web.config ở trên cần phải được đặt trong web.config của dự án thực hiện cuộc gọi đến API Web không?
Mike Marks

Nó thực sự ở cả hai web.configs ... :(
Mike Marks

Ồ không ... Tôi nghĩ rằng bạn đang tham khảo một dự án API Web từ một dự án MVC.
Aron

1
Bạn có thể đăng lên danh sách mã của Bộ điều khiển không? Tất cả. Vấn đề nằm ở dự án API Web của bạn và không biết cách xử lý PUT, đó là ý nghĩa của 405. Kiểm tra rằng GET hoạt động, chỉ để loại trừ định tuyến. Tái bút Cố gắng sao chép mã dán thay vì ảnh chụp màn hình. PPS, KHÔNG SỬ DỤNG Task.Result, bạn sẽ gặp các sự cố luồng không liên quan trong các tình huống nhất định. Thay vào đó, chỉ cần biến toàn bộ phương thức thành async đang chờ. Chưa kể nó tạo ra mã bị chặn đa luồng, đa luồng (chậm hơn so với luồng đơn).
Aron

14

Tôi đang chạy một ứng dụng ASP.NET MVC 5 trên IIS 8.5. Tôi đã thử tất cả các biến thể được đăng ở đây, và đây là giao diện của tôi 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>

Tôi không thể gỡ cài đặt WebDav khỏi Máy chủ của mình vì tôi không có quyền quản trị viên. Ngoài ra, đôi khi tôi nhận được các method not allowedtập tin .css và .js. Cuối cùng, với cấu hình ở trên, mọi thứ bắt đầu hoạt động trở lại.


5

Trang trí một trong các thông số hành động bằng [FromBody] đã giải quyết vấn đề cho tôi:

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

Tuy nhiên ASP.NET sẽ suy luận chính xác nếu đối tượng phức tạp được sử dụng trong tham số phương thức:

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

1

Một nguyên nhân khác của điều này có thể là nếu bạn không sử dụng tên biến mặc định cho "id" thực sự là: id.


0

Trong trường hợp của tôi, lỗi 405 đã được xử lý bởi trình xử lý tĩnh do tuyến đường ("api / hình ảnh") xung đột với thư mục cùng tên ("~ / hình ảnh").


0

Bạn có thể xóa mô-đun webdav theo cách thủ công khỏi GUI cho cụ thể trong IIS.
1) Đi đến II.
2) Đi đến trang web tương ứng.
3) Mở "Trình xử lý ánh xạ"
4) Cuộn xuống và chọn mô-đun WebDav. Nhấp chuột phải vào nó và xóa nó.

Lưu ý: điều này cũng sẽ cập nhật web.config của ứng dụng web.


-1

Ứng dụng khách và ứng dụng máy chủ của bạn phải nằm trong cùng một miền, ví dụ:

khách hàng - localhost

máy chủ - localhost

và không :

khách hàng - localhost: 21234

máy chủ - localhost


2
Tôi không nghĩ vậy. Mục đích của việc tạo ra một dịch vụ là gọi từ một tên miền khác
Ozan BAYRAM

Bạn đang nghĩ đến một yêu cầu tên miền chéo, sẽ cung cấp cho bạn 200 phản hồi từ máy chủ, nhưng trình duyệt sẽ thực thi quy tắc "không yêu cầu tên miền chéo" và không chấp nhận phản hồi. Câu hỏi đề cập đến câu trả lời 405 "Phương pháp không được phép", một vấn đề khác.
Josh Noe

CORS sẽ cung cấp 405 "Phương thức không được phép", ví dụ: URL yêu cầu: testapi.nottherealsite.com/api/Reporting/RunReport Phương thức yêu cầu: TÙY CHỌN Mã trạng thái: 405 Phương thức không được phép vui lòng đọc tại đây stackoverflow.com/questions/12458444/
Lev K.

Bạn đang đề cập đến vấn đề CORS.
user3151766
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.