Web API PutリクエストでHttp 405 Method Not Allowedエラーが生成される


134

これPUTが私のWeb APIのメソッドの呼び出しです-メソッドの3行目(私はASP.NET MVCフロントエンドからWeb APIを呼び出しています):

ここに画像の説明を入力してください

client.BaseAddressですhttp://localhost/CallCOPAPI/

ここにありcontactUriます:

ここに画像の説明を入力してください

ここにありcontactUri.PathAndQueryます:

ここに画像の説明を入力してください

そして最後に、これが私の405応答です。

ここに画像の説明を入力してください

これが私の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エラーが発生するのはなぜですか?

更新

リクエストに応じて、ここに私の部門のコントローラーコードを示します(私のフロントエンドプロジェクトの部門のコントローラーコードと、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);
        }
    }
}

[HttpPut]アクションメソッド定義の前に使用するべきではありませんか?([HttpPost]および[HttpDelete]適切な場合も同様)
Chris Pratt

@ChrisPratt明確に言う[HttpPut]と、WebAPIコントローラー(ApiController)を使用するということですか?なぜなら、Department(Editメソッド)のフロントエンドコントローラーには[HttpPost]属性があるからです。
マイクマーク

1
@ChrisPrattザ・ValuesController(WebAPIのテンプレートが付属しています1)持っていない[HttpPut]、などが入れ/ポスト/削除方法の属性...
マイク・マークス

はい、私はそれがWeb API側でそれらを必要とすることを合理的に確信しています。個人的には、私は常にWeb APIにAttributeRoutingを使用してきたので、私の思い出は少し大ざっぱです。
クリスプラット

どうやらそれはWebDAVの問題だったようです。ローカルのIIS(Windowsの機能)をチェックして、インストールされていないことを確認し、インストールされていないことを報告しました...とにかく答えを投稿しました。 .config。
マイクマークス

回答:


304

そこで、Windowsの機能をチェックして、WebDAVと呼ばれるものがインストールされていないことを確認しました。とにかく、私は先に進み、web.configに以下を配置しました(念のため、フロントエンドとWebAPIの両方)。これを中に入れました<system.webServer>

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

さらに、web.configハンドラーに次のものを追加する必要があることがよくあります。ババクのおかげで

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

2
ははは...うん...あきらめようとしていた そうそう。でWebDAVが有効になっている必要がありますapplicationhost.config。修正してくれてうれしいです。
2013年

9
あなたは、あまりにも、これを追加する必要があります<handlers><remove name="WebDAV" />...
ババク

14
これを私のWebApi web.configにのみ追加すると、機能しました。
Fordy

IE10ではこの構成がなくても問題なく機能しましたが、Chromeブラウザーで機能させるにはWebApi web.configでのみ行う必要がありました。
Dennis R

1
この本当に迷惑な問題への答えをありがとう。なぜこれが最初に発生するのですか?
スコットウィルソン

23

WebDav-SchmebDav .. ..IDを使用して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でこれを2回賛成できるといいのに
Noel

1
8時間以上の作業が解決に達した後、誰もがweb.configの変更をすすめています。
sairfan 2018年

22

これをに追加しますweb.config。IISにPUT PATCH DELETEそのOPTIONS意味と意味を伝える必要があります。そして、どれ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プロジェクトではなく、Web APIプロジェクトに配置されることを想定していますよね?
Mike Marks

WebDAVをインストールしていません。さらに、上のweb.configコードは、Web APIを呼び出すプロジェクトのweb.configに配置する必要があると言っていますか?
Mike Marks

実際には両方のweb.configsにあります... :(
Mike Marks

ああ...あなたはMVCプロジェクトからWeb APIプロジェクトを参照していると思いました。
2013年

1
DepartmentControllerのコードリストを投稿できますか?それのすべて。問題はWeb APIプロジェクトにあり、それを処理する方法がわかりませんPUT。これが405の意味です。ルーティングを除外するために、GETが機能することを確認します。PS。スクリーンショットではなく、コードを貼り付けてみてください。PPS、使用しないTask.Resultでください。特定の状況では、無関係なスレッドの問題が発生します。代わりに、メソッド全体を非同期に変更するだけです。言うまでもなく、同期のマルチスレッドブロックコード(シングルスレッドより低速)が作成されます。
2013年

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]でアクションパラメータの1つを装飾すると、問題が解決しました。

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

ただし、メソッドパラメータで複雑なオブジェクトが使用されている場合、ASP.NETはそれを正しく推測します。

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


0

私の場合、ルート( "api / images")が同じ名前のフォルダー( "〜/ images")と競合しているため、エラー405が静的ハンドラーによって呼び出されました。


0

IISの特定のGUIからwebdavモジュールを手動で削除できます。
1)IIに移動します。
2)それぞれのサイトに移動します。
3)「ハンドラーマッピング」を開き
ます。4)下にスクロールして、WebDavモジュールを選択します。それを右クリックして削除します。

注:これにより、Webアプリのweb.configも更新されます。


-1

クライアントアプリケーションとサーバーアプリケーションは、次のように同じドメインにある必要があります。

クライアント-ローカルホスト

サーバー-ローカルホスト

ではなく:

クライアント-localhost:21234

サーバー-ローカルホスト


2
私はそうは思いません。サービスを作成する目的は、別のドメインから呼び出すことです
Ozan BAYRAM '14 / 04/15

サーバーから200応答が返されるクロスドメインリクエストを考えていますが、ブラウザは「クロスドメインリクエストなし」ルールを適用し、応答を受け入れません。問題は、405「メソッドが許可されていません」という別の問題への対応に関するものです。
Josh Noe

CORSは405の「許可されていないメソッド」を提供します。例:リクエストURL:testapi.nottherealsite.com/api/Reporting/RunReportリクエストメソッド:OPTIONSステータスコード:405許可されていないメソッドはこちらをご覧くださいstackoverflow.com/questions/12458444/…
レフK.

CORSの問題を参照しています。
user3151766
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.