WebGet and non WebGet methods in WCF Rest Service - wcf

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

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

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!

Pass Email Id as parameter in WCF restful service

Suppose I have a web service which accept email id and password as parameter in url . I have to authenticate user by email id and password. using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.ServiceModel.Web;namespace WebApp.Services{[ServiceContract]public interface IService { [WebInvoke(Method = "GET", UriTemplate = "/authenticate/{emailId}/{password}", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)] [OperationContract] Boolean Authenticate(string emailId, string password); }}
we call web service like it :
http://localhost:14176/Services/Service.svc/Authenticate/sushant.bhatnagar#greatdevelopers.com/123
because email contain '.' which is not encoded by the web browser , so web service function is not called .
There is any solution to pass email id in url other than query string .
If You could use POST:
[ServiceContract]
public interface IMyService
{
[OperationContract]
bool Authenticate(EmailCredential request);
}
[DataContract]
public class EmailCredential
{
[DataMember]
public string EmailId {get; set;}
[DataMember]
public string Password {get; set;}
}
and call service using WebClient or WebHttpRequest with that xml (i don't know now how json looks like for this so xml)
<EmailCredential >
<EmailId >sushant.bhatnagar#greatdevelopers.com</EmailId >
<Password >123</Password >
</EmailCredential >

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