Defining a datacontract with the same input paramiters - c#

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();
}
}

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 service doesn't recognise correct JSON

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.

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

WCF Rest Service has value deserializing as 0 every time

I have a WCF Rest service with a method that takes in multiple parameters:
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json)]
StatusMessage DoSomeWork(short myId, decimal latitude, decimal longitude, string someData);
The JSON data which is serialized on the client side serializes correctly, and this method receives that data. The problem is that the longitudeparameter always comes back as 0, no matter what value the value is when it gets serialized. All the other parameters are deserialized correctly. Any idea as to why this is happening, and a possible fix?
Make sure that the name of the property in the JSON object matches the name of the parameter longitude. The code below shows your exact operation contract, and the longitude is correctly received by the service.
public class StackOverflow_23529686
{
[ServiceContract]
public class Service
{
[OperationContract]
[WebInvoke(
Method = "POST",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
RequestFormat = WebMessageFormat.Json)]
public StatusMessage DoSomeWork(short myId, decimal latitude, decimal longitude, string someData)
{
return new StatusMessage
{
Text = string.Format("id={0}, lat={1}, lon={2}, data={3}", myId, latitude, longitude, someData)
};
}
}
public class StatusMessage
{
public string Text { get; set; }
}
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, "application/json");
var json =
"{'someData':'hello','longitude':-56.78,'latitude':12.34,'myId':1}"
.Replace('\'', '\"');
Console.WriteLine(c.UploadString(baseAddress + "/DoSomeWork", json));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}

Categories

Resources