WCF service doesn't recognise correct JSON - c#

I have the following code:
[DataContract]
public class OptimizationServiceSettings
{
[DataMember]
public bool StealthMode { get; set; }
}
Server:
[WebInvoke(Method = "POST", UriTemplate = "SetSettings", BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
[OperationContract]
public void SetSettings(OptimizationServiceSettings settings)
{
if (settings != null)
{
_stageOptimizer.ServiceSettings = settings;
}
else
{
Trace.TraceError("Attemp to set null OptimizationServiceSettings");
}
}
Client:
private static void SetSettings()
{
OptimizationServiceSettings op = new OptimizationServiceSettings();
op.StealthMode = true;
string jsonInput = ToJson(op);
var client = new WebClient();
client.Headers["Content-type"] = "application/json";
client.Encoding = Encoding.UTF8;
var response = client.UploadString("http://localhost:8080/BlocksOptimizationServices/SetSettings", "POST", jsonInput);
}
private static string ToJson<T>(T data)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, data);
return Encoding.Default.GetString(ms.ToArray());
}
}
For some reason the SetSettings method on the server always gets a null settings object. If I change the settings object type to string it all works. I don't understand what is wrong here. Everything looks like it is correct.
Here is an example of the jsonInput string that I got in SetSettings on the client:
"{\"StealthMode\":\"true\"}"

