Passing List<string> in WCF Rest Post Method - wcf

I am trying to pass a List in WCF Post call as parameter. Below is my code.
TrackingNumbers.cs
[KnownType(typeof(List<string>))]
[DataContract]
public class TrackingNumbers
{
[DataMember]
public List<object> TrackingNumberList { get; set; }
}
IService.cs
[OperationContract]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "v1/xml/GetMultipleShipmentDetails/")]
Shipments[] XMLMultipleData(TrackingNumbers trackingNumbers);
Now When I am passing the following XML from fiddler
<TrackingNumbers xmlns="http://schemas.datacontract.org/2004/07/Chhotu.Web.Partner.API">
<TrackingNumberList>10000008871</TrackingNumberList>
<TrackingNumberList>10000008864</TrackingNumberList>
<TrackingNumberList>10000008858</TrackingNumberList>
</TrackingNumbers>
the XMLMultipleData method is not getting called from debugger. Please suggest what i am doing wrong.

I see some issues with our code:
No need for [KnownType(typeof(List))], the DataContractSerializer knows this type already.
List - is not a good approach. If you use numbers why not make it an int?
Are you sure you are attached? You can try to enforce the attaching of a debugger with Debugger.Break(); at a good position in your code.

I will suggest you try change this line
Shipments[] XMLMultipleData(TrackingNumbers trackingNumbers);
with
Shipments[] XMLMultipleData(TrackingNumbers[] trackingNumbers);
And your [DataContract] as
[DataContract]
public class TrackingNumbers
{
[DataMember]
public int TrackingNumber{ get; set; }
}
Also! Try removing KnownType(typeof(List<string>))]
Thanks!

Related

How to serialize a subclass using DataContracts

I just started programming a WCF project and there is a serialization issue I can't seem to fix. I'm using DataContracts and DataMembers to serialize my classes to XML.
I have a class TestResponse that includes a property TestParameter. This property contains one string parameter. Also, I have a subclass of TestParameter called TestParameterSubclass. I need to serialize this subclass. These three classes look like this:
TestResponse.cs
[DataContract(Namespace = Service.defaultNamespace, Name="TestResponse")]
public class TestResponse
{
[DataMember(Name = "TestParameter")]
public TestParameter param { get; set; }
}
TestParameter.cs
[DataContract(Namespace = Service.defaultNamespace, Name="TestParameter")]
[KnownType(typeof(TestParameterSubclass))]
public class TestParameter
{
[DataMember(Name="ParamName")]
public string ParamName {get; set;}
}
TestParameterSubclass.cs
[DataContract(Name="TestParameterSubclass")]
public class TestParameterSubclass : TestParameter
{
}
I have an OperationContract
[OperationContract]
[WebInvoke(
Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/calculateA")]
TestResponse CalculateA(TestRequest data);
and CalculateA
public TestResponse CalculateA(TestRequest request)
{
TestResponse tr = new TestResponse();
TestParameterSubclass parameterSubclass = new TestParameterSubclass();
tr.param = parameterSubclass;
tr.param.ParamName = "hai";
return tr;
}
which results in
<TestResponse>
<TestParameter i:type="a:TestParameterSubclass">
<ParamName>hai</ParamName>
</TestParameter>
</TestResponse>
However, I need the XML to use the subclass name as the element name, like this
<TestResponse>
<TestParameterSubclass>
<ParamName>hai</ParamName>
</TestParameterSubclass>
</TestResponse>
Does anyone know how to do this?
(I have a similar problem with deserializing the input XML, but I think both problems are related, so fixing this would (hopefully) also fix my other problem.)

WCF RESTful Service - HTTP POST Request

I developed a WCF Service with the following post method:
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "/InsertBearingData")]
bool InsertBearingData(String JSONString);
I am using Fiddler to formulate an HTTP POST Request for this method but, it is returning Status Code - 400 Bad Request. This is the request formulated:
Request Header:
Host: localhost:21468
Content-Length: 96
Content-Type: application/json
Request Body:
[{"start time":"29-03-2013 11:20:11.340","direction":"SW","end time":"29-03-2013 11:20:14.770"}]
Can you please tell me how to formulate a good request in order to get a succesful response?
There are a few issues in your code:
The data type of the parameter is string, but you're passing a JSON array to it; a string parameter requires a JSON string to be passed.
The body style of the operation is set to Wrapped, which means that the parameter should be wrapped in an object whose key is the parameter name, something like {"JSONString":<the actual parameter value>}
To receive a request like the one you're sending, you need to have an operation like the following:
[ServiceContract]
public interface ITest
{
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/InsertBearingData")]
bool InsertBearingData(MyType[] param);
}
[DataContract]
public class MyType
{
[DataMember(Name = "start time")]
public string StartTime { get; set; }
[DataMember(Name = "end time")]
public string EndTime { get; set; }
[DataMember(Name = "direction")]
public string Direction { get; set; }
}

WCF Restful service parse enum within json cause error

