WCF Restful service parse enum within json cause error - wcf

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

Related

Custom WCF REST Service Hosted in SharePoint 2013

I followed this wonderful post
SharePoint 2013: Create a Custom WCF REST Service Hosted in SharePoint
Now when I call a "GET" request everything work as expected. My problem with "POST" request, it always return 404 not found error response!
[OperationContract]
[WebInvoke( Method = "POST",
UriTemplate = "Approve",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
bool Approve(PendingMeRequest pendingRequest);
Approve implementation is simple and return true
public bool Approve(PendingMeRequest pendingRequest)
{
return true;
//SPUser currentuser = SPContext.Current.Web.CurrentUser;
//return Take_approval_action(pendingRequest, "approve", currentuser.LoginName);
}
PendingMeRequest Model is simple with 3 string fields
public class PendingMeRequest
{
public string Key { set; get; }
public string RequestedBy { set; get; }
public string RequestTitle { set; get; }
}
When I call this method with jquery I get 404 not found error
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + '/_vti_bin/UnifiedWorklistService.svc/Approve/',
method: 'POST',
dataType: 'JSON',
data: JSON.stringify({pendingRequest: obj}),
contentType: 'application/json; charset=utf-8',
success: function (data) {
alert(data);
}
});
I tried to call it from POSTMAN but I got the same error
I think i miss something with Sharepoint configuration but I cannot figure it out
UPDATE:
After few hours of searching finally I found the problem, it is the trailing slash in the ajax call /_vti_bin/UnifiedWorklistService.svc/Approve/ should be removed!!
I cannot believe the time I wasted to figure it out...

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

Passing List<string> in WCF Rest Post Method

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!

Calling wcf rest service from jquery doesn't work

I have written a really simple wcf rest service which seems to work fine when I make requests to it through fiddler but I cannot get it to work when calling it from JQuery.
Service:
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "POST",
UriTemplate = "customers/{regionId}",
ResponseFormat = WebMessageFormat.Json
)]
Customer[] GetCustomers(String regionId);
}
[DataContract]
public class Customer
{
[DataMember]
public Guid Id { get; private set; }
[DataMember]
public String Name { get; private set; }
public Customer(Guid id, String name)
{
Id = id;
Name = name;
}
}
public class Service1 : IService1
{
public Customer[] GetCustomers(String regionId)
{
return new[]
{
new Customer(Guid.NewGuid(), "john"),
new Customer(Guid.NewGuid(), "pete"),
new Customer(Guid.NewGuid(), "ralph")
};
}
}
I can make requests to this service via fiddler and it returns the expected json. However, when I try and call it with JQuery ajax via the firebug console it always fails. Here is the call:
$.ajax({
type: "POST",
data: "{}",
url: "http://127.0.0.1:8081/json/customers/1",
contentType: "application/json; charset=utf-8",
dataType: "json",
success:function(res)
{
alert('success');
},
error: function(xhr)
{
alert('failed: '+xhr.responseText);
}
});
I always get the failed alert and the responseText is always blank. Any ideas would be greatly appreciated.
When you say "via Fiddler" do you mean "using Fiddler's request builder" or do you mean "with Fiddler running?"
Question: What URL is your website running on? You cannot generally make XHR requests to different servers (or ports, in FF) using XHR.