web-dev-qa-db-ja.com

405メソッドは許可されていません-ASP.NETWeb API

GoogleとStackOverflowでASP.NETWeb APIで許可されていない405メソッドのすべての回答を確認しましたが、どのソリューションも機能していません。

  1. チェックされたCORS
  2. WebDAVを確認しました
  3. HTTPDelete属性を確認しました

ASP.NET Web APIを作成していて、2つのダミーコントローラーがあります。

一方のコントローラーにはHTTPDeleteメソッドを使用できますが、もう一方のコントローラーには使用できません。

バリューコントローラー

using System.Collections.Generic;
using System.Web.Http;

namespace JobSite_WebAPI.Controllers
{
  public class ValuesController : ApiController
  {
    List<string> strings = new List<string>()
    {
        "value1", "value2","value3"
    };
    // GET api/values
    public IEnumerable<string> Get()
    {
        return  strings;
    }

    // GET api/values/5
    public string Get(int id)
    {
        return strings[id];
    }

    // DELETE api/values/5
    public void Delete(int id)
    {
        strings.RemoveAt(id);
    }
  }
}

ジョブ詳細コントローラー

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Net;
 using System.Net.Http;
 using System.Web.Http;
 using DataAccess;

 namespace JobSite_WebAPI.Controllers
 {
  public class JobDetailController : ApiController
  {
    public JobDetailController()
    {
        JobSiteEntities entities = new JobSiteEntities();
        entities.Configuration.ProxyCreationEnabled = false;
    }
    public IEnumerable<JobDetail>Get()
    {
        using (JobSiteEntities entities = new JobSiteEntities())
        {
            return entities.JobDetails.ToList();
        }
    }

[HttpGet]
    public HttpResponseMessage Get(int id)
    {
        using (JobSiteEntities entities = new JobSiteEntities())
        {
            var entity = entities.JobDetails.FirstOrDefault(e => e.JOBID == id);
            if (entity != null)
            {
                return Request.CreateResponse(HttpStatusCode.OK, entity);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Job With Id = " + id.ToString() + " not found");
            }
        }
    }


 [HttpGet]
    public HttpResponseMessage RetrieveJobByLocation(string locationName)
    {
        try
        {
            using (JobSiteEntities entities = new JobSiteEntities())
            {
                IEnumerable<JobDetail> jobDetails = entities.JobDetails.Where(e => e.Location.LocationName.ToLower() == locationName).ToList();

                if (jobDetails != null)
                    return Request.CreateResponse(HttpStatusCode.OK, jobDetails);
                else
                    return Request.CreateResponse(HttpStatusCode.NotFound);

            }
        }
        catch(Exception ex)
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest, ex);
        }
    }

    [HttpDelete]
    public HttpResponseMessage Delete(int jobId)
    {
        try
        {
            using (JobSiteEntities entities = new JobSiteEntities())
            {
                var entity = entities.JobDetails.FirstOrDefault(e => e.JOBID == jobId);

                if (entity == null)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound, "Job Id with id " + jobId + "is not found");
                }
                else
                {
                    entities.JobDetails.Remove(entity);
                    entities.SaveChanges();
                    return Request.CreateResponse(HttpStatusCode.OK);
                }
            }
        }
        catch (Exception ex)
        {
            return Request.CreateResponse(HttpStatusCode.BadRequest, ex);
        }
    }
}

}

WebAPIConfig.cs

 var cors = new EnableCorsAttribute("*", "*", "*");
 config.EnableCors(cors);


 // Web API routes
 config.MapHttpAttributeRoutes();

 config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }

        );
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));

Web.Config

 <remove name="WebDAV" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />

CORSを有効にし、WebDAVを無効にしました。また、削除メソッドにHTTPDelete属性を追加しました。

直面している問題は、Value ControllerのDeleteメソッドがFiddlerから正常に機能することですが、JobDetailsControllerの場合は許可されていない405メソッドを取得します。

GETとPOST Method.AmもPUTで同じ問題に直面しています。

fiddlerからのエラーメッセージのスクリーンショットを追加しました。Fiddler URLFiddlerエラーメッセージ

5
BSB

コンベンションベースのルートテンプレート...のため、ValuesControllerで機能します。

_"api/{controller}/{id}" 
_

コントローラーが準拠する_{id}_プレースホルダーがありますが、JobDetailController.Delete(int jobId)jobIdパラメーター名のため、ルートテンプレートと一致しません。これらのパラメータ引数を_int id_に変更して、規則で設定されたルートテンプレートと一致させます。

_[HttpDelete]
public HttpResponseMessage Delete(int id) {
    //...
}
_

それ以外の場合は、config.MapHttpAttributeRoutes()でも有効になっているため、代わりに属性ルーティングを使用できます。

参照: ASP.NET Web API 2の属性ルーティング

_[RoutePrefix("api/JobDetail")] 
public class JobDetailController : ApiController {

    [HttpGet]
    [Route("")] //Matches GET api/jobdetail
    public IEnumerable<JobDetail> Get() {
        //...
    }

    [HttpGet]
    [Route("{id:int}")] //Matches GET api/jobdetail/1
    public HttpResponseMessage Get(int id) {
       //...
    }

    [HttpGet]
    [Route("{locationName}")] //Matches GET api/jobdetail/somewhere
    public HttpResponseMessage RetrieveJobByLocation(string locationName) {
        //...
    }

    [HttpDelete]
    [Route("{jobId:int}")] //Matches DELETE api/jobdetail/1
    public HttpResponseMessage Delete(int jobId) {
        //...
    }
}
_

コントローラにルーティングする場合は、慣例または属性のいずれかであり、両方ではないことに注意してください。属性によってアクションにルーティングする場合、コントローラー上の他のすべてのアクションにも属性ルーティングが必要です。

2
Nkosi