You specified the requestbody to be wrapped:
[WebInvoke(..., BodyStyle = WebMessageBodyStyle.WrappedRequest, ...]
Hence, the deserialization only succeeds if you wrap the settings-object within a containing object, as #Pankaj suggested.
Instead of doing that, you could try to change the attribute to WebMessageBodyStyle.Bare to avoid the need to wrap the parameter.

Related

Why is my Json string response escaped for a WCF Rest web service (weakly-typed Json) response?

I have this contract :
[ServiceContract]
public interface IServiceJsonContract
{
[WebInvoke(UriTemplate = "/MyMethod", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, Method = "POST")]
Message MyMethod(Message input);
}
And the definition for MyMethod is :
Message MyMethod(Message input)
{
...
Message response = Message.CreateMessage(
MessageVersion.None,
"*",
"{\"bla\": 2 }",
new DataContractJsonSerializer(typeof(string)));
response.Properties.Add( WebBodyFormatMessageProperty.Name,new
WebBodyFormatMessageProperty(WebContentFormat.Json));
var contextOutgoingResponse = WebOperationContext.Current.OutgoingResponse;
contextOutgoingResponse.ContentType = "application/json;charset=utf-8";
return response;
}
When calling the method I got the Json escaped:
"{\"bla\": 2 }"
instead of unescaped one (below):
"{"bla": 2 }"
Any idea how to get the unescaped Json ( "{"bla": 2 }" ) ?
Thanks
The DataContractJsonSerializer is serializing your string and escaping the quotation marks. Create a class to hold your data and pass that instead of the string.
public class MyData
{
public string Bla { get; set; }
}
// create an instance
MyData myData = new MyData()
{
Bla = "the value";
};
// then use it
Message response = Message.CreateMessage(
MessageVersion.None,
"*",
myData,
new DataContractJsonSerializer(typeof(MyData)));
you can use Stream as your out put. this way you can send back uncapped string:
[ServiceContract]
public interface IServiceJsonContract
{
[WebInvoke(UriTemplate = "/MyMethod", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, Method = "POST")]
Stream MyMethod(Message input);
}
Stream MyMethod(Message input)
{
..
return new MemoryStream(Encoding.UTF8.GetBytes("{\"bla\": 2 }"));
}

how to call WCF service method from Angular js

I created a WCF service and I am not able to call any method from my angular js script.
namespace jSonTest2.Service
{
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class service:IService1
{
public DB obj = new DB();//object class which return string
[WebInvoke(Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
string IService1.JsonCall()
{
return obj.JsonCall();
throw new NotImplementedException();
}
}
}
//---------------------------------------
namespace jSonTest2.DB_provider
{
class DB//class
{
public string JsonCall()
{
string str = "{name: 'Amit', marks: 97, distinction: true}";
return str;
}
}
}
//I created a WCF service and I am not able to call any method from my angular

WCF JSON serialization is inconsistent so how can it be deserialized correctly?

I have a serializable polymorphic type, and a service contract.
[DataContract]
[KnownType(typeof(SomethingA))]
[KnownType(typeof(SomethingB))]
public class Something
{
[DataMember]
public int Item1 { get; set; }
[DataMember]
public string Item2 { get; set; }
}
[DataContract]
public class SomethingA : Something
{ }
[DataContract]
public class SomethingB : Something
{ }
[ServiceContract]
[ServiceKnownType(typeof(SomethingA))]
[ServiceKnownType(typeof(SomethingB))]
public interface ITesting
{
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "use-something",
Method = "POST")]
Something UseSomething();
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "use-polymorphic-somethings",
Method = "POST")]
List<Something> UsePolymorphicSomethings();
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "throw-web-exception",
Method = "POST")]
void ThrowServerException();
}
...and an implementation of that contract.
using System.Net;
using System.ServiceModel.Web;
public class Testing : ITesting
{
public Something UseSomething()
{
SomethingA a = new SomethingA();
a.Item1 = 2;
a.Item2 = "b";
return a;
}
public List<Something> UsePolymorphicSomethings()
{
List<Something> retVal = new List<Something>();
retVal.Add(new SomethingA { Item1 = 1, Item2 = "1" });
retVal.Add(new SomethingB { Item1 = 1, Item2 = "1" });
return retVal;
}
public void ThrowServerException()
{
try
{
throw new ApplicationException("Bad news.");
}
catch (ApplicationException e)
{
throw new WebFaultException<ApplicationException>(e, HttpStatusCode.InternalServerError);
}
}
}
I have some functional tests in another assembly.
using System.Net;
using System.Net.Http;
using System.Runtime.Serialization.Json;
[TestMethod]
public void UseSomething_WebTest()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = TestUtil.TestsBaseAddress;
HttpResponseMessage response = http.PostAsJsonAsync("use-something",
new StringContent(string.Empty)).Result;
string ret1 = response.Content.ReadAsStringAsync().Result;
// Deserializes SomethingA as Something.
Stream stream = response.Content.ReadAsStreamAsync().Result;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Something));
Something ret = (Something)serializer.ReadObject(stream);
// FAILS.
Assert.AreEqual(typeof(SomethingA), ret.GetType());
}
}
[TestMethod]
public void UsePolymorphicSomethings_WebTest()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = TestUtil.TestsBaseAddress;
HttpResponseMessage response = http.PostAsJsonAsync("use-polymorphic-somethings",
new StringContent(string.Empty)).Result;
string ret2 = response.Content.ReadAsStringAsync().Result;
// Deserializes SomethingA and SomethingB correctly.
Stream stream = response.Content.ReadAsStreamAsync().Result;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Something>));
List<Something> somethings = (List<Something>)serializer.ReadObject(stream);
// SUCCEEDS.
Assert.AreEqual(typeof(SomethingA), somethings[0].GetType());
Assert.AreEqual(typeof(SomethingB), somethings[1].GetType());
}
}
[TestMethod]
public void ThrowServerException1_WebTest()
{
using (HttpClient http = new HttpClient())
{
http.BaseAddress = TestUtil.TestsBaseAddress;
HttpResponseMessage response = http.PostAsync("throw-web-exception",
new StringContent(string.Empty)).Result;
Assert.AreEqual(HttpStatusCode.InternalServerError, response.StatusCode);
string ret3 = response.Content.ReadAsStringAsync().Result;
// Deserializes ApplicationException as Exception.
Stream stream = response.Content.ReadAsStreamAsync().Result;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Exception));
Exception e = (Exception)serializer.ReadObject(stream);
// FAILS.
Assert.AreEqual(typeof(ApplicationException), e.GetType());
}
}
In UseSomething_WebTest ret1 is:
"{\"Item1\":2,\"Item2\":\"b\"}"
...with no type information embedded unsurprisingly the DataContractJsonSerializer fails to deserialize the correct type of the object that was returned.
In UsePolymorphicSomethings_WebTest ret2 is:
"[{\"__type\":\"SomethingA:#InSite8WebServiceLib\",\"Item1\":1,\"Item2\":\"1\"},{\"__type\":\"SomethingB:#InSite8WebServiceLib\",\"Item1\":1,\"Item2\":\"1\"}]"
...with type information embedded in the form of __type entries which the DataContractJsonSerializer correctly deserializes.
In ThrowServerException1_WebTest ret3 is:
"{\"ClassName\":\"System.ApplicationException\",\"Message\":\"Bad news.\",\"Data\":null,\"InnerException\":null,\"HelpURL\":null,\"StackTraceString\":\" at InSite8WebServiceLib.Testing.ThrowServerException() in d:\\\\SvnSource\\\\Hammersmith\\\\trunk\\\\VisualStudioProjects\\\\InSite8WebService\\\\InSite8WebServiceLib\\\\Testing\\\\Testing.cs:line 74\",\"RemoteStackTraceString\":null,\"RemoteStackIndex\":0,\"ExceptionMethod\":\"8\\u000aThrowServerException\\u000aInSite8WebServiceLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\\u000aInSite8WebServiceLib.Testing\\u000aVoid ThrowServerException()\",\"HResult\":-2146232832,\"Source\":\"InSite8WebServiceLib\",\"WatsonBuckets\":null}"
...with type information embedded in the form of a ClassName entry which the DataContractJsonSerializer fails to deserialize correctly.
So my question is this. Why for a single WCF WebHttp endpoint do several WebInvoke attributed methods return several different formats of JSON only one of which the DataContractJsonSerializer can actually deserialize, and how do I fix it so that it works properly?
You can force the DataContractJsonSerializer to always emit type information by overloading the constructor. Then you set the alwaysEmitTypeInformation argument to True.
Some more information on MSDN

