17

I'm working on a ASP.NET WebAPI project with basic CRUD operations. The project runs locally and has a sample database living inside Windows Azure.

So far, the Http GET and POST works fine, giving me a 200 and 201. But I'm struggling with DELETE and POST. I changed the handlers in the Web.config, removed WebDav, but none of this worked. Also enabling CORS and all sorts of Attributes like [AcceptVerbs] didn't work.

Any idea what I am doing wrong?

Fiddler Raw Output:

HTTP/1.1 405 Method Not Allowed
Cache-Control: no-cache
Pragma: no-cache
Allow: GET
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcTWFyY1xPbmVEcml2ZVxEb2t1bWVudGVcRmlcVnNQcm9qZWt0ZVxONTIwMTQwODI1XE41XE41XGFwaVxwcm9kdWN0XDEwODM=?=
X-Powered-By: ASP.NET
Date: Sun, 14 Sep 2014 15:00:43 GMT
Content-Length: 75

{"Message":"The requested resource does not support http method 'DELETE'."} 

Web.config:

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <remove name="WebDAVModule" />
    </modules>
    <handlers>
      <remove name="WebDAV" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT" type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
 </system.webServer>

Controller:

 public class ProductController : BaseApiController
    {
        public ProductController(IRepository<Product> repo)
            : base(repo)
        {

        }

        [HttpGet]
        public IEnumerable<Product> Get()
        {
            //...
        }

        [HttpGet]
        public Product Get(int id)
        {
            //...
        }

        [HttpPost]
        public HttpResponseMessage Post([FromBody] Product product)
        {
           //...
        }

        [HttpPut]
        public HttpResponseMessage Put(int productId, [FromBody] Product product)
        {
            //..
        }

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

    }

Routing & Formatters:

 public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));


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

        // Custom Formatters:
        config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(
            config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml"));

        var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
        jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
}
2
  • Why are you calling attribute routing but you configure product route using pre WebApi2 way of configuring a route? Commented Sep 14, 2014 at 15:46
  • It`s a leftover and shouldn't be there. I update it. thx Commented Sep 14, 2014 at 15:57

3 Answers 3

28

Finally I found what I messed up. The naming of the Id (productId) in both controller methods (Post and Put) must be the same as in the customized routing (id). When I changed it from productId to id both POST and PUT worked in fiddler. After that I switched back my Web.config settings to the default one. This is what I changed:

Controller:

    [HttpPut]
    public HttpResponseMessage Put(int id, [FromBody] Product product)
    {
        //..
    }

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

Web.config:

<system.webServer>
<modules>
  <remove name="FormsAuthentication" />
</modules>
<handlers>
  <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" />
</handlers>

Sign up to request clarification or add additional context in comments.

2 Comments

If using the build-in default routing, the parameter name must also be "id".
I did not have handlers in my web.config file, adding it helped me out as well, thanks
12

The "Attribute Routing in ASP.NET Web API 2" (20-Jan-2014) article tells us the following;

Routing is how Web API matches a URI to an action. Web API 2 supports a new type of routing, called attribute routing.

( See: "Attribute Routing in ASP.NET Web API 2" )

So, as of Web API 2, you can also fix it by adding the route attribute [to the method in question] with the placeholder named as you wish.

[HttpDelete]
[Route("api/product/{productId}")]
public HttpResponseMessage Delete(int productId)
{
    if (values.Count > productId) {
        values.RemoveAt(productId);
    }
}

Tested this in my own code, because I got hit with the same problem, and it worked like a charm!

2 Comments

In the code above, why couldn't productId be more than values.Count and still be valid. As far as I can see, using this if statement would fail eventually.
@KeenanStewart The code is just a quick & dirty sample. This is about the attribute routing.
0

Try adding this below code in your WebConfig file:

<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>

I also got the same issue, by doing this it got resolved!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.