Answered by:
WCF JSON Multiple Parameters

Question
-
Hi,
I've been experimenting with calling a WCF services from a Windows Mobile device using HttpWebResponse/HttpWebRequest. The format of the data exchange is Json. The test service has the following method signature:
public string Process(Data dData)
When I make the call eveything is fine and I can see a trace of the exchange using TcpTrace. However when I change the method signature to receive multiple parameters, I receive a HTTP server 500 error.
{ return string.Format("you entered: {0} {1}", dData.StringValue, dData.BoolValue); }
public string Process(Data dData, Data dData2) { return string.Format("you entered: {0} {1} {2} {3}", dData.StringValue, dData.BoolValue, dData2.StringValue, dData2.BoolValue); }
The code on the client is as follows:
Data dData1 = new Data(); dData1.BoolValue = true; dData1.StringValue = "Hello WCF World"; Data dData2 = new Data(); dData2.BoolValue = false; dData2.StringValue = "HW"; //DataContractJsonSerializer dcjSerialiser = null; JsonSerializer jsSerialiser = null; //string strJson = null; //byte[] bData = null; Uri uUri = new Uri("http://localhost:8080/WcfTest/Service.svc/process"); HttpWebRequest hwrRequest = (HttpWebRequest)WebRequest.Create(uUri); hwrRequest.Method = "POST"; hwrRequest.ContentType = "application/json; charset=utf-8"; //hwrRequest.ContentLength = bData.Length; //using(MemoryStream msStream = new MemoryStream()) //{ //dcjSerialiser = new DataContractJsonSerializer(dData1.GetType()); jsSerialiser = new JsonSerializer(); jsSerialiser.NullValueHandling = NullValueHandling.Ignore; //dcjSerialiser.WriteObject(msStream, dData); using(Stream sData = hwrRequest.GetRequestStream()) { //sData.Write(bData, 0, bData.Length); //dcjSerialiser.WriteObject(sData, dData1); //dcjSerialiser.WriteObject(sData, dData2); using(StreamWriter swWriter = new StreamWriter(sData)) { using(JsonWriter jwWriter = new JsonTextWriter(swWriter)) { jsSerialiser.Serialize(jwWriter, dData1); jsSerialiser.Serialize(jwWriter, dData2); } } sData.Close(); } //strJson = Encoding.UTF8.GetString(msStream.ToArray()); //bData = Encoding.UTF8.GetBytes(strJson); //msStream.Close(); //} using(HttpWebResponse hwrResponse = (HttpWebResponse)hwrRequest.GetResponse()) { StreamReader srReader = new StreamReader(hwrResponse.GetResponseStream()); Console.WriteLine(srReader.ReadToEnd()); }
Is it possible to send multiple parameters?
Any help would be appreciated,
MarkThursday, September 24, 2009 1:44 PM
Answers
-
If you use multiple parameters, you need to "wrap" the request in its own object (and note it on the [WebInvoke] attribute), otherwise you'd get an invalid JSON. For example, the request you're sending is this:
{"StringValue":"Hello WCF World","BoolValue",true}{"StringValue":"HW","BoolValue":false}
which is not a valid JSON. You need to wrap it like the following:
{"data1":{"StringValue":"Hello WCF World","BoolValue",true},"data2":{"StringValue":"HW","BoolValue":false}}
And your contract has to be as shown below:
[
OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
string Process(Data dData1, Data dData2);
The code below shows the whole thing end-to-end:
public class Post_044876ce_2643_4f2b_b9f4_250f920454ae_2Param { [DataContract] public class Data { [DataMember] public string StringValue; [DataMember] public bool BoolValue; } [ServiceContract] public interface ITest { [OperationContract] [WebInvoke( BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)] string Process(Data dData1, Data dData2); } public class Service : ITest { public string Process(Data dData1, Data dData2) { if (dData1 == null) { return "dData1 == null"; } if (dData2 == null) { return "dData2 == null"; } return string.Format("you entered: {0} {1}, {2} {3}", dData1.StringValue, dData1.BoolValue, dData2.StringValue, dData2.BoolValue); } } public static void Test() { string baseAddress = "http://localhost:8000/Service"; ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior()); host.Open(); Console.WriteLine("Host opened"); Util.SendRequest(baseAddress + "/Process", "POST", "application/json", "{\"dData1\":{\"BoolValue\":true,\"StringValue\":\"Hello\"}, \"dData2\":{\"BoolValue\":false,\"StringValue\":\"World\"}}"); Console.Write("Press ENTER to close the host"); Console.ReadLine(); host.Close(); } } public static class Util { public static string SendRequest(string uri, string method, string contentType, string body) { string responseBody = null; HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri); req.Method = method; if (!String.IsNullOrEmpty(contentType)) { req.ContentType = contentType; } if (!String.IsNullOrEmpty(body)) { byte[] bodyBytes = Encoding.UTF8.GetBytes(body); req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length); req.GetRequestStream().Close(); } HttpWebResponse resp; try { resp = (HttpWebResponse)req.GetResponse(); } catch (WebException e) { resp = (HttpWebResponse)e.Response; } Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription); foreach (string headerName in resp.Headers.AllKeys) { Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]); } Console.WriteLine(); Stream respStream = resp.GetResponseStream(); if (respStream != null) { responseBody = new StreamReader(respStream).ReadToEnd(); Console.WriteLine(responseBody); } else { Console.WriteLine("HttpWebResponse.GetResponseStream returned null"); } Console.WriteLine(); Console.WriteLine(" *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* "); Console.WriteLine(); return responseBody; } }
- Proposed as answer by Carlos Figueira Friday, September 25, 2009 11:45 PM
- Marked as answer by markpirvine Saturday, September 26, 2009 9:19 AM
Thursday, September 24, 2009 2:03 PM
All replies
-
If you use multiple parameters, you need to "wrap" the request in its own object (and note it on the [WebInvoke] attribute), otherwise you'd get an invalid JSON. For example, the request you're sending is this:
{"StringValue":"Hello WCF World","BoolValue",true}{"StringValue":"HW","BoolValue":false}
which is not a valid JSON. You need to wrap it like the following:
{"data1":{"StringValue":"Hello WCF World","BoolValue",true},"data2":{"StringValue":"HW","BoolValue":false}}
And your contract has to be as shown below:
[
OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
string Process(Data dData1, Data dData2);
The code below shows the whole thing end-to-end:
public class Post_044876ce_2643_4f2b_b9f4_250f920454ae_2Param { [DataContract] public class Data { [DataMember] public string StringValue; [DataMember] public bool BoolValue; } [ServiceContract] public interface ITest { [OperationContract] [WebInvoke( BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)] string Process(Data dData1, Data dData2); } public class Service : ITest { public string Process(Data dData1, Data dData2) { if (dData1 == null) { return "dData1 == null"; } if (dData2 == null) { return "dData2 == null"; } return string.Format("you entered: {0} {1}, {2} {3}", dData1.StringValue, dData1.BoolValue, dData2.StringValue, dData2.BoolValue); } } public static void Test() { string baseAddress = "http://localhost:8000/Service"; ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior()); host.Open(); Console.WriteLine("Host opened"); Util.SendRequest(baseAddress + "/Process", "POST", "application/json", "{\"dData1\":{\"BoolValue\":true,\"StringValue\":\"Hello\"}, \"dData2\":{\"BoolValue\":false,\"StringValue\":\"World\"}}"); Console.Write("Press ENTER to close the host"); Console.ReadLine(); host.Close(); } } public static class Util { public static string SendRequest(string uri, string method, string contentType, string body) { string responseBody = null; HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri); req.Method = method; if (!String.IsNullOrEmpty(contentType)) { req.ContentType = contentType; } if (!String.IsNullOrEmpty(body)) { byte[] bodyBytes = Encoding.UTF8.GetBytes(body); req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length); req.GetRequestStream().Close(); } HttpWebResponse resp; try { resp = (HttpWebResponse)req.GetResponse(); } catch (WebException e) { resp = (HttpWebResponse)e.Response; } Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription); foreach (string headerName in resp.Headers.AllKeys) { Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]); } Console.WriteLine(); Stream respStream = resp.GetResponseStream(); if (respStream != null) { responseBody = new StreamReader(respStream).ReadToEnd(); Console.WriteLine(responseBody); } else { Console.WriteLine("HttpWebResponse.GetResponseStream returned null"); } Console.WriteLine(); Console.WriteLine(" *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* "); Console.WriteLine(); return responseBody; } }
- Proposed as answer by Carlos Figueira Friday, September 25, 2009 11:45 PM
- Marked as answer by markpirvine Saturday, September 26, 2009 9:19 AM
Thursday, September 24, 2009 2:03 PM -
Carlos,
Thanks for the reply and code snippet.
MarkSaturday, September 26, 2009 9:22 AM -
http://arraycode.com/Main/Details/post-multiple-parameters-to-wcf-service-1329
Maybe This will help?
- Proposed as answer by TaylorCode Monday, August 1, 2011 12:19 PM
Monday, August 1, 2011 12:19 PM -
Link doesn't work. FYI
Monday, October 14, 2013 3:33 PM