The remote server returned an error: (405) Method Not Allowed. WCF REST Service

106,649

Solution 1

First thing is to know the exact URL for your REST Service. Since you have specified http://localhost:2517/Service1/Create now just try to open the same URL from IE and you should get method not allowed as your Create Method is defined for WebInvoke and IE does a WebGet.

Now make sure that you have the SampleItem in your client app defined in the same namespace on your server or make sure that the xml string you are building has the appropriate namespace for the service to identify that the xml string of sample object can be deserialized back to the object on server.

I have the SampleItem defined on my server as shown below:

namespace SampleApp
{
    public class SampleItem
    {
        public int Id { get; set; }
        public string StringValue { get; set; }            
    }    
}

The xml string corresponding to my SampleItem is as below:

<SampleItem xmlns="http://schemas.datacontract.org/2004/07/SampleApp" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Id>6</Id><StringValue>from client testing</StringValue></SampleItem>

Now i use the below method to perform a POST to the REST service :

private string UseHttpWebApproach<T>(string serviceUrl, string resourceUrl, string method, T requestBody)
        {
            string responseMessage = null;
            var request = WebRequest.Create(string.Concat(serviceUrl, resourceUrl)) as HttpWebRequest;
            if (request != null)
            {
                request.ContentType = "application/xml";
                request.Method = method;
            }

            //var objContent = HttpContentExtensions.CreateDataContract(requestBody);
            if(method == "POST" && requestBody != null)
            {
                byte[] requestBodyBytes = ToByteArrayUsingDataContractSer(requestBody);
                request.ContentLength = requestBodyBytes.Length;
                using (Stream postStream = request.GetRequestStream())
                    postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);                    
            }

            if (request != null)
            {
                var response = request.GetResponse() as HttpWebResponse;
                if(response.StatusCode == HttpStatusCode.OK)
                {
                    Stream responseStream = response.GetResponseStream();
                    if (responseStream != null)
                    {
                        var reader = new StreamReader(responseStream);

                        responseMessage = reader.ReadToEnd();                        
                    }
                }
                else
                {
                    responseMessage = response.StatusDescription;
                }
            }
            return responseMessage;
        }

private static byte[] ToByteArrayUsingDataContractSer<T>(T requestBody)
        {
            byte[] bytes = null;
            var serializer1 = new DataContractSerializer(typeof(T));            
            var ms1 = new MemoryStream();            
            serializer1.WriteObject(ms1, requestBody);
            ms1.Position = 0;
            var reader = new StreamReader(ms1);
            bytes = ms1.ToArray();
            return bytes;
        }

Now i call the above method as shown:

SampleItem objSample = new SampleItem();
objSample.Id = 7;
objSample.StringValue = "from client testing";
string serviceBaseUrl = "http://localhost:2517/Service1";
string resourceUrl = "/Create";
string method="POST";

UseHttpWebApproach<SampleItem>(serviceBaseUrl, resourceUrl, method, objSample);

I have the SampleItem object defined in the client side as well. If you want to build the xml string on the client and pass then you can use the below method:

private string UseHttpWebApproach(string serviceUrl, string resourceUrl, string method, string xmlRequestBody)
            {
                string responseMessage = null;
                var request = WebRequest.Create(string.Concat(serviceUrl, resourceUrl)) as HttpWebRequest;
                if (request != null)
                {
                    request.ContentType = "application/xml";
                    request.Method = method;
                }

                //var objContent = HttpContentExtensions.CreateDataContract(requestBody);
                if(method == "POST" && requestBody != null)
                {
                    byte[] requestBodyBytes = ASCIIEncoding.UTF8.GetBytes(xmlRequestBody.ToString());
                    request.ContentLength = requestBodyBytes.Length;
                    using (Stream postStream = request.GetRequestStream())
                        postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);                    
                }

                if (request != null)
                {
                    var response = request.GetResponse() as HttpWebResponse;
                    if(response.StatusCode == HttpStatusCode.OK)
                    {
                        Stream responseStream = response.GetResponseStream();
                        if (responseStream != null)
                        {
                            var reader = new StreamReader(responseStream);

                            responseMessage = reader.ReadToEnd();                        
                        }
                    }
                    else
                    {
                        responseMessage = response.StatusDescription;
                    }
                }
                return responseMessage;
            }