400 bad request but cant find the issue

I am having a real difficult time figuring out why I am getting a 400 bad request from my POST method on my client side. My other POST methods work fine for this service and client. Yet this one isnt working? I was hoping a fresh pair of eyes might find the problem?
My Service looks like this:
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, UriTemplate = "/Message")]
void AddMessage(Message message);
//Post Method for Message
[DataContract(Name = "Message")]
public class Message
{
[DataMember(Name = "MessageID")]
public string MessageID { get; set; }
[DataMember(Name = "GroupMessage")]
public string GroupMessage { get; set; }
//DataContracts for Message
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class RawDataService : IReceiveData
{
List<Message> messages = new List<Message>();
int eCount = 0;
public void AddMessage(Message message)
{
message.MessageID = (++eCount).ToString();
messages.Add(message);
}
// add message method, increment MessageID
Client Code to Post which gives the 400 bad request on marked line:
private void button15_Click(object sender, EventArgs e)
{
string uriMessage = "http://localhost:8000/Service/Message";
StringBuilder sb1 = new StringBuilder();
sb1.AppendLine("</Message>");
sb1.AppendLine("<GroupMessage>" + this.textBox22.Text + "</GroupMessage>");
sb1.AppendLine("</Message>");
string GroupMessage = sb1.ToString();
byte[] arr1 = Encoding.UTF8.GetBytes(GroupMessage);
HttpWebRequest req1 = (HttpWebRequest)WebRequest.Create(uriMessage);
req1.Method = "POST";
req1.ContentType = "application/xml";
req1.ContentLength = arr1.Length;
Stream reqStrm1 = req1.GetRequestStream();
reqStrm1.Write(arr1, 0, arr1.Length);
reqStrm1.Close();
HttpWebResponse resp1 = (HttpWebResponse)req1.GetResponse(); //400 bad request?
MessageBox.Show(resp1.StatusDescription);
reqStrm1.Close();
resp1.Close();
}
This might be it.
sb1.AppendLine("</Message>");
sb1.AppendLine("<GroupMessage>" + this.textBox22.Text + "</GroupMessage>");
sb1.AppendLine("</Message>");
The opening Message element is actually a closing element.

Defining a datacontract with the same input paramiters

Is it possible to define two operation contracts with the same paramiters? I want to have the same endpoint do diffrent things on post and get. My code is below
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "MAC/{input}")]
string MAC(string input);
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "MAC/{input}")]
Datalayer.Datacontracts.WebserviceMessage MAC(string input);
With the same name? NO.
Using same parameters as you have mentioned is possible. But not with the same name.
Services follow document-centric paradigm; so when designing services, we should get rid of object oriented thinking. Don't think about polymorphism, overloading or overriding.
The metadata of the service has to be shared as a document to even non-object oriented systems/platforms (to support interoperability).
In addition to what SaravananArumugam said - the code as you have doesn't even compile (you cannot have two methods in the same interface with the same name whose only difference is the return type). However, you can change the method names and continue with the same UriTemplate - you'll have a "virtual" method with the same name (i.e., the address the client uses will be the same - like in the example below.
One more thing: you shouldn't use [WebInvoke(Method = "GET")], use [WebGet] instead.
public class StackOverflow_6548562
{
public class WebserviceMessage
{
public string Data;
}
[ServiceContract]
public interface ITest
{
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "MAC/{input}")]
string MAC_Get(string input);
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "MAC/{input}")]
WebserviceMessage MAC_Post(string input);
}
public class Service : ITest
{
public string MAC_Get(string input)
{
return input;
}
public WebserviceMessage MAC_Post(string input)
{
return new WebserviceMessage { Data = input };
}
}
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();
Console.WriteLine(c.DownloadString(baseAddress + "/MAC/fromGET"));
Console.WriteLine(c.UploadString(baseAddress + "/MAC/frompost", "POST", ""));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

Categories

Resources