asmx WebMethod caching on POST request in asp.net - asp.net

I am using jQuery to get back some JSON data from the server. I am using a POST verb, but even after setting the WebMethod CacheDuration attribute, the JSON doesn't get cached.
I checked the response headers with firebug and the Cache-Control is still set to no-cache.
How can i cache these request on the client and avoid the server to be hit every time.
UPDATE
After reading this post from scottGu I thought it would have been safe to go on to use a POST request. Does his post not apply to the kind of operation i would be trying to do ? (getting data from the server without modifying it). In fact after changing the verb to GET, i am not even getting to the web service ...

You should be using a get request. Post does not cache by default. You can try to get a post to cache by using .ajax() and setting cache to true and type to post. I cannot say that this will work as typically you would not expect a post to cache. I suggest using get.
E.g
$.ajax( { url: '/bla',
type : 'post',
data : dataObj,
cache : true } );

Use the GET keyword instead if you want to use caching. There is a similar question on SO.

I've noticed differences in the way ASP.NET caches responses depending upon whether the caching parameters are query string parameters or (in my case with ASP.NET MVC) route parameters.
I never completely figured out exactly what the conditions were, but this may help someone.

Related

Pre-Flight Http 'OPTIONS' Method being sent instead of 'DELETE'

I've been stuck on this for a few hours with no luck, so I figured that I would ask here.
I have a service with a bunch of endpoints, most of which accept GET and POST http methods. In that case, my service simply specifies Access-Control-Allow-Origin to be * in the response headers, in the event that one of my apps is on a different domain/port and wants to use the service.
I have one endpoint that uses the DELETE http method, and I can't seem to get it to work. When I call this endpoint from my client app, I get this message in my console:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
I've been reading up on CORS for the past couple hours and have tried a few different things, all of which have not worked. I (think I) at least understand that when I'm using http methods other than GET and POST, the browser sends a pre-flighted request with OPTIONS as the http method.
What is the best way to handle this? Is there a way to disable this pre-flighted request? I specify in my client app that the http method to call this endpoint is DELETE. Should I be putting something specifying headers in my AJAX function that calls this endpoint (I'm using straight JavaScript)?
If I can't figure out a way around this, I'm just going to change my endpoint to use a GET or POST method, but I wanted to find a way to handle this issue before I took the easy way out.
I (think I) at least understand that when I'm using http methods other than GET and POST, the browser sends a pre-flighted request with OPTIONS as the http method.
Yes
Is there a way to disable this pre-flighted request?
No there isn’t. It’s initiated by browsers automatically, with no way to disable it from your JS. As long as you’re sending that DELETE request cross-origin in your JS, browsers will do that preflight.
Should I be putting something specifying headers in my AJAX function that calls this endpoint?
Given the “No 'Access-Control-Allow-Origin' header is present on the requested resource” message you’re getting, no changes you make in your client code will make any difference.
The place where more headers need to be sent to deal with this is instead on the server side.
If I can't figure out a way around this, I'm just going to change my endpoint to use a GET or POST method
You might want to experiment with trying that first. It seems even if you make that change you’re still gonna get that “No 'Access-Control-Allow-Origin' header is present on the requested resource”.
The SO question "No 'Access-Control-Allow-Origin' header is present on the requested resource" is a good place to read up on this to get a better idea of what’s happening.

Why a browser only supports GET and POST HTTP methods?

I read the following text from Apress Apache Tomcat 7
The HttpServlet.service() method implementation is a convenient way to
control access to your servlets in the code. For example, servlets
that delete data from the database should always be accessed using the
DELETE method, but because browsers only support GET and POST
operations, the POST method should be used instead.
It seems most browsers only supports 2 HTTP methods, GET and POST.
If so, why?
In a form the only possible methods are GET and POST. When you make an AJAX call, other methods are supported.
<form>:
method = get|post [CI]
This attribute specifies which HTTP method will be used to submit the form data set. Possible (case-insensitive) values are "get" (the
default) and "post".
XMLHttpRequest:
method
The HTTP method to use, such as "GET", "POST", "PUT", "DELETE", etc. Ignored for non-HTTP(S) URLs.
There are modern browsers which allow GET, POST, PUT and DELETE using the XMLHttpRequest. You can go through this bug 10671
Executing PUT and DELETE to modify resources on the origin server is
straight-forward for modern Web browsers using the XmlHttpRequest
object. For unscripted browser interactions this not so simple.
Typically, devs and frameworks end up creating work-arounds that mimic
the HTTP PUT/DELETE + Etag interaction using a "POST FORM" coupled
with specialized server-side code to sort out the special case and act
as if the proper HTTP Method was used in the request
Other considerations:
Using POST as a tunnel instead of using PUT/DELETE can lead to
caching mis-matches (e.g. POST responses are cachable5, PUT responses
are not[6], DELETE responses are not[7])
Using a non-idempotent method (POST) to perform an idempotent
operation (PUT/DELETE) complicates recovery due to network failures
(e.g. "Is is safe to repeat this action?").
You can also refer this thread: Are the PUT, DELETE, HEAD, etc methods available in most web browsers?

Is caching in browser automatic?

I have a JavaScript app that sends requests to REST API, the responses from server have cache headers (like ETag, cache-control, expires). Is caching of responses in browser automatic, or the app must implement some sort of mechanism to save the data?
An AJAX request is no different from a normal request - it's a GET/POST/HEAD/whatever request being sent by the browser, and it is handled as such. This is confirmed here:
The HTTP and Cache sub-systems of modern browsers are at a much lower level than Ajax’s XMLHttpRequest object. At this level, the browser doesn’t know or care about Ajax requests. It simply obeys the normal HTTP caching rules based on the response headers returned from the server.
As per the jQuery documentation, caches can also be invalidated in at least one usual way (appending a query string):
cache (default: true, false for dataType 'script' and 'jsonp')
Type: Boolean
If set to false, it will force requested pages not to be cached by the browser. Note: Setting cache to false will only work correctly with HEAD and GET requests. It works by appending "_={timestamp}" to the GET parameters. The parameter is not needed for other types of requests, except in IE8 when a POST is made to a URL that has already been requested by a GET.
So in short, given the same headers, AJAX responses are cached the same way as other requests.
Browser handles automatically cache of resources. What you seem to be asking about is the actuall response from the server.
You will need to set that up yourself in your application. You can do so both on front-end and backend.
Most of JS frameworks have cache control implemented, for example:
jQuery
$.ajaxSetup({
// Disable caching of AJAX responses
cache: false
});
AngularJS
$http.defaults.cache = false;
etc.
On backend it really depends on what language you using, what server engine etc.
Checkout Memcached for example
http://memcached.org/
As with anything with web development there are odd things here and there, for example some IE versions are automatically chaching requests and you have to add unique id to the url to prevent that.
From https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started :
Note 2: If you do not set header Cache-Control: no-cache the browser will cache the response and never re-submit the request, making debugging "challenging." You can also append an always-diferent aditional GET parameter, like the timestamp or a random number (see bypassing the cache)
Browser should handle the cache automatically.
Check this article, there's only clear cache method for javascript.
https://developer.chrome.com/extensions/browsingData
If the server sends the response with any of cache headers browsers should respect it. there is no difference between resources or ajax requests.
also you can specify cache headers in your ajax calls to make it not use caches and fetch the whole response from the server.
Most modern browsers support browser caching because of the cache and expire headers
http://www.arlocarreon.com/blog/http/http-requests-and-your-browsers-cache/
There are 2 apects of an HTTP request that can qualify it for being cached:
- Specifc HTTP cache and expire headers
- A unique URL
Interesting read:
http://www.mobify.com/blog/beginners-guide-to-http-cache-headers/

Which REST operation (GET, PUT, or POST) for validating information?

My users enter a few information fields in an iOS app.
This information must be validated on my server, which has a RESTful API.
After validation the UI of the iOS app changes to indicate the result.
Neither GET, PUT, or POST seem to be appropriate, because I'm not getting a resource, and neither is a resource created or updated.
What is the best fitting REST operation to implement this validation?
I use the same scenario as you and use PUT for it. You have to ask yourself: "when I send the same request twice, does this make a different state on server?" If yes, use POST, if no use PUT.
My users enter a few information fields in a iOS app. This information
must be validated on my server, which has a RESTful API. After
validation the UI of the iOS app changes to indicate the result....I'm
not getting a resource, and neither is a resource created or updated.
Since you aren't saving anything (not modifying any resource), I'd think this is technically more RPC than RESTful to me.
The following is my opinion, so don't take it as gospel:
If the information is simply being submitted and you're saying yes or no, and you're not saving it, I'd say POST is fine..
If information were actually being saved / updated, then choosing the proper HTTP method would be a lot more relevant.
POST = CREATE / SUBMIT (in an RPC context)
PUT = UPDATE (or CREATE if there is nothing to UPDATE)
I recommend using a ValidationResource and two requests. Each instance of this resource represents the validation of a set of data. The workflow:
1. Create new ValidationResource
Request: POST /path/to/validations
data to validate as the body
Response: 201 Created
Location: /path/to/validations/<unique-id-of-this-validation>
2. Look up result
Request: GET /path/to/validations/<unique-id-of-this-validation>
Respons: 200 OK
body: {'valid': true} or {'valid': false}
This is a RESTful approach in which the Validation is a Resource with server state.
Google proposes use of Custom Methods for REST API
For custom methods, they should use the following generic HTTP
mapping:
https://service.name/v1/some/resource/name:customVerb
The reason to use : instead of / to separate the custom verb from the
resource name is to support arbitrary paths. For example, undelete a
file can map to POST /files/a/long/file/name:undelete
Source: https://cloud.google.com/apis/design/custom_methods
So for validation the URL should be POST /resource:validate
I believe it is similar to GET entity but since we need to send data to validate and sending confidential data in URL is wrong habit as only payload data is ciphered by TLS, the only way left is POST or PUT.
However you may save or update the data in validate(eg. "verified":false). Based on requirement, you can go for POST or PUT (recommended POST if no update)
POST /user/validate-something
It seems like you're not doing it the correct way, if the validation is at the server-side then it should happen while submitting the data using a POST method. Then you'll validate that data, if validation fails then you can raise a 400 BAD REQUEST error, else you can create the resource.
This approach is more RESTful, as the POST method is properly used to create a resource or to raise 400 if validation fails

Supporting both ASP.NET Caching and ETag/Conditional GET in WCF WebHttp Service

I am trying to implement a REST web service with WCF that supports both caching and Conditional GETs.
I implemented basic caching following the instructions in MSDN: Caching Support for WCF Web HTTP Services. That means adding an [AspNetCacheProfile("MyOutputCacheProfile")] attribute to each of my web methods and adding appropriate entries to web.config. That seems to work correctly: cached responses are returned when identical arguments are passed to the web methods.
Then I added support for Conditional GET by calculating an ETag value and setting that on the response like this:
WebOperationContext.Current.OutgoingResponse.SetETag(myETag);
That sorta works: I can see the ETag header in the response the first time I call the web method.
But here's the problem: The next time I invoke that web method with the same arguments, a cached response is returned, and the cached response does not include the ETag header. (If I wait until cache expiration, or disable caching entirely, then the ETag headers are returned properly.)
So, is there any way get the cached responses to include that ETag value?
Update: After some more study and experimentation, I find that doing this causes the ETag header to be included in all cached responses:
HttpContext.Current.Response.Cache.SetETag(myETag);
If I call that, then I don't need to call the associated WebOperationContext...SetETag() operation to make everything work.
Is this the Right Way to do this?
Correct me if I am wrong. Restful service are more close to Http and Http caching says that
The goal of caching in HTTP/1.1 is to eliminate the need to send
requests in many cases, and to eliminate the need to send full
responses in many other cases. The former reduces the number of
network round-trips required for many operations; we use an
"expiration" mechanism for this purpose (see section 13.2). The latter
reduces network bandwidth requirements; we use a "validation"
mechanism for this purpose (see section 13.3).
Asp.net caching does not fall in any one of this category(neither expiration nor validation).The caching is only done on web server and IIS instead of executing the method, sends the stored response. Some how it does not fit in RESTful model.
To implement caching, we should add Cache Control Headers and Etag to response headers and then try to handle conditional Get. Please consult this excellent article.

Resources