0

I have a scenario where I need to send the class object to the WCF REST method as input as given below .

[OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "/InsertContact", ResponseFormat = WebMessageFormat.Xml,
          RequestFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped)]
        int InsertContact(ContactType objContactType);

Getting the below error in the Fiddler

<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none"><Code><Value>Receiver</Value><Subcode><Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</Value></Subcode></Code><Reason><Text xml:lang="en-US">Error in deserializing body of request message for operation 'InsertContact'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'InsertContact' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'ContactType' and namespace ''</Text></Reason><Detail><ExceptionDetail xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><HelpLink i:nil="true"/><InnerException><HelpLink i:nil="true"/><InnerException i:nil="true"/><Message>OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'InsertContact' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'ContactType' and namespace ''</Message><StackTrace>   at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, String action, MessageDescription messageDescription, Object[] parameters, Boolean isRequest)&#xD;
   at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest)&#xD;
   at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeRequest(Message message, Object[] parameters)</StackTrace><Type>System.Runtime.Serialization.SerializationException</Type></InnerException><Message>Error in deserializing body of request message for operation 'InsertContact'. OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name 'InsertContact' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'ContactType' and namespace ''</Message><StackTrace>   at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeRequest(Message message, Object[] parameters)&#xD;
   at System.ServiceModel.Dispatcher.DemultiplexingDispatchMessageFormatter.DeserializeRequest(Message message, Object[] parameters)&#xD;
   at System.ServiceModel.Dispatcher.UriTemplateDispatchFormatter.DeserializeRequest(Message message, Object[] parameters)&#xD;
   at System.ServiceModel.Dispatcher.CompositeDispatchFormatter.DeserializeRequest(Message message, Object[] parameters)&#xD;
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</StackTrace><Type>System.ServiceModel.CommunicationException</Type></ExceptionDetail></Detail></Fault>

I want to make my REST API to accept either JSON or XML request depending on the client.Do I need to set this property in the WebInvoke attribute or in the web.config ?

Passing the below XML

<ContactType>
    <ContactTypeID>3</ContactTypeID>
    <Name>Assistant Sales Representative</Name>
    <ModifiedDate>2002-06-01T00:00:00</ModifiedDate>
 </ContactType>

Can anyone help me regarding this ?

Hemant Kumar
  • 4,593
  • 9
  • 56
  • 95
  • Are you using the namespace to validate? If not, then maybe just remove it - and retry. – Anthony Horne May 07 '14 at 18:59
  • @AnthonyHorne Passing this XML 3 Assistant Sales Representative 2002-06-01T00:00:00 – Hemant Kumar May 07 '14 at 19:02
  • The most recent service I wrote allows the user to send txt, XMLElement (or Document) or the actual object. The interface just defined them separately. I needed to change System.Linq to System.XML (otherwise did not work) and in my case, required me to remove the NS (as the vendor puts in an invalid one) – Anthony Horne May 07 '14 at 19:07
  • Fiddler allows you to specify an xml response version. In my .NET 5.6 it requires me to pick the HTTP/1.1 in Composer, otherwise I get an error. >1.1 gives error. – Anthony Horne May 07 '14 at 19:14
  • @AnthonyHorne I have tried with 1.1 version and selected higher version also. Getting the same error. – Hemant Kumar May 07 '14 at 19:17
  • What does ContactType look like? Any enums referenced? – Anthony Horne May 07 '14 at 19:26
  • Look at http://stackoverflow.com/a/19431291/1662973 and see if you get anything further. I also tried to do the XML Serialize generically, but with complicated object it becomes ever increasing an issue. – Anthony Horne May 07 '14 at 19:29

1 Answers1

2

The error pointed out the problem you have:

Expected to find node type 'Element' with name 'InsertContact' and namespace 'http://tempuri.org/'. Found node type 'Element' with name 'ContactType' and namespace ''

When you declare the BodyStyle of your WebInvoke to be Wrapped, it means that you must wrap the request body with the operation name (and appropriate XML namespace).

The code below shows one way to pass the value to your operation.

public class StackOverflow_23526051
{
    [ServiceContract]
    public interface ITest
    {
        [WebInvoke(Method = "POST", UriTemplate = "/InsertContact", ResponseFormat = WebMessageFormat.Xml,
          RequestFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Wrapped)]
        int InsertContact(ContactType objContactType);
    }
    public class Service : ITest
    {
        public int InsertContact(ContactType objContactType)
        {
            Console.WriteLine("objContactType: {0}", objContactType);
            return 0;
        }
    }

    [DataContract(Name = "ContactType", Namespace = "")]
    public class ContactType
    {
        [DataMember(Order = 1)]
        public int ContactTypeID { get; set; }

        [DataMember(Order = 2)]
        public string Name { get; set; }

        [DataMember(Order = 3)]
        public string ModifiedDate { get; set; }

        public override string ToString()
        {
            return string.Format("ContactType[Id={0},Name={1},ModifiedDate={2}]", ContactTypeID, Name, ModifiedDate);
        }
    }

    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
        host.Open();
        Console.WriteLine("Host opened");

        WebClient c = new WebClient();
        c.Headers.Add(HttpRequestHeader.ContentType, "text/xml");
        var xml = @"<t:objContactType>
            <ContactTypeID>3</ContactTypeID>
            <Name>Assistant Sales Representative</Name>
            <ModifiedDate>2002-06-01T00:00:00</ModifiedDate>
         </t:objContactType>";

        xml = "<t:InsertContact xmlns:t=\"http://tempuri.org/\">" + xml + "</t:InsertContact>";

        Console.WriteLine(c.UploadString(baseAddress + "/InsertContact", xml));
        Console.WriteLine();

        // To find out the request format: use the following 5 lines, look at Fiddler
        var factory = new WebChannelFactory<ITest>(new Uri(baseAddress));
        var proxy = factory.CreateChannel();
        proxy.InsertContact(new ContactType { ContactTypeID = 123, ModifiedDate = "the date", Name = "John Doe" });
        ((IClientChannel)proxy).Close();
        factory.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • carlosfigueira Thanks for your help. I have few questions regarding the Wrap . 1. Do this effect the XML object ? 2. I have to convert to the class ContactType object into XML. Do the xml string will vary ? 3. I have implemented as given but the request ContactTypeId is not returned . – Hemant Kumar May 08 '14 at 04:46
  • The body style affects the format (schema) of the XML body which needs to be passed as the request body. As long as the XML follows the specified schema, it should work. Try sending the request with a **WCF client** (as I showed in the last part of the code), and look at what is sent with a tool such as Fiddler. That will tell you exactly the format the request needs to be sent. – carlosfigueira May 08 '14 at 04:48
  • Am sending the xml string as " 3 Assistant Sales Representative 2002-06-01T00:00:00 " . At service the validating the if contacttype object is not null return ContactTypeId. Always I am getting contactId as Zero not Three. – Hemant Kumar May 08 '14 at 05:05
  • Without seeing the full implementation of your service / class it's impossible to know what the format should be. If you post a [small, self-contained, complete example](http://sscce.org) of your issue (like I have in my answer), then we'll be able to help more. – carlosfigueira May 08 '14 at 13:27