How to cache .NET Web API requests (& use w/ AngularJS $http) - c#

I have a Web API written in ASP.NET that I'm consuming via AngularJS $http.
I have enabled caching in my AngularJS factory as follows but every request still returns a response of 200, never 200 (from cache) or 304 (and by every request I mean making the same web api request numerous times on the same page, revisiting a page I've already visited that contains a Web API request, refreshing said page etc).
angular.module('mapModule')
.factory('GoogleMapService', ['$http', function ($http) {
var googleMapService = {
getTags: function () {
// $http returns a promise, which has a 'then' function, which also returns a promise
return $http({ cache: true, dataType: 'json', url: '/api/map/GetTags', method: 'GET', data: '' })
.then(function (response) {
return response.data;
});
};
return googleMapService;
}]);
Am I missing something from the AngularJS side of things? Or is this a Web API problem. Or both?

Turns out it was a Web API thing. I'd overlooked the fact that the response header clearly stated that caching was disabled.
Response as viewed in the Network tab of Google Chrome:
Upon further investigation (and as seen in the image above), caching is disabled in Web API controllers. Even the [OutputCache] attribute, which is used in regular MVC controllers, isn't supported.
Luckily I found this blog:
http://www.strathweb.com/2012/05/output-caching-in-asp-net-web-api/
which lead me to these two solutions:
ASP.NET Web API CacheOutput
CacheCow
I decided to go with CacheOutput as it lets me use attributes like:
[CacheOutputUntilToday] which supports server & client side caching.
Or if I wanted to just use client-side caching I can use something like:
[CacheOutput(ClientTimeSpan = 100, ServerTimeSpan = 0)]
Which seemed a little easier at first glance that CacheCow's approach. And easier to refactor out later if need be.
Now additional requests give me a 200 (from cache):
With a refresh giving me a 304 Not Modified:
Problem solved! Hope this helps someone else.

Related

Unable to make cross domain AJAX request (localhost:50675 to localhost:27081) using IIS Express with 2 separate projects in the same solution

In Visual Studio 2015 I have 2 projects in my solution: ASP.NET MVC app and an ASP.NET Web API app. The MVC app uses a different port in IIS express than the Web API app.
In the debugger I see that I end up in the ChangeName method Web API controller, but the parameter never gets set and then in the console I see errors. The errors have to do with cross domain problems.
Is it this complicated to make a jQuery AJAX request to a different domain? When I use fiddler everything works fine.
The domain for the app that the below code is in is: localhost:50675 and I am trying to make a request to another project in the same solution that is localhost:27081
Here is my AJAX request:
$("#btnChangeName").click(function() {
var name = $("#Name").val();
var url = 'http://localhost:27081/api/products/changename';
$.ajax({
url: url,
type: 'POST',
dataType: 'text',
data: JSON.stringify({name: name}),
success: successFuncApi,
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
});
Here is one of the errors I am seeing in the console:
XMLHttpRequest cannot load http://localhost:27081/api/products/changename.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:50675' is therefore not allowed access.
The response had HTTP status code 500.
I am not sure if the error is due to my controller erroring since the param is null or if it is the root of my problem.
The Error occurs because you send a request from origin (source) to another one.
all you need to do is to enable cross origin in your backend (or your ASP.NET Web API) to be added in the header.
this link will give you more information, and guide you to enable cross-origin requests.
This error might go away, when you move your apps to production (depending on the setup of webservers). As for now, I would try something, as explained here Enabling Cross-Origin Requests in ASP.NET. If this doesn't fit your situation, there are other ways to enable the same thing.
You could also deploy your apps on IIS. Create app for client, then add new app to that app for webapi.

Web API GET vs POST

I initially setup a Web API (not any expert with web api) and followed someone's tutorial online for passing in parameters to a simple get API call.
I had originally created a GET with query strings but as the tutorial showed how using POST allows me to pass JSON to an class object in POST API parameter, it seemed a good idea.
Later on one developer said this was bad practice? Is it? Should I always use GET instead of POST which in essence is what it should be anyway... a GET call, but I like the idea of passing parameters via an object and avoiding a long API call with query strings.
So:
$.ajax({
url: '\api\getlist\1?param2=yyyy&param3=kikkkk&param4=88' etc
})
or
var params = ....
$.ajax({
url: '\api\getlist\',
data: params
})
What should I do, change the code back to using GET? What about caching?
You should take a look at the http documentation in w3c.
GET is recommended for reading data and POST is used to send information (write operations) into the server.
From client side perspective, you could set in jquery ajax setup, to do not use cache with the follow code:
$.ajaxSetup({
cache: false
});
It will generate a random argument on the async request to make a different request everytime, add a parameter like this: ?_=31312312312.

cross domain ajax POST to web-api always return empty response

I want to POST HTML form to web-api.
If I execute ajax POST with jQuery in other domain everything is OK and I receive 200 OK but in firebug and response tab I receive blank response like below image.
this is my jQuery code:
var formData = new FormData($('form')[0]);
var response = '';
$.ajax({
url: 'http://localhost:2143/api/controller',
type: 'POST',
// Form data
data: formData,
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false,
success : function(text)
{
response = text;
alert(response);
}
});
Please help me...
Due to the same origin policy restriction that's built in browsers it is not allowed to perform cross domain AJAX calls. You have a couple of possiblre workarounds:
JSONP - The idea here is that your server will wrap the JSON response in a callback. This works only with GET requests, so it might not be suitable for your case from what I can see you are attempting to send a POST request. You could use a custom JsonpMediaTypeFormatter as shown in this similar post.
CORS - the server should send a special Access-Control-Allow-Origin response HTTP headers. The drawback here is that older browsers might not support it. Here's a blog post covering this in more details.
Server side bridge. If the previous 2 techniques didn't work for you because of the constraints they are imposing you could have a server side script on the domain hosting your javascript that will act as a proxy between your domain and the remote domain hosting the API. In this case you will send the AJAX request to your own domain which in turn will call the remote API and return the result to the client.

Calling cross domain asmx web service using JavaScript

I have written a web service. I am calling this web service using JavaScript. I am calling this from different domain. For that I have added [System.Web.Script.Services.ScriptService] property in the web service. From JavaScript I am calling the service using XMLHttpRequest. I tested it using Firefox and everything was fine when. But it was not working in IE.
After some searching I found that this is an issue related to Cross domain calling. I have gone through some of the questions posted here. And then I did the following changes in my code -
From javaScript I am now calling the service using XDomainRequest.
I have added following lines befor the return statements in the web-service - HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Origin", "*");
HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Credentials", "true");
return result;
It is still working fine in firefox. but in IE8 (as per my knowledge, XDomainRequest will not work in lower versions of IE) it is showing error (XDomainRequest.onerror).
Am I missing something?
The crux of your problem in IE is that XDomainRequest doesn't support the pre-flighting necessary to make a cross-domain request that includes a Content-Type header. I believe that's fixed in IE10, but even IE9 doesn't fully support CORS.
To reliably make cross-domain requests to ScriptServices in browsers that don't support CORS well, a server-side proxy is (unfortunately) your best bet.
Look into JSONP (json with padding).
Question about JSONP:
jsonp with jquery
Has some more info about it: http://api.jquery.com/jQuery.ajax/
your web service runs over HTTP right?
I don't recommend using the native XMLHttpRequest to make ajax request, maybe you should use Jquery to do this, I always do in that way and works in all modern browsers:
i.e:
function Activate(EmailId, controle) {
$.ajax({
type: "POST",
url: "/Page/Method",
data: "&EmailId=" + EmailId,
success: function (message) {
$(controle).text(message);
}
});
}
EDIT: to make cross-domain requests you can use the James Padolsey plug-In, and do something like this:
$('#container').load('http://google.com');
$.ajax({
url: 'http://news.bbc.co.uk',
type: 'GET',
success: function(res) {
var headline = $(res.responseText).find('a.tsh').text();
alert(headline);
}
});

How to make an ajax call to another domain?

I am trying to build an interface that communicates with a REST API for attask.com. Their API is convenient because it returns JSON. I thought that was perfect because I could forget about server-side C# code and just write the interface using jQuery and AJAX. However, when I try to make an AJAX request to their API I get an error in Chrome's javascript console:
Origin http://mysite.com is not allowed by Access-Control-Allow-Origin.
What does this mean? Is this the browser preventing the request? If so, why?
Update:
If I don't have any control over the server and it does not respond to JSONP requests, is my only option to employ a server-side REST client and have my AJAX talk to my own domain instead of attempting to go cross-domain?
I found that jQuery-JSONP is the easiest way to do this.
jQuery JSONP is an alternative solution to jQuery's implementation of JSONP
jQuery-JSONP features:
error recovery in case of network failure or ill-formed JSON responses,
precise control over callback naming and how it is transmitted in
the URL,
multiple requests with the same callback name running concurrently,
two caching mechanisms (browser-based and page based),
the possibility to manually abort the request just like any other AJAX request,
a timeout mechanism.
Sample Code to Get user profiles from YouTube
function getProfile(userId) {
$.jsonp({
"url": "http://gdata.youtube.com/feeds/api/users/"+userId+"?callback=?",
"data": {
"alt": "json-in-script"
},
"success": function(userProfile) {
// handle user profile here
},
"error": function(d,msg) {
alert("Could not find user "+userId);
}
});
}
For more samples.
Alternatively, you can use the fututre standard Cross Origin Resource Sharing that is supported on modern browsers and fallback to JSONP for the other browsers.
You'll want to use JSONP, JQuery has nice support for this built in. See JQuery Documentation for more info.
You need to make a JSONP request to perform a cross domain AJAX request, you can do this by appending
callback=?
To the URL you send the request to

Categories

Resources