3

I have created WCF RESTful service which uses simple database behind it and just trying to working on put, get,post and delete items. Right now post ,put and get is working. But the delete is n't working. Some forums telling that I need to disable the WebDAV module. I did that and then I got PUT to work. But I can not get DELETE to work. Whenever I call DELETE verb through my service I got the following error:

The remote server returned an unexpected response: (405) Method Not Allowed.

Can any one help me on this?

Ravikumar
  • 31
  • 1
  • 2

4 Answers4

2

I have not yet found one comprehensive answer for PUT and DELETE being overridden and returning 405s for restful WCF services anywhere else, so I'm going to post it here.

This problem can be addressed easily by simply uninstalling WebDAV from the machine via either the role manager (on a server) or through Add/Remove windows features. If that is an acecceptible approach, you can stop reading now.

The commonly recommended fix here is to simply remove the WebDAV module from your site, appending something like the following to your web.config:

  <system.webServer>
        <modules>
            <remove name="WebDAVModule" />
        </modules>
  </system.webServer>

The problem here is that now your WCF app has no way of knowing how to handle PUT and DELETE at all. So to solve this, some solutions suggest making the follwing modification:

<modules runAllManagedModulesForAllRequests="true">
 <system.webServer>
       <modules>
           <remove name="WebDAVModule" />
       </modules>
 </system.webServer>

This may be satisfactory for most, but I did not like the idea of having our service uselessly loading everything up for every call when it wasn't necessary. So I refined the approach a bit by manually mapping the extensionless URL handler to all HTTP verbs (probably could be refined to just the necessary ones)

  <system.webServer>
        <modules>
            <remove name="WebDAVModule" />
        </modules>
        <handlers>
            <remove name="WebDAV" />
            <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
            <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0" />
        </handlers>
  </system.webServer>

I only tested this on R2 64 and 7 64, so ymmv. But hopefully this helps.

ptrc
  • 714
  • 6
  • 15
0

I've used the WebChannelFactory approach in the client side to consume the REST service. I've created the Service Reference using the normal "Add Service Reference" approach. This doesn't add [WebGet(UriTemplate = "/")].

After I added these for all Operation on Client side proxy class just like the Service Contract, it started working.

Adi Lester
  • 23,781
  • 12
  • 86
  • 106
0

Adding Codes to the Web.config File

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </configSections>
    <appSettings>
        <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    </appSettings>
    <system.web>
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
    </system.web>
    <system.serviceModel>
        <behaviors >
            <serviceBehaviors>
                <behavior  name="http">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                </behavior>
            </serviceBehaviors>
            <endpointBehaviors>
                <behavior name="www">
                    <webHttp/>
                </behavior>
            </endpointBehaviors>
        </behaviors>
        <protocolMapping>
            <add binding="basicHttpsBinding" scheme="https" />
        </protocolMapping>
        <services>
            <service behaviorConfiguration="http" name="REST.CRUD.Alternativ">
                <endpoint address=""
                                    binding="webHttpBinding"
                                    behaviorConfiguration="www"
                                    contract="REST.CRUD.IAlternativ"
                                    bindingConfiguration="rest">
                </endpoint>
                <endpoint address="mex"
                                    binding="mexHttpBinding"
                                    contract="IMetadataExchange">
                </endpoint>
            </service>
        </services>
        <bindings>
            <webHttpBinding>
                <binding allowCookies="true" name="rest">
                    <security mode="None"></security>
                </binding>
            </webHttpBinding>
        </bindings>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
        <directoryBrowse enabled="true" />
        <security>
            <requestFiltering>
                <verbs>
                    <add verb="GET" allowed="true" />
                    <add verb="POST" allowed="true" />
                    <add verb="DELETE" allowed="true" />
                    <add verb="PUT" allowed="true" />
                </verbs>
            </requestFiltering>
        </security>
    </system.webServer>
    <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
            <parameters>
                <parameter value="v11.0" />
            </parameters>
        </defaultConnectionFactory>
        <providers>
            <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
        </providers>
    </entityFramework>
    <connectionStrings>
        <add name="KendoDB" connectionString="Data Source=(localDB)\v11.0;Initial Catalog=Kendo;Integrated Security=True;Pooling=False" providerName="System.Data.SqlClient" />
    </connectionStrings>
</configuration>

PersonDTO

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;

namespace REST.CRUD
{
    public class PersonDTO
    {
        public int ID { get; set; }
        public string firstName { get; set; }
        public string lastName { get; set; }
    }

