PUT and Delete not working with ASP.NET WebAPI and Database on Windows Azure

29,333

Solution 1

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>

Solution 2

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!

Share:
29,333
oldsport
Author by

oldsport

Updated on August 02, 2022

Comments

  • oldsport
    oldsport almost 2 years

    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();
        }
    }