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

时间:2017-08-26 17:52:37

标签: c# asp.net-web-api http-headers asp.net-web-api-routing

我已经检查了Google上的所有答案,并且在ASP.NET Web API中不允许使用StackOverflow for 405方法,并且没有一个解决方案正在运行。

  1. Checked CORS
  2. 检查过WebDAV
  3. 检查HTTPDelete属性
  4. 我正在创建一个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属性添加到我的删除方法中。

    面临的问题是价值控制器删除方法在Fiddler中运行良好,但对于JobDetails控制器我不允许使用405方法。

    我能够做一个GET和POST方法。我也面临与PUT相同的问题。

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

1 个答案:

答案 0 :(得分:1)

它适用于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) {
        //...
    }
}

请注意,在路由到控制器时,它是按惯例或按属性,而不是两者。如果按属性路由到操作,则控制器上的所有其他操作也需要属性路由。