I asked almost the same question for me some month ago. My answer I describe on an example of my realization.
On the server side I have WFC service which receive requests in one of the following forms
GET /Service/RequestedData?param1=data1¶m2=data2…
GET /Service/RequestedData/IdOfData?param1=data1¶m2=data2…
PUT /Service/RequestedData/IdOfData // with param1=data1¶m2=data2… in body
POST /Service/RequestedData/IdOfData // with param1=data1¶m2=data2… in body
DELETE /Service/RequestedData/IdOfData
So requests are in REST for, but GET
requests have some optional parameters. Especially this part is a port of your interest.
Because WFC support a URL templates, the prototype of functions which reply to a client request looks like
[WebGet (UriTemplate = "RequestedData?param1={myParam1}¶m2={myParam2}",
ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
MyResult GetData (string myParam1, int myParam2);
All requests like
GET /Service/RequestedData?param1=¶m2=data2
GET /Service/RequestedData?param2=data2¶m1=
GET /Service/RequestedData?param2=data2
will be mapped to the same call from the side of my WCF service. So I have one problem less.
Now at the beginning of implementation of every method which response to HTTP GET
request I set in the HTTP header "Cache-Control: max-age=0". It means that client always try to verify client browser cache and no ajax
requests will be not easy responded from the local cache like it can do Internet Explorer.
Next I calculate always an ETag
based on my data. The exact algorithm is a subject of separate discussion, but important is, that in all responses to HTTP GET
requests exist ETag
in the HTTP header.
So clients every time verify his local cache and send GET request to server. They send the ETag
, which come from its local cache, inside of "If-None-Match
" HTTP header. Server computes the ETag
which has data, which will be sending back to this GET request. It ETag
of data is the same as in the client request server send back response with empty body and the code "304 Not Modified
" back. In this case browser gives data from the local cache.
If the same client from a unknown reason create a new version of URL request, which will be interpret from the web browser as a new URL, then web browser will not find old server response in the local cache and send one more time the same request to the server. Is it a real problem? The server send the data one more time. If you have a server side caching you can makes a little more optimization. In the most cases, the URL of GET requests will be produced by a client side JavaScript so you will be no time have such situation.
Calculation of ETag
and setting of "Cache-Control: max-age=0
" and Etag
header as well as setting "304 Not Modified
" code should do WFC service, but it is very easy.
The most important is that my implementation of ETag
calculation is not as expansive as getting the whole data from the database server and calculation MD5 cache from there. I use permanently rowversion
data type in every row of data in the SQL Server database. This rowversion
is nothing other as a counter of changes in the database. If one change a row of data rowversion
value in the corresponding row will be incremented. So if one makes SELECT
statement from maximum value of rowversion
value, and this value is not changed comparing with the previous requests, one can be sure that the data were not changed in the time period. The algorithm of calculation of ETa
g should be only sensitive to deleting of data from the table. But it is also a solved problem. A little more about this you can read in http://stackoverflow.com/questions/2658443/concurrency-handling/2663654#2663654.
I don’t want suggest my ETag
calculation as a best choice, I want only say, that calculation of ETag
can be much cheaper as calculation MD5 from the whole data.
In case of errors Server throws an exception which will be mapped to a HTTP code, which I define in the throw statement. As a body WFC sends a standard JSON object {"description":"My error text"}
. A custom error object is also possible (see http://stackoverflow.com/questions/1891119/is-webprotocolexception-included-in-net-4-0/2633677#2633677). On the client side I use jQuery and in the corresponding jQuery.ajax
inside of error event handler the error message will be decoded and displayed to the user.
So my recommendation: usage of ETag
together with "Cache-Control: max-age=0
" for all HTTP GET
requests. For all other requests I’ll recommend you implement RESTfull service. For the error implementation you should look at the most native way which is supported by the software used for server and client implementation and use this.
UPDATED: To clear the URL structure I should add following. In my service the main part like GET /Service/RequestedData/IdOfData
describes data objects requested. Parameters param1=data1¶m2=data2
corresponds mostly the information about sorting, paging and filtering of data. I use active jqGrid plugin for jQuery and if the end-user scroll in the grid to the next page, click on the column header (sorting of data) or if he set a filter with respect of searching feature, all these follows to different optional parameters appended the main URL.