Trying to call a WCF service with a WebRequest

14,031

Solution 1

I think you're mixing up two different things here:

  1. WebRequest and a POST and the [WebInvoke] attribute suggests you're trying to do something like REST
  2. Your service config however has basicHttpBinding - a SOAP protocol which won't fly with WebRequest

So - make up your mind!

Do you want to use SOAP? Then you're fine with the basicHttpBinding as is, but you cannot access a SOAP service just like that from a WebRequest with POST - you need to use the SOAP client generated by Visual Studio or svcutil.exe on the command line.

Do you want to use WebRequest and a simple POST request?? Then you need to create a REST based WCF service - use the webHttpBinding and the WebServiceHost (as opposed to a plain ServiceHost).

For SOAP-based WCF services, check out the WCF Developer Center on MSDN.

For REST-based WCF services (which you can navigate to in your browser, and which you can call from WebRequest), check out the WCF REST Developer Center on MSDN and have a look at the excellent screencast series by Pluralsight on REST based development in WCF - most notably:

Solution 2

basicHttpBinding is also suitable!

I spend almost a day figuring out whats wrong with WebRequest to WCF service with basicHttpBinding and it turned out I missed small but crucial thing: SOAPAction header has to be set!

newRequest.Headers["SOAPAction"] = "http://tempuri.org/INotificationService/MyMethodName"
Share:
14,031
Seth
Author by

Seth

Updated on June 23, 2022

Comments

  • Seth
    Seth almost 2 years

    I have a WCF service that needs to be called by a 3rd party app, posting some raw XML.

    I am trying to test my service by constructing a simple WebRequest and making the request to the service.

    Here's my service code:

    Interface:

        [ServiceContract(Namespace = "http://test.mydomain.com")]
    public interface ITest
    {
        [WebInvoke(UriTemplate = "", BodyStyle = WebMessageBodyStyle.Bare, Method="POST")]
        [OperationContract]
        Stream SaveXML(Stream input);
    }
    

    Service:

        [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(Namespace = "http://test.mydomain.com")]
    public class Test : ITest
    {
        public Stream SaveXML(Stream input)
        {
            StreamReader streamReader = new StreamReader(input);
            string rawString = streamReader.ReadToEnd();
            streamReader.Dispose();
    
            // here need to save the input stream to xml format file
            Encoding encoding = Encoding.GetEncoding("ISO-8859-1");
            WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
            byte[] returnBytes = encoding.GetBytes(rawString);
            return new MemoryStream(returnBytes);
        }
    }
    

    config:

        <services>
      <service behaviorConfiguration="Blah.TestBehavior" name="Blah.Test">
        <endpoint address="http://localhost:51494/Blah/Test.svc" binding="basicHttpBinding" contract="Blah.ITest">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    

    faulty client code:

                string postData = "<Message version=\"1.5\" xmlns=\"http://test.mydomain.com\" ><books>Blah</books></Message>";
            WebRequest request = WebRequest.Create("http://localhost:51494/Blah/Test.svc/SaveXML");
            request.Method = "POST";
    
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            request.ContentType = "application/x-www-form-urlencoded";
            //request.ContentType = "text/xml; charset=utf-8";
            //request.ContentType = "text/xml;";
            //request.ContentType = "application/xml;";
            request.ContentLength = byteArray.Length;
    
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();
    
            // Get the response.
            WebResponse response = request.GetResponse();
    

    On that last line I get a 400 (Bad Request) or 415 (Unsupported Media Type) error, depending on which ContentType I specify.

    Also, if I add a service reference in my client app, and call the service using the API it works fine. Any insights would be greatly appreciated, as I am new to WCF and completely stumped.

    • Cheeso
      Cheeso about 14 years
      What I would do: use Fiddler fiddler2.com/fiddler2 to see the request for "the API" - the one that works. Then compare it to the request that doesn't work. That should narrow it down.
    • John Saunders
      John Saunders about 14 years
      Your StreamReader needs to be in a using block, as do several of your other objects. A using block will cause them to be disposed of even if an exception is thrown.
  • Abhijeet
    Abhijeet over 10 years
    What did you supply in body of the WebRequest. Did it include SOAPHeaders as well.
  • Alexander Selishchev
    Alexander Selishchev over 10 years
    @autrevo, you mean request stream? You can install http proxy (such as Fiddler) and check whats being sent in WCF service call. You will see request body and headers. I had to forward request in my task, so im not constructing request body by myself.
  • default
    default almost 7 years
    WCF Developer Center seems dead - any updated link available?
  • default
    default almost 7 years
    .. And the RESTful videos as well unfortunately.
  • marc_s
    marc_s almost 7 years
    @Default: sorry, those links were ok - in 2010 when I answered - but you're right, they seem to be dead know. I'm sorry, I don't have any alternate links..... try to ask Google or Bing, maybe??
  • default
    default almost 7 years
    I know that you wrote the answer in 2010. No need to point it out. When links rot on stackoverflow I usually let the OP know since I don't just want to randomly update links to some other resource. My intention was to let the links get updated somehow for other visitors as well, not just now, for me. I am sorry if you took offence. I will try Google.