I'm trying to operate two servers.
MVC Web API service.
MVC Web application.
The idea is that the web application renders a page filled with javascript requests, which populate the actual data from the remote API service. The web application will never itself touch the database, or the API service (besides setting up authorisation tokens initially).
What is the best way to achieve this?
So far I've been using JQuery AJAX requests, attempting to use JSONP. However I always get "x was not called" exceptions.
$.ajax({
url: '#(ViewBag.API)api/customer',
type: 'get',
dataType: 'jsonp',
jsonp: false,
jsonpCallback: function (data) {
debugger;
// code to load to ko
},
error: function (xhr, status, error) {
alert(error.message);
}
});
Also the jsonpCallback function is called before the request is sent, so I assume its actually trying to call a function to generate a string? If I reform this request:
window.success = function (data) {
debugger;
// code to load to ko
};
... with jsonpCallback being "success", I still get the same error (but the success method is never called.
Any ideas? Thanks.
Edit: I've gotten started on the right course from this:
http://www.codeproject.com/Tips/631685/JSONP-in-ASP-NET-Web-API-Quick-Get-Started
Added the formatter, and replaced jsonCallback with success, like a normal ajax. However this only seems to work for get. I cannot delete or update. :(
Can you get it to work using the $.getJSON method?
$.getJSON( "ajax/test.json", function( data ) {
//handle response
});
Have you fired up developer tools in IE and watched the network traffic to see precisely what is being sent and returned?
Related
I have a working prototype Symfony2 RESTful webservice which I am still working on and I am trying to figure out how a client can send JSON or consume JSON data from the webservice. All I need is an example(s) on how to send a request or post data to it and I can figure out the rest. From my browser, if I visit http://localhost/app_dev.php/users.json, I get the correct result from my database as JSON, e.g.
[{"id":1,"username":"paulo","username_canonical":"paulo","email":"a#ymail.com","email_canonical":"a#ymail.com","enabled":true,"salt":"66r01","password":"UCxSG2v5uddROA0Tbs3pHp7AZ3VMV","last_login":"2013-12-03T13:55:15-0500","locked":false,"expired":false,"roles":[],"credentials_expired":false,"first_name":"Monique","last_name":"Apple"}, ... etc.
All other routes are working correctly and I can get the same result by using httpie or cURL. Now, the problem I am trying to solve is to get the same JSON data using AJAX (and mobile iOS, Android, etc later). Here is my attempt at using AJAX JS:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
$.ajax({
dataType: "json",
type: "GET",
url: "http://192.168.1.40/symfony/web/app_dev.php/users.json",
success: function (responseText)
{
alert("Request was successful, data received: " + responseText);
},
error: function (error) {
alert(JSON.stringify(error));
}
});
</script>
The AJAX alerts the following results which indicates an error:
{"readyState":0,"responseText":"","status":0,"statusText":"error"}
What am I doing wrongly and how can I solve the problem. Kindly give an example.
This is a cross-domain request issue. You need to make the request to the same domain you are on. This is a browser-level security feature.
For example, you can only request URLs on http://192.168.1.40 if you are currently ON http://192.168.1.40. This means that a request from http://192.168.1.39 (for example) won't work
I am calling the web service from other domain using Ajax call and I want to get returned response from server in my application by using following code I get response text in firebug but not in my JavaScript code. Control are not showing success and error response it goes out directly.
I want response in my success or error section but both not handling in this.
I am trying lot but not finding any solution please any one help me.
I am in a trouble. I hope somebody can help me for calling cross domain web service by using Ajax call. I am trying from 1 week but didn't find any solution till. I am getting response on browser but not getting it on my actual code.
My JavaScript code.
crossdomain.async_load_javascript(jquery_path, function () {
$(function () {
crossdomain.ajax({
type: "GET",
url: "http://192.168.15.188/Service/Service.svc/GetMachineInfo?serialNumber="+123,
success: function (txt) {
$('#responseget').html(txt);
alert("hii get");
}
});
crossdomain.ajax({
type: "POST",
url: "http://192.168.15.188/Server/Service.svc/GetEvents/",
// data: "origin=" + escape(origin),
success: function (txt) {
$('#responsepost').html(txt);
alert("hii post");
}
});
});
});
</script>
You can't simply ignore the Same Origin Policy.
There are only three solutions to fetch an answer from a web-service coming from another domain :
do it server-side (on your server)
let the browser think it comes from the same domain by using a proxy on your server
change the web service server, by making it JSONP or (much cleaner today) by adding CORS headers
I have a web site that is trying to call an MVC controller action on another web site. These sites are both setup as relying party trusts in AD FS 2.0. Everything authenticates and works fine when opening pages in the browser window between the two sites. However, when trying to call a controller action from JavaScript using the jQuery AJAX method it always fails. Here is a code snippet of what I'm trying to do...
$.ajax({
url: "relyingPartySite/Controller/Action",
data: { foobar },
dataType: "json",
type: "POST",
async: false,
cache: false,
success: function (data) {
// do something here
},
error: function (data, status) {
alert(status);
}
});
The issue is that AD FS uses JavaScript to post a hidden html form to the relying party.
When tracing with Fiddler I can see it get to the AD FS site and return this html form which should post and redirect to the controller action authenticated. The problem is this form is coming back as the result of the ajax request and obviously going to fail with a parser error since the ajax request expects json from the controller action. It seems like this would be a common scenario, so what is the proper way to communicate with AD FS from AJAX and handle this redirection?
You have two options.
More info here.
The first is to share a session cookie between an entry application (one that is HTML based) and your API solutions. You configure both applications to use the same WIF cookie. This only works if both applications are on the same root domain.
See the above post or this stackoverflow question.
The other option is to disable the passiveRedirect for AJAX requests (as Gutek's answer). This will return a http status code of 401 which you can handle in Javascript.
When you detect the 401, you load a dummy page (or a "Authenticating" dialog which could double as a login dialog if credentials need to be given again) in an iFrame. When the iFrame has completed you then attempt the call again. This time the session cookie will be present on the call and it should succeed.
//Requires Jquery 1.9+
var webAPIHtmlPage = "http://webapi.somedomain/preauth.html"
function authenticate() {
return $.Deferred(function (d) {
//Potentially could make this into a little popup layer
//that shows we are authenticating, and allows for re-authentication if needed
var iFrame = $("<iframe></iframe>");
iFrame.hide();
iFrame.appendTo("body");
iFrame.attr('src', webAPIHtmlPage);
iFrame.load(function () {
iFrame.remove();
d.resolve();
});
});
};
function makeCall() {
return $.getJSON(uri)
.then(function(data) {
return $.Deferred(function(d) { d.resolve(data); });
},
function(error) {
if (error.status == 401) {
//Authenticating,
//TODO:should add a check to prevnet infinite loop
return authenticate().then(function() {
//Making the call again
return makeCall();
});
} else {
return $.Deferred(function(d) {
d.reject(error);
});
}
});
}
If you do not want to receive HTML with the link you can handle AuthorizationFailed on WSFederationAuthenticationModule and set RedirectToIdentityProvider to false on Ajax calls only.
for example:
FederatedAuthentication.WSFederationAuthenticationModule.AuthorizationFailed += (sender, e) =>
{
if (Context.Request.RequestContext.HttpContext.Request.IsAjaxRequest())
{
e.RedirectToIdentityProvider = false;
}
};
This with Authorize attribute will return you status code 401 and if you want to have something different, then you can implement own Authorize attribute and write special code on Ajax Request.
In the project which I currently work with, we had the same issue with SAML token expiration on the clientside and causing issues with ajax calls. In our particular case we needed all requests to be enqueud after the first 401 is encountered and after successful authentication all of them could be resent. The authentication uses the iframe solution suggested by Adam Mills, but also goes a little further in case user credentials need to be entered, which is done by displaying a dialog informing the user to login on an external view (since ADFS does not allow displaying login page in an iframe atleast not default configuration) during which waiting request are waiting to be finished but the user needs to login on from an external page. The waiting requests can also be rejected if user chooses to Cancel and in those cases jquery error will be called for each request.
Here's a link to a gist with the example code:
https://gist.github.com/kavhad/bb0d8e4a446496a6c05a
Note my code is based on usage of jquery for handling all ajax request. If your ajax request are being handled by vanilla javascript, other libraries or frameworks then you can perhaps find some inspiration in this example. The usage of jquery ui is only because of the dialog and stands for a small portion of the code which could easly be swapped out.
Update
Sorry I changed my github account name and that's why link did not work. It should work now.
First of all you say you are trying to make an ajax call to another website, does your call conforms to same origin policy of web browsers? If it does then you are expecting html as a response from your server, changedatatype of the ajax call to dataType: "html", then insert the form into your DOM.
Perhaps the 2 first posts of this serie will help you. They consider ADFS and AJAX requests
What I think I would try to do is to see why the authentication cookies are not transmitted through ajax, and find a mean to send them with my request. Or wrap the ajax call in a function that pre authenticate by retrieving the html form, appending it hidden to the DOM, submitting it (it will hopefully set the good cookies) then send the appropriate request you wanted to send originally
You can do only this type of datatype
"xml": Treat the response as an XML document that can be processed via jQuery.
"html": Treat the response as HTML (plain text); included script tags are evaluated.
"script": Evaluates the response as JavaScript and evaluates it.
"json": Evaluates the response as JSON and sends a JavaScript Object to the success callback.
If you can see in your fiddler that is returning only html then change your data type to html or if that only a script code then you can use script.
You should create a file anyname like json.php and then put the connection to the relayparty website this should works
$.ajax({
url: "json.php",
data: { foobar },
dataType: "json",
type: "POST",
async: false,
cache: false,
success: function (data) {
// do something here
},
error: function (data, status) {
alert(status);
}
});
I am using this code from http://www.joe-stevens.com/2010/01/04/using-jquery-to-make-ajax-calls-to-an-asmx-web-service-using-asp-net/
function callWebService(address) {
var result;
$("#result").addClass("loading");
$.ajax({
type: "POST",
url: address,
data: "{}",contentType: "application/json; charset=utf-8",
dataType: "json",
success: Success,
error: Error
});
}
function Success(data, status) {
$("#result").removeClass("loading");
$("#result").html(data.d);
alert("Success");
}
function Error(request, status, error) {
$("#result").removeClass("loading");
$("#result").html(request.statusText);
alert("Error");
}
I don't understand what is wrong with this code. It keeps returning "Error"
Also make sure that the service URL that you're trying to access is in the same domain as your site. AJAX calls won't succeed if you cross domains, since browsers subject AJAX calls to the same domain policy. Can you also include the URL you're trying to access?
If you're trying to access a resource at a different domain, you may want to consider a JSONP request instead. See the jQuery AJAX documentation for a discussion of how to use JSONP.
I think if you combine knowing the URL you're trying to access along with Justin and mohlsen's suggestions, I think we can help.
Your code looks fine at first glance.
I recommend you use FireBug to attempt to isolate the problem further, as it will allow you to see the actual HTTP requests, POSTed data, etc...
A few suggestions based on some code I have doing this. But as others have said, make sure to manually look at the data going out and coming back. Your link references asp.net webservice, is that what you are calling since you didn't mention it.
Make sure the "address" url is of the form /location/page.asmx/methodname
You might need to pass the data to the success method in the call
success: function(msg) {
//msg is a json object, .d is the data field returned by asp.net
if (msg.d.length > 0)
ProcessData(msg.d);
else
HandleError('No data was returned.');
},
error: function() {
HandleError('There was a problem calling the webservice.');
}
Can i Call web service from java script?
Thanks
Yes, you can do this.
Definitely. We would need a bit more information to know what kind of service you are using and if you are using a JS library. This is very easy with Dojo or EXT.
I'll show you a Dojo example as that is what I'm working with the most lately. I mostly create my services as REST services at this point. Depending on the service and how it's going to be used, I either send the response back as JSON or JSONP.
Below is an example for services that send the response as JSONP, which I use for cross-domain calls. You would need to use dojo.io.script.get (if using the Dojo library):
dojo.io.script.get({
callbackParamName: 'method',
url: 'http://mydomain/myservicename/mymethodname/param1/param2',
timeout: 20000,
load: dojo.hitch(this,function(response,ioArgs) {
this.doSomething(response);
}),
error: dojo.hitch(this,function(error) {
alert('uh oh, something went wrong');
})
});
For services that send the response back as JSON, you can use the following Dojo functions:
dojo.xhr, dojo.xhrDelete, dojo.xhrGet, dojo.xhrPost, dojo.xhrPut, dojo.rawXhrPost, and dojo.rawXhrPut depending on the type of call you make. Below is an example:
dojo.rawXhrPost({
url: url,
handleAs: 'json',
postData: parametersJSON,
headers: { "Content-Type": "text/json" },
timeout: 45000,
//function to be run in case of successful call to the specified Web method
load: function(data) {
onComplete(data);
},
//function to be run in case of failed call to the specified Web method
error: function(error) {
onError(error.message);
}
});
You can call a webservice on the same server as the page with a normal XHR call. If the server is on a different server then you should use a JSONP call. NOTE the JSONP doesnt have the best error handling.
You can easily call a JSON or a RESTful web service.
For SOAP web services you need a library.