405 方法不允许 - ASP.NET Web API

405 method not allowed - ASP.NET Web API

我已经检查了 Google 和 Whosebug 上关于 ASP.NET Web API 和 none 中不允许的 405 方法的所有答案。

  1. 已检查 CORS
  2. 已检查 WebDAV
  3. 已检查 HTTPDelete 属性

我正在创建一个 ASP.NET Web API 并且有 2 个虚拟控制器。

我可以对一个控制器使用 HTTP Delete 方法,但不能对另一个控制器使用。

值控制器

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.also 在我的删除方法中添加了 HTTPDelete 属性。

我面临的问题是 Value Controller Delete 方法在 Fiddler 中工作正常,但对于 JobDetails Controller,我得到一个不允许的 405 方法。

我可以执行 GET 并且 POST Method.Am 也面临与 PUT 相同的问题。

添加了来自 fiddler 的错误消息屏幕截图。 Fiddler URL Fiddler Error Message

它适用于 ValuesController 因为基于约定的路由模板...

"api/{controller}/{id}" 

有控制器符合的{id}占位符,而JobDetailController.Delete(int jobId)由于jobId参数名称而与路由模板不匹配。将这些参数参数更改为 int id 以使其匹配约定设置的路由模板。

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

否则您可以使用属性路由,因为它也可以通过 config.MapHttpAttributeRoutes()

启用

参考:Attribute Routing in 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) {
        //...
    }
}

请注意,当路由到控制器时,它要么通过约定要么通过属性,而不是两者。如果通过属性路由到一个动作,那么控制器上的所有其他动作也需要属性路由。