And the call to the above method would be as shown below:

string sample = "<SampleItem xmlns=\"http://schemas.datacontract.org/2004/07/XmlRestService\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><Id>6</Id><StringValue>from client testing</StringValue></SampleItem>";   
string serviceBaseUrl = "http://localhost:2517/Service1";
string resourceUrl = "/Create";
string method="POST";             
UseHttpWebApproach<string>(serviceBaseUrl, resourceUrl, method, sample);

NOTE: Just make sure that your URL is correct

Solution 2

Are you running WCF application for the first time?

run below command to register wcf.

"%WINDIR%\Microsoft.Net\Framework\v3.0\Windows Communication Foundation\ServiceModelReg.exe" -r

Solution 3

After spending 2 days on this, using VS 2010 .NET 4.0, IIS 7.5 WCF and REST with JSON ResponseWrapped, I finally cracked it by reading from "When investigating further..." here https://sites.google.com/site/wcfpandu/useful-links

The Web Service Client code generated file Reference.cs doesn't attribute the GET methods with [WebGet()], so attempts to POST them instead, hence the InvalidProtocol, 405 Method Not Allowed. Problem is though, this file is regenerated when ever you refresh the service reference, and you also need a dll reference to System.ServiceModel.Web, for the WebGet attribute.

So I've decided to manually edit the Reference.cs file, and keep a copy. Next time I refresh it, I'll merge my WebGet()s back in.

The way I see it, it's a bug with svcutil.exe not recognising that some of the service methods are GET and not just POST, even though the WSDL and HELP that the WCF IIS web service publishes, does understand which methods are POST and GET??? I've logged this issue with Microsoft Connect.

Share:
106,649
Praneeth
Author by

Praneeth

I am a developer interested in exploring better ways to code.

Updated on August 19, 2020

Comments

  • Praneeth
    Praneeth over 3 years

    This question is already asked elsewhere but those things are not the solutions for my issue.

    This is my service

    [WebInvoke(UriTemplate = "", Method = "POST")]
    public SampleItem Create(SampleItem instance)
    {
        // TODO: Add the new instance of SampleItem to the collection
        // throw new NotImplementedException();
        return new SampleItem();
    }
    

    I have this code to call the above service

    XElement data = new XElement("SampleItem",
                                 new XElement("Id", "2"),
                                 new XElement("StringValue", "sdddsdssd")
                               ); 
    
    System.IO.MemoryStream dataSream1 = new MemoryStream();
    data.Save(dataSream1);
    
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:2517/Service1/Create");
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    // You need to know length and it has to be set before you access request stream
    request.ContentLength = dataSream1.Length;
    
    using (Stream requestStream = request.GetRequestStream())
    {
        dataSream1.CopyTo(requestStream);
        byte[] bytes = dataSream1.ToArray();
        requestStream.Write(bytes, 0, Convert.ToInt16(dataSream1.Length));
        requestStream.Close();
    }
    
    WebResponse response = request.GetResponse();
    

    I get an exception at the last line:

    The remote server returned an error: (405) Method Not Allowed. Not sure why this is happening i tried changing the host from VS Server to IIS also but no change in result. Let me know if u need more information

  • Praneeth
    Praneeth about 12 years
    I am getting The remote server returned an error: (405) Method Not Allowed.
  • Rajesh
    Rajesh about 12 years
    How is your service hosted? Do you have an entry in the global.asax. Also check if you have the help page enabled and from it try to find the url for the method you are trying to post and see that the url is correct
  • Praneeth
    Praneeth about 12 years
    help is working i can see the services in the browser and get is working in the browser. Service is hosted through VS Server and I have routes registered in the global.asax
  • Rajesh
    Rajesh about 12 years
    Can you remove the empty URITemplate attribute and see if that works. Also your help page would give the URL for the CREATE method during POST
  • Praneeth
    Praneeth about 12 years
    page is giving create url during help. I removed URi Template but still i get a 405 exception
  • Rajesh
    Rajesh about 12 years
    Can you use just that without any Create in your URI?
  • Praneeth
    Praneeth about 12 years
    I dont have create in the URI