    public class KendoContext : DbContext
    {
        public  KendoContext():base("KendoDB"){}
        public DbSet<PersonDTO> PersonDTOs { get; set; }
    }
}

IAlternativ.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Web.Services;


namespace REST.CRUD
{
    [ServiceContract]
    public interface IAlternativ
    {
        [WebInvoke(Method = "POST",
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        List<PersonDTO> GetAll();

        [WebInvoke(Method = "GET",
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        PersonDTO Get(int ID, string f, string l);

        [WebInvoke(Method = "DELETE", 
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        String Delete(int ID, string f, string l);

        [WebInvoke(Method = "PUT", 
            BodyStyle = WebMessageBodyStyle.WrappedRequest,
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json)]
        [OperationContract]
        String Update(int ID, string f, string l);
    }
}

Alternativ.svc.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Web.Script.Services;
using System.Web.Services;


namespace REST.CRUD
{
    public class Alternativ : IAlternativ
    {
        public List<PersonDTO> GetAll()
        {
            var db = new KendoContext();
            return db.PersonDTOs.Select(c => c).ToList();
        }

        public PersonDTO Get(int ID, string f, string l)
        {
            var db = new KendoContext();
            return db.PersonDTOs.Where(c => c.ID == ID).Select(c => c).First();
        }

        public String Delete(int ID, string f, string l)
        {
            //Delete Code
            return "OK";
        }

        public String Update(int ID, string f, string l)
        {
            //Update Code
            return "OK";
        }
    }
}

[Build and Run the WCF Project(F5)].

Add jquery to DOM for test(Paste to Console)

(function() {
  if (! window.jQuery ) {
    var s = document.createElement('script');
    s.type = 'text/javascript';
    s.async = true;
    s.src = '//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js'; 
    (document.getElementsByTagName('head')[0] ||
      document.getElementsByTagName('body')[0]).appendChild(s);
  }
}());

Add functions to Console

function POST(){
$.ajax({
      type: "POST", //GET,POST,PUT or DELETE verb
      url: "/Alternativ.svc/GetAll", // Location of the service
      data: '{"ID":"1"}', //Data to be sent to server
      dataType: "json", // content type sent to server
      contentType: "application/json; charset=utf-8", //Expected data format from server
      processdata: false, //True or False
      success: function (response) {
        console.log(response);
      },
      error: function (xhr, ajaxOptions, thrownError) {
        alert(xhr.statusText);
      }
});
}
function GET(){
$.ajax({
      type: "GET", //GET,POST,PUT or DELETE verb
      url: "/Alternativ.svc/Get", // Location of the service
      data: {ID:1}, //Data to be sent to server
      dataType: "json", // content type sent to server
      contentType: "application/json; charset=utf-8", //Expected data format from server
      processdata: true, //True or False
      success: function (response) {
        console.log(response);
      },
      error: function (xhr, ajaxOptions, thrownError) {
        alert(xhr.statusText);
      }
});
}
function DELETE(){
$.ajax({
      type: "DELETE", //GET,POST,PUT or DELETE verb
      url: "/Alternativ.svc/Delete", // Location of the service
      data: '{"ID":"1"}', //Data to be sent to server
      dataType: "json", // content type sent to server
      contentType: "application/json; charset=utf-8", //Expected data format from server
      processdata: false, //True or False
      success: function (response) {
        console.log(response);
      },
      error: function (xhr, ajaxOptions, thrownError) {
        alert(xhr.statusText);
      }
});
}
function PUT(){
$.ajax({
      type: "PUT", //GET,POST,PUT or DELETE verb
      url: "/Alternativ.svc/Update", // Location of the service
      data: '{"ID":"1"}', //Data to be sent to server
      dataType: "json", // content type sent to server
      contentType: "application/json; charset=utf-8", //Expected data format from server
      processdata: false, //True or False
      success: function (response) {
        console.log(response);
      },
      error: function (xhr, ajaxOptions, thrownError) {
        alert(xhr.statusText);
      }
});
}

Call functions

DELETE();
PUT();
GET();
POST();
Ali.Asadi
  • 160
  • 4
  • 12
0

There seems to have some similar questions on StackOverflow already:

WCF Service 405 Method Not Allowed Exception

WCF The request failed with HTTP status 405: Method Not Allowed

WCF Service Returning "Method Not Allowed"

Hope one of them helps.

Community
  • 1
  • 1
Bruce Li
  • 445
  • 3
  • 10
  • 27