How to use XmlSerializerFormat in a Restful Webservice? - wcf

We have created a WCF webservice. We have created two operation contracts like this:
public interface IRestServiceImpl
{
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "getID/{id}")]
File getID(string id);
[OperationContract]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "auth")]
ResponseData Auth(RequestData rData); }
As you can see I have a Get and Post method. This works fine, but if I want to set the response format of my GET service,I have to use XMLSERIALIZERFORMAT tag.If I add this and then try to hit POST service, I get Error:400 "Bad Request Error". How should I set the response of my GET method in the same service.
I have tried adding another service 'Service2.svc' in the project where I have kept only GET methods and 'Service1.svc' has only POST services. In the interface of Service2, i have used XMLSERIALIZERFORMAT but still not able to hit POST service. I think I have to use DATACONTRACTSERIALIZER. But I dont know how to set the attributes in that.
Can anyone please help me out with this?
Thanks
Charan

If you want your GET to send a Response in XML then below setting on your GET method should be enough.
ResponseFormat = WebMessageFormat.Xml
You dont need to use XmlSerializerFormat. Just try to browse to your service in IE and you should see the response from your GET Method would be in XML format.
Regarding getting a Bad Request on your POST try to see on how the request body is being sent to your method. To see your request body try using tools like Fiddler to inspect your request and response. To debug the cause of Bad Request try enabling tracing on your service.
How to enable tracing on your Service

Related

Accessing API on different domain with CORS

I am working on a self-hosted WCF service with some GET and POST methods,
For Example
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
public string HelloWorld(){
....
}
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped)]
public string GetMessage(string username){
....
}
when accessing those services on the client side which is hosted on different domain, I have got the following error
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:57805' is therefore not allowed
access. The response had HTTP status code 400.
After researching on the Internet, I figured that the error can be resolved by putting the following codes in each WCF function
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Header", "Content-Type, Accept, SOAPAction");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Credentials", "false");
}
Now this block of code is working great for a GET method, so I can see there is "Access-Control-Allow-Origin" added into the response header. However it does not work for a POST method somehow as the response header has no change at all.
Does anyone have an idea why it is not working for a POST method?
I have changed the GetMessage to be a GET method, the response header worked immediately but not when I changed it back to POST
The problem is resolved!!
The code works great for both GET and POST, however the web service throw the following error for my POST function, therefore it causes a failure.
The OperationFormatter could not deserialize any information from the
Message because the Message is empty (IsEmpty = true).
By changing the BodyStyle for the function to WrappedResponse, the error gone and the function can be accessed outside the domain
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedResponse)]
Booking CreateNewBooking(int divisionId);

Make all methods in a WCF service all be GET's with the same body wrap style

I would like to make all the methods I am adding to my WCF service have the following behaviour:
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped)]
Instead of having to add these attributes to every single [OperationContract] method is there a way I can configure this service wide?

WCF REST error HTTP 307

I have a REST WCF service. When a POST attempt is made to this service to an operation as mentioned below, I get the below error:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "", RequestFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)]
void Write();
Error:
HTTP 307
There is no operation listening for https://xx.xxx.xx.xxx/EnrollmentServer/Discovery.svc, but there is an operation listening for https://xx.xxx.xx.xxx/EnrollmentServer/Discovery.svc/, so you are being redirected there.
Any pointers will be appreciated.
Change your UriTemplate to "/" instead. RESTful WCF has a "thing" about wanting Uris ending with / instead of no ending.
Also, use the Uri with the ending slash to avoid WCF responding with the 307.

Creating a WCF JSON (non RESTful) Service

I am trying to create a simple non-RESTful JSON service using WCF and .NET 4.
I'd like my service to be able to parse a JSON request message with a specific format, something like this:
{ "MethodNameRequest": { "MethodParam1Name": "ParamValue1", "MethodParam2Name": "ParamValue2" } }
The endpoint for this service should reside in a single constant URI ("http://myserver/myservice/") so that all methods could be invoked using a POST request to it.
The problem is that whenever I try to declare two (or more) methods using the same "UriTemplate" and the same HTTP verb "POST" (using WebInvokeAttribute), like this:
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json, Method = "POST", UriTemplate = "")]
public string Method1()
{
return "Method1";
}
[WebInvoke(BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json, Method = "POST", UriTemplate = "")]
public string Method2()
{
return "Method2";
}
I get the following exception:
In contract '', there are multiple
operations with Method 'POST' and a
UriTemplate that is equivalent to ''.
Each operation requires a unique
combination of UriTemplate and Method
to unambiguously dispatch messages.
Use WebGetAttribute or
WebInvokeAttribute to alter the
UriTemplate and Method values of an
operation.
Any ideas on how I can configure WCF to allow this?
I don't see how WCF could figure out which method to call if it somehow allowed the identical UriTemplate for the different methods. Seems you need to implement logic inside the method to handle content based processing.
Try to ommit the UriTemplate property, use instead the <enableWebScript/> element in web.config. This will allow wcf to automatically handle the requests for you.

WCF WebInvoke ResponseFormat

I have a WCF restul service and I want to allow the user to choose what request format they want, i have the decorations
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "getstreamurl?ch={ch}&format=xml")]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "getstreamurl?ch={ch}&format=json")]
First of, is there a way to specify the ResponseFormat at runtime and take the format in as an argument to the method? From reading around i dont think so... OK next thing
The above code is ok and works, but im having a problem, i want to be able to specify a default, so when no format arguement is passed then i just default but if i decorate like so
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "getstreamurl?ch={ch})]
[OperationContract]
[WebInvoke(Method = "GET",
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "getstreamurl?ch={ch}&format=json")]
Where the XML is the default, if i try to call the service method through the browser it tells me that:
UriTemplateTable does not support multiple templates that have equivalent path as template 'getstreamurl?ch={ch}' but have different query strings, where the query strings cannot all be disambiguated via literal values. See the documentation for UriTemplateTable for more detail
They obviously can be distinguished but it seems that WCF is only reading up to the argument and thats it...Any suggestions?
No, I don't think you can do that programmatically at runtime. What you can do of course if to expose two distinct endpoints from your service - one returning XML, another returning JSON, and then programmatically pick which one to call from your client app.
Marc
Update: as Steve Michelotti correctly points out, this automatic switching between JSON and XML can now be achieved in WCF 4.0. WCF 4.0 has an improved REST support which also includes an Format Message Selection feature, based on HTTP accept headers.
For more info on WCF 4.0's new features, see: A Developer's Introduction to WCF 4.0
You can do this if your rest service is configured automatically select response type.
Then on client request simply add needed header Accept: application/json