Advantages of WebInvoke POST compared to WEBGET - wcf

hi i found one of the examples of wcf REST with a WEBINVOKE method just like the following
[OperationContract]
[WebInvoke(
BodyStyle=WebMessageBodyStyle.Bare,
Method="POST",
RequestFormat=WebMessageFormat.Xml,
ResponseFormat=WebMessageFormat.Xml,
UriTemplate="CreateStudent/{StudentName}/{Chair}/{AverageNote}")]
int Insert(string StudentName, string Chair, string AverageNote);
[OperationContract]
[WebGet(
BodyStyle= WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml)]
Student[] GetAllStudents();
my question is can i use WEBGET method instead of WEBINVOKE just like below and what exactly is the difference betwenn WEBINVOKE POST and WEBGET,
as per my observation we are sending the parameters by appending query strings in the URI Templates for both WEbGet and WebInvoke POST, what are the advantages that we can get using WebInvoke POST which we can not get using WEBGET
[OperationContract]
[WebGet(
BodyStyle=WebMessageBodyStyle.Bare,
RequestFormat=WebMessageFormat.Xml,
ResponseFormat=WebMessageFormat.Xml,
UriTemplate="CreateStudent/{StudentName}/{Chair}/{AverageNote}")]
int Insert(string StudentName, string Chair, string AverageNote);

It is very big difference. First of all REST is usually used with these HTTP verbs:
GET - retrieving items
POST - inserting items
PUT - updating items
DELETE - deleting items
You should never use GET for anything else then retrieving items. Using HTTP GET for data modification is considered as a bad practice in whole web development. To trigger GET you just need to create link on the web page or simply type a URL to the browser. You will hit refresh 50 times and you have 50 same inserts. Data modification should be always done with POST. If you have form which triggers HTTP POST (Post cannot be triggered directly) and you hit refresh browser will usually ask you if you want the form to be submitted again = if you really want to post and process the data again to the server.
Another problem is that GET request can be cached and redirected but POST requests cannot.

This link should provide further insight into the answers provided:
http://blog.markkoltnuk.com/2011/02/14/understanding-wcf-webinvokewebget-attributes/
Lets explain, once and for all, what the difference between WebInvoke & WebGet.
WebGet (Commonly used to retrieve data)
The WebGet attribute exposes operations using the GET verb. You can access the endpoint is directly via a Web browser by typing the URI to the service into the address bar. Parameters can be sent within the URI either as query string parameters or embedded in the URI. The WebGet attribute should be used only for data retrieval due to its caching capabilities.
WebInvoke (Commonly used for data input/update)
The WebInvoke attribute exposes services using other HTTP verbs such as POST, PUT, and DELETE. POST is the default value but it can be changed by setting the Method property of the attribute. The WebInvoke attribute should be used only for data input/update.

To answer your question i would recommend you to understand the HTTP protocol semantics, especially HTTP Verbs, such as GET, POST, PUT, DELETE
HTTP GET is done to retrieve resource from any location and therefore the request should not alter the state of the resource.
HTTP POST is used to create and sometimes update content and hence has been used in the Insert method above.
If you run the WCF service above and see how are these request formed and server you would see that GET does not have a body payload whereas POST has. In case of POST the body contains the content that needs to be created\update.

Related

Handle JSON calls in WCF to single URL with method name contained in request body

We are replicating an existing service and need to offer the exact same contract.
Requests are posted to a single URL with the method name contained in the request body.
For example the request body of a call to LoginService.Login:
All calls will be made to: http://example.com/json
{"id": "","method":"LoginService.Login","params":{"aUserID":"flip","aPassword":"1234-613E-1240-C55D-9853F37A41B2"}}
How can we accomplish this within WCF? The response should also be JSON.
I didn't know what I wanted was called jsonrpc. Luckily somebody already tackled this problem:
Implement JSON-RPC in WCF

Implementing versioning a RESTful API with WCF or ASP.Net Web Api