I have a restful service based on WCF like below:
(The FeedbackInfo class has only one enum member - ServiceCode.)
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
public List<FeedbackInfo> GetFeedbackInfoList(ServiceCode code)
{
return ALLDAO.GetFeedbackInfoList(code);
}
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
public int? CreateFeedback(FeedbackInfo feedback)
{
return ALLDAO.CreateFeedback(feedback);
}
I will use jquery ajax to invoke these two method like below:
$.ajax({
type: "GET",
url: "/Service/ALL.svc/GetFeedbackInfoList",
datatype: "text/json",
data: { "code": "Info"},
});
var feedbackInfo = { feedback: {
ServiceCode: "Info"
}};
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "/Service/ALL.svc/CreateFeedback",
datatype: "text/json",
data: JSON.stringify(feedbackInfo),
});
The first calling will be excuted succesfully, whereas the second one give me an error: The value "Info" cannot be parsed as the type 'Int64'. I'm wondering why the same one enum can not be parsed in the second calling? Just because of the enum type being used as a member of class?
EDIT:
The FeedbackInfo and ServiceCode are looked like below:
public class FeedbackInfo
{
public int ID { get; set; }
public string Title { get; set; }
public ServiceCode ServiceCode { get; set; }
}
[DataContract]
public enum ServiceCode
{
[EnumMember]
Info,
[EnumMember]
Error
}
I have put together a better solution that uses the Newtonsoft.Json library. It fixes the enum issue and also makes the error handling much better. It's quite a lot of code, so you can find it on GitHub here: https://github.com/jongrant/wcfjsonserializer/blob/master/NewtonsoftJsonFormatter.cs
You have to add some entries to your Web.config to get it to work, you can see an example file here:
https://github.com/jongrant/wcfjsonserializer/blob/master/Web.config
Enums are serialized as integers, so you'd need to use ServiceCode: 1 (or whatever), or alternatively, add a custom property in the FeedbackInfo class to deserialize the enum from a given string value. Ie, something like this:
public string ServiceCode {
get {
return ServiceCodeEnum.ToString();
}
set {
MyEnum enumVal;
if (Enum.TryParse<MyEnum>(value, out enumVal))
ServiceCodeEnum = enumVal;
else
ServiceCodeEnum = default(MyEnum);
}
}
private MyEnum ServiceCodeEnum { get; set; }

Return a WCF EF4 Entity as JSON

My service interface is:
[ServiceContract]
public interface IMyService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "HelloJSON/{name}")]
string HelloJSON(string name);
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "GetEmployees")]
List<Employee> GetEmployees();
}
My implementation is:
public class MyService : IMyService
{
public string HelloJSON(string name)
{
return string.Format("Hello {0} in JSON", name);
}
public List<Employee> GetEmployees()
{
using (DBEntities ctx = new DBEntities())
{
List<Employee> emp = new List<Employee>();
emp = (from e in ctx.Employee select e).ToList();
return emp;
}
}
}
When I call the first method I get something like "Hello pepe in JSON", that's ok.
When I call the second method and set a breakpoint on line "return emp;" I get the list of the employees(there are 6 records from the database), but in IE I get this:
Internet Explorer cannot display the webpage
and testing in Firefox all I get is a blank page with a blank body, no HTML, no data and no errors.
I think WCF can't serialize my default EF4 entities.
EDIT:
My final solution was something(not exactly) like this:
static string SerializeJSON<T>(T obj) {
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj); }
EF entities cannot be serialized by default you must add code generation to them.
Refer to this article on how to create Serializable entities.
called Self Tracking entities
The best way would be to enable RIA Services and expose JSON Endpoint, it does everything correctly.
http://blogs.msdn.com/b/davrous/archive/2010/12/14/how-to-open-a-wcf-ria-services-application-to-other-type-of-clients-the-json-endpoint-4-5.aspx
http://channel9.msdn.com/Shows/SilverlightTV/Silverlight-TV-26-Exposing-SOAP-OData-and-JSON-Endpoints-for-RIA-Services

WebGet and non WebGet methods in WCF Rest Service

Following is my Contract and the OperationContracts, my issue is when I'm going with WebGet attribute to all the methods my service is working fine, when I remove WebGet Attribute to any one of the OperationContracts im getting following error.
Operation 'ProductDetails' of
contract 'IDemo' specifies multiple
request body parameters to be
serialized without any wrapper
elements. At most one body parameter
can be serialized without wrapper
elements. Either remove the extra body
parameters or set the BodyStyle
property on the
WebGetAttribute/WebInvokeAttribute to
Wrapped.
These are my methods
string AddNumbers(int x,int y); --- using [WebGet]
string SubtractNumbers(int x, int y); -- using [WebGet]
String ProductDetails(string sName, int cost, int Quntity, string binding); -- not using using [WebGet]
CompositeType GetDataUsingDataContract(CompositeType composite); -- not using [WebGet]
Is it mandatory to include [WebGet] attribute to all the operation contracts if we go for WebHttpbinding??.
public interface IService1
{
[OperationContract]
string GetData(int value,string binding);
[OperationContract]
[WebGet(BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "/Add?num1={x}&num2={y}")]
string AddNumbers(int x,int y);
[OperationContract]
[WebGet(BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "/Subtract?num1={x}&num2={y}")]
string SubtractNumbers(int x, int y);
[OperationContract]
String ProductDetails(string sName, int cost, int Quntity, string binding);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
}
The error message really says exactly what the problem is:
Operation 'ProductDetails' of contract
'IDemo' specifies multiple request
body parameters to be serialized
without any wrapper elements. At most
one body parameter can be serialized
without wrapper elements.
You cannot have methods which expect more than one parameter, unless you wrap those, e.g. by specifying the BodyStyle setting in the WebGet attribute.
So yes: either you have to apply a [WebGet] to each method of your REST service, or you can reorganize your methods to take in only a single parameter (e.g. by wrapping up the two or three parameters you have now into a single class that holds those multiple parameters, and then passing in an object instance of that Request class).
[DataContract]
public class AddNumbersRequest
{
[DataMember]
public int X { get; set; }
[DataMember]
public int Y { get; set; }
}
[OperationContract]
string AddNumbers(AddNumbersRequest request);