웹 API 넣기 요청이 Http 405 메소드 허용되지 않음 오류를 생성 함


134

다음 PUT은 내 웹 API 에서 메소드에 대한 호출입니다. 메소드의 세 번째 줄입니다 (ASP.NET MVC 프론트 엔드에서 웹 API를 호출합니다).

여기에 이미지 설명을 입력하십시오

client.BaseAddress입니다 http://localhost/CallCOPAPI/.

여기 있습니다 contactUri:

여기에 이미지 설명을 입력하십시오

여기 있습니다 contactUri.PathAndQuery:

여기에 이미지 설명을 입력하십시오

마지막으로 405 응답입니다.

여기에 이미지 설명을 입력하십시오

내 웹 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 오류가 발생하는 이유를 아는 사람이 있습니까?

최신 정보

요청에 따라 부서 컨트롤러 코드는 다음과 같습니다 (프런트 엔드 프로젝트의 부서 컨트롤러 코드와 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 });
        }
    }
}

웹 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]적절한 경우)
Chris Pratt

@ChrisPratt 분명하게 말하면 [HttpPut]WebAPI 컨트롤러 (ApiController)를 사용하는 것입니까? 부서 용 프런트 엔드 컨트롤러 (편집 방법)에 [HttpPost]특성 이 있기 때문입니다.
Mike Marks

1
@ChrisPratt ValuesController (WebAPI 템플릿과 함께 제공되는)에는 [HttpPut]Put / Post / Delete 메소드에 속성 등 이 없습니다 .
Mike Marks

예, 웹 API 측에 필요하다는 것이 합리적입니다. 개인적으로, 나는 항상 웹 API에 대해 AttributeRouting을 사용했기 때문에 내 기억은 약간 스케치 적입니다.
Chris Pratt

분명히 WebDAV 일이었습니다 .. 로컬 IIS (Windows 기능)가 설치되어 있지 않은지 확인했지만 설치되지 않았다고 대답했습니다 ... 어쨌든 기본적으로 웹 내부에서 모듈 WebDAV를 제거했습니다. .config.
Mike Marks

답변:


304

그래서 WebDAV라는이 설치되어 있지 않은지 Windows 기능을 확인했지만 설치하지 않았다고 말했습니다. 어쨌든, 나는 계속해서 내 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
또한 이것을 추가해야 할 수도 있습니다 :<handlers><remove name="WebDAV" />...
Babak

14
내 WebApi web.config 에만 추가 하고 작동했습니다.
Fordy

IE10에서는이 구성이 없어도 정상적으로 작동했지만 Chrome 브라우저에서 작동하도록 WebApi web.config에서만 수행해야했습니다.
Dennis R

1
이 성가신 문제에 대한 답변에 감사드립니다. 왜 이런 일이 처음에 발생합니까?
Scott Wilson

23

WebDav-SchmebDav .. .. 아이디가 올바른 URL을 작성하십시오. 처럼 보내지 마십시오 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)
Josh Noe

4
WebDav-SchmebDav
Noel

1
8 시간 이상의 작업이 솔루션에 도달 한 후, 모든 사람들은 web.config가 너무 놀랍게 변화 할 것을 권장하고 있습니다.
sairfan

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가 활성화되어 있지 않은지 확인하십시오.


이미 가지고 있습니다. 나는 이것이 내 프론트 엔드 MVC 프로젝트가 아닌 웹 API 프로젝트에 넣어야한다고 가정하고 있습니다.
Mike Marks

WebDAV가 설치되어 있지 않습니다. 또한 위의 web.config 코드를 웹 API를 호출하는 프로젝트의 web.config에 배치해야한다고 말하는가?
Mike Marks

그것은 실제로 두 web.configs에 있습니다 ... :(
Mike Marks

아뇨. MVC 프로젝트에서 웹 API 프로젝트를 참조한다고 생각했습니다.
Aron

1
DepartmentController의 코드 목록을 게시 할 수 있습니까? 그것의 모든. 문제는 웹 API 프로젝트에 있으며 처리 방법을 모릅니다 PUT. 즉 405의 의미입니다. 라우팅을 배제하기 위해 GET이 작동하는지 확인하십시오. 추신. 스크린 샷이 아닌 붙여 넣기 코드를 복사 해보십시오. PPS, 사용하지 마십시오 Task.Result. 특정 상황에서 관련이없는 스레딩 문제가 발생합니다. 대신 전체 메소드를 async await로 바꾸십시오. 말할 것도없이 동기식, 다중 스레드 차단 코드 (단일 스레드보다 느림)를 만듭니다.
Aron

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

필자의 경우 같은 이름의 폴더 ( "~ / images")와 충돌하는 경로 ( "api / images")로 인해 정적 핸들러에서 오류 405가 호출되었습니다.


0

IIS의 특정 GUI에서 webdav 모듈을 수동으로 제거 할 수 있습니다.
1) II로 이동하십시오.
2) 해당 사이트로 이동하십시오.
3) "핸들러 매핑"을 엽니 다.
4) 아래로 스크롤하여 WebDav 모듈을 선택합니다. 마우스 오른쪽 버튼으로 클릭하고 삭제하십시오.

참고 : 웹 응용 프로그램의 web.config도 업데이트됩니다.


-1

클라이언트 애플리케이션과 서버 애플리케이션은 다음과 같은 도메인에 있어야합니다.

클라이언트-localhost

서버-localhost

아니 :

클라이언트-localhost : 21234

서버-localhost


2
나는 그렇게 생각하지 않습니다. 서비스를 만드는 목적은 다른 도메인에서 전화를하는 것입니다.
Ozan BAYRAM

교차 도메인 요청을 생각하고 있는데 서버에서 200 개의 응답을 제공하지만 브라우저는 "교차 도메인 요청 없음"규칙을 적용하고 응답을 수락하지 않습니다. 이 질문은 다른 문제인 405 "Method Not Allowed"방법에 대한 것입니다.
Josh Noe

요청 URL : CORS (405)는 예를 들어, "방법은 허용되지 않음"줄 것이다 testapi.nottherealsite.com/api/Reporting/RunReport 신청 방법 : 옵션 상태 코드 : 405 방법은 여기를 참조하시기 바랍니다 허용되지 stackoverflow.com/questions/12458444/...
Lev K.

CORS 문제를 참조하고 있습니다.
user3151766
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.