Assume i've read a lot about versioning a restful api, and I decided to not version the the service through the uri, but using mediatypes (format and schema in the request accept header):
What would be the best way to implement a wcf service or a web api service to serve requests defining the requested resource in the uri, the format (eg. application/json) and the schema/version (eg player-v2) in the accept header?
WCF allows me to route based on the uri, but not based on headers. So I cannot route properly.
Web Api allows me to define custom mediatypeformatters, routing for the requested format, but not the schema (eg. return type PlayerV1 or PlayerV2).
I would like to implement a service(either with WCF or Web Api) which, for this request (Pseudo code):
api.myservice.com/players/123 Accept format=application/json; schema=player-v1
returns a PlayerV1 entity, in json format
and for this request:
api.myservice.com/players/123 Accept format=application/json; schema=player-v2
returns a PlayerV2 entity, in json format.
Any tips on how to implement this?
EDIT: To clarify why I want to use content negotiation to deal with versions, see here: REST API Design: Put the “Type” in “Content-Type”.
What you are bringing here does not look to me as versioning but it is is more of content negotiation. Accept header expresses wishes of the client on the format of the resource. Server should grant the wishes or return 406. So if we need more of a concept of Contract (although Web API unline RPC does not define one) then using resource is more solid.
The best practices for versioning have yet to be discussed fully but most REST enthusiast believe using the version in the URL is the way to go (e.g. http://server/api/1.0.3/...). This also makes more sense to me since in your approach using content negotiation server has to keep backward compatibility and I can only imagine the code at the server will get more and more complex. With using URL approach, you can make a clean break: old clients can happily use previous while new clients can enjoy the benefits of new API.
UPDATE
OK, now the question has changed to "Implementing content-negotiation in a RESTful AP".
Type 1: Controller-oblivious
Basically, if content negotiation involves only the format of the resource, implementing or using the right media type formatter is enough. For example, if content negotiation involves returning JSON or XML. In these cases, controller is oblivious to content negotiations.
Type 2: Controller-aware
Controller needs to be aware of the request negotiation. In this case, parameters from the request needs to be extracted from the request and passed in as parameter. For example, let's imagine this action on a controller:
public Player Get(string schemaVersion)
{
...
}
In this case, I would use classic MVC style value providers (See Brad Wilson's post on ValueProviders - this is on MVC but Web API's value provider looks similar):
public Player Get([ValueProvider(typeof(RequestHeadersSchemaValueProviderFactory))]string schemaVersion)
{
...
}

How to pass object to RESTful Service with GET request?

I have seen some posts in stackoverflow saying "sending list of items in the GET Method, is NOT allowed. It has to be accomplished via POST method only"
My code looks like
[OperationContract]
[WebGet(UriTemplate = "Employee/{emp}",RequestFormat=WebMessageFormat.Json)]
Employee GetEmpDetails(string emp);
and my input json object will be "{'id':1,'name':'test',....}
Is there any alternative way of achieving this issue.
Thanks
It is possible to send list of items with GET, it's just that out of the box only primitive values are supported. String values work just fine, but if you want to pass a complex object, you need to create a custom QueryStringConverter. The post at http://blogs.msdn.com/b/carlosfigueira/archive/2011/08/09/wcf-extensibility-querystringconverter.aspx explains how this can be done.
If you make your service RESTful you will most probably use HTTP PUT for Add method and HTTP POST for Update method. It is absolutely ok to pass object to these methods because objet will be part of HTTP request's body, not part of URI. URI is important for HTTP GET requests. HTTP GET requests should be only for data retrieval not for data modification.
You are mixing up HTTP GET/POST/... requests and REST GET/POST/PUT/DELETE/...
When you wanna request something RESTfully - you do a GET request. In your case I think it should look like
employee/{id}
or
employee/{name}
Please also note that usage of lowercase in the URI is preferable.
If you need multiple GET criteria, I think it could look like:
employee/id/{id}/name/{name}

Returning JSON from WCF Web API

The WCF Web API returns data either XML or JSON based on the Accept parameter in the request header not considering whether we set ResponseFormat=WebMessageFormat.Json in the WebInvoke/WebGet attributes. Is this the correct behavior of the API or a bug?
WCF Web API ignores the ResponseFormat attribute. That attribute is just there because of an effort to be backward compatible with previous WCF REST efforts.
The returned media type is based largely on the Accept header sent by the client.

How to force requests to be JSON? I.e. how to block XML body?

I have a REST WCF service and a WCF client application for it.
My operation has the WebGet attribute with the following properties: BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json
However, when I use the WCF client, the request is made with the body in XML format! This is undesirable! How can I change it to use JSON?
Furthermore, I want to prevent XML from being accepted on the server side, as well - how can I accomplish this? I would have expected specifying RequestFormat to do it but it appears to be just a suggestion?
Edit: nevermind, I am an idiot. I was looking at the wrong operation contract - the right ones were inside a #region that I had not expanded... the client works fine. The server point is still valid but in the context of this question, it's probably for the better to consider this question closed.
What do you mean you are specifying [WebGet] and getting an request with an XML body? A GET request can't have a body (any inputs must be part of the URL path or the query string). Are you talking about [WebInvoke]?
As for enforcing the request format on the server side, right now, I think WCF by default just handles both formats regardless of what you specified on the contract. You can probably enforce it yourself by looking at the request message content type and rejecting it if it's "text/xml" (or anything other than application/json for that matter).
Nevermind, I am an idiot. I was looking at the wrong operation contract - the right ones were inside a #region that I had not expanded... the client works fine. The server point is still valid but in the context of this question, it's probably for the better to consider this question closed.