Handling errors raised by jQuery Ajax method - c#

I have a page in which I am using a jQuery ajax method to call a simple Webservice which will get some data from the database and bind it to some controls in the page. The ajax method is called on the onchange event of select (here the HTTP request is POST). Following is the jQuery ajax method
function CallAjax(url, jsonData, SucessFunction, FailurFunction) {
$.ajax({
type: "POST",
url: url,
data: jsonData,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: SucessFunction,
error: function(){
alert('error occured');
}
});
}
The URL for above method is somepage.aspx/getDataFromDatabse where getDataFromDatabse is the webservice method. Our testers are testing the page using burp suite. When they are directly tying to access the url(www.example.com/somepage.aspx/getDataFromDatabse) in the browser, the HTTP method shown in burp suite is GET and an error is raised and the user is getting redirected to the appropriate page. But when they are directly accessing the above URL and intercepting the request in burp suite and changing GET request to POST request the following error message is displayed directly in the browser:
{"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}
The "error" in the above ajax function is not getting executed and the alert box is not shown and we are able to handle the error. How to handle such an error and redirect the user to a custom page?

It would appear that the response from your server is a valid JSon response, despite the fact that it contains what (to you) reads as an error. As such the $.ajax(...) call is handling the response as a success, not an error.
You can return a valid JSon response and within that response indicate whether there was an error or not, along with any additional info such as a user-friendly error message, a redirect URL, etc.
The error: handler of the $.ajax(...) call should be used for real server response errors (i.e. unhandled 500 errors, timeouts etc.)
For example, your successful JSon response could be something like:
{
success: true,
errorMessage: null,
errorRedirectUrl: null,
data: { .... your successful data response .... }
}
and your failed JSon response (e.g. due to validation problems, not server failures) would look like this:
{
success: false,
errorMessage: 'There was an error processing the request.',
errorRedirectUrl: 'http://....someurl...',
data: null
}
Then you check for response.success == true in the success: option of the $.ajax(....) call, and handle appropriately.
By having a single, consistent structure the success: option handles all ajax requests which complete and then determines whether there was a handled error and what to do with it, such as display an alert to the user, redirect them to a URL, etc...
In contrast, the error: option handles only those ajax requests which didn't come back with a response you can use.
Update:
On your server you are already handling the difference between receiving a GET http request and a POST http request. So, I think your problem is that you also need to detect whether the POST request contains valid data in the format the webservice method needs.
So, your web service needs to decide if the POSTed data in the http request is in a format it expects to receive and if not return an HTTP redirect response (302) rather than returning the error.
You could do this in 2 ways:
Using a Try... Catch... block. Your webservice method already appears to be throwing an exception and returning it, so catch it and then instead of returning it, set up and return a 302 response instead.
If genuine calls to the webservice can generate exceptions under normal operations (this is usually bad!) you'll need to validate the data received in the request to see if it is what the webservice method expects to receive (was data received? was it the right structure as would be sent by the ajax request? etc.)
Note: if the request does contain valid data then there is no easy way to detect whether this came from a genuine source (the ajax call) or a forged request by some other means. There are solutions to this, but they are involved and can require multiple calls for authentication etc.

Related

POST method to send RAW TEXT data and get HTML Response using Jquery AJAX Web Method and check with POSTMAN

I'm Trying to do a POST Request using RAW TEXT.
I want to send POST Request from POSTMAN like, in body Section I've selected RAW(from radio buttons) and Text(from drop-down) and pass below simple string.
01JAINAM120112356598
Now, when we click on send in Postman, Response must come in HTML string "01" on success and "00" on error.
[Type of Request & Response I Need] https://imgur.com/bC26Pw7 (In photo URL is of .php page, but I'll pass my asp.net c# page (.aspx)).
I need to use JQuery ajax code to pass request & get proper response.
Something like,
$.ajax({
url: "RFID.aspx/saveRFIDData",
type: "POST",
dataType: "text",
success: function () {
},
error: function (response) {
alert("Error")
}
});
But, when I call above URL as post method as same shown in Image above, my WebMethod in code behind is not called.
Instead, when I call same ajax call for JSON, my WebMethod is been called.
But, I don't want to pass JSON.
So, Can anyone help me to get it done with "dataType : text" & get HTML string response.
Note : If someone didn't Understand my question. Do comment first, to be more clear rather than DEVOTE this question
It seems to be "Unsupported Media Type" issue and status may be 415. Add supported media type, that might work.

which cookies/headers should I set?

I should get a protected page from external site, if I call it directly, I get an error:
Bad Request
Postman:
But if I call a login page with valid credentials via Postman:
and then recall THE SAME resource page from the same Postman I got the protected page!:
I have to get the same page on website. I try to implement it by the following way:
var loginXml = "<Request><MsgType>Authenticate</MsgType><SubMsgType>Login</SubMsgType><UserID>my_login</UserID><passwordNotEncrypted>my_password</passwordNotEncrypted></Request>";
$.ajax(
{
url: 'https://address/browserservices.aspx/login',
type: 'POST',
contentType: 'text/xml',
datatype: 'text',
//xhrFields: {
// withCredentials: true
//},
//crossDomain: true,
data: loginXml,
success: function (output, status, xhr) {
alert(xhr.getResponseHeader("Set-Cookie"));
$.ajax({
url: "https://address/RemoteSupport.aspx?id=GUID&pltFrmType=Android&agentversion=13.46",
type: 'GET',
xhrFields: { withCredentials: true },
//crossDomain: true,
success: function (x) { },
error: function (xhr, textStatus) { alert(xhr.status); }
});
},
})
but I get Bad Request again.
Which headers/cookies should I pass to page to open protected page, like it's in Postman?
ADDED 28/01/19
Postman "Cookie" tab after success login request (fail login request has the same):
and "Headers" tab:
as I see, all access-control-allow header are available. What should I pass via ajax?
Based on the information that you have supplied there are two likely scenarios.
Firstly, the cookie that is set by the external site is HttpOnly. This is easy enough to check in Postman, by clicking on the the Cookies tab.
The second option is a little more complex, but the external server has to set the Access Control headers correctly. Again there is a Headers tab to view these. More info on cross domain ajax and headers in this question: Why is jquery's .ajax() method not sending my session cookie?
Finally worth noting, your browser will automatically add a header to indicate that it is an ajax request. You could try adding the X-Requested-With: XMLHttpRequest header in Postman and seeing how it differs from your examples. The external server may well be configured to respond differently to ajax requests than to browser or server-server api requests.
Update
Your Postman update shows that both of those scenarios are true. Unfortunately this means that you cannot achieve your desired result with JavaScript. HttpOnly = true means that the browser will never allow the script on your page to access the cookie.
At this point your best bet is probably to write a little proxy method on your own site that makes the request server to server and then returns the result to your JavaScript code. This should bypass all the above issues albeit you need to make 2 requests instead of 1 for the data.
Take a look at this answer for some code
Struggling trying to get cookie out of response with HttpClient in .net 4.5

AngularJS with C# WCF Wait for record to insert before refreshing on screen

I am new to AngularJS and building a webpage that has a history table. When an action happens an entry is made in the database using a $http.post. Afterwards I want to retrieve the data from the database again and display it back in the table to show the new entry of the history being logged.
The issue I am having is that the post is called first and then the get, but the get happens before the insert can complete. How do I delay, or prevent the call to get the new data from the history until the post has completed?
Here are the $http calls I am making:
$http.post('http://MYSERVER/Service1.svc/insertImageHistory', {params: {JSON: parameters}}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
console.log(data);
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
console.log(data);
});
$http.get('http://MYSERVER/WcfService/Service1.svc/getImageHistory', {params: {DOC_ID: DOC_ID}})
.success(function (response){
$scope.InsImageHistory = response;
alert(JSON.stringify(response));
})
.error(function(data, status) {
console.error('Response error', status, data);
});
Thanks to the help from people on this site, I figured out how to make it work now. I changed my code to use .then for my first $http.post and inside the .then I called the #http.get like so:
$http.post('http://MYSERVER/Service1.svc/insertImageHistory', {params: {JSON: parameters}})
.then(function(data, status) {
$http.get('http://MYSERVER/WcfService/Service1.svc/getImageHistory', {params: {DOC_ID: DOC_ID}})
.success(function (response){
$scope.InsImageHistory = response;
//alert(JSON.stringify(response));
})
.error(function(data, status) {
console.error('Response error', status, data);
});
});
Hope this helps someone.
A bit more information on how you are posting your data to your end point (WCF API) would be helpful, but i'll assume you are making use of $http.
A basic http request in Angular looks like this:
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function (response) {
// this callback will be called asynchronously
// when the response is available
}, function (response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
As you can see in the above example, the $http service incorporates Promises. Once it receives a response from your WCF service request, it will hit the '.then' portion of the function. This allows you to run code after you receive a response from your Get/Post request.
You can include your code in the '.then' part of the request. This way when you receive a response back from the 'Insert' api method, you can be sure that the insert has completed, and you can call your 'refresh' GET api request thereafter.
Documentation for $http can be found here - $http Service
Documentation for Promises in angular $q can be found here - Promises $q
EDIT: Okay now that I have some more information I can advise further.
If I was you, I would Create an angular Service/Factory to wrap your functionality (Object Oriented Design). You can call it "ImageService". Create Functions such as Add, Get, Delete etc Which will wrap your $http methods.
I have created a really quick and simple Plunker for you here to see what I'm talking about: Angular Promises Plunker

How to see what dataType is requested by an ajax call in asp.net api

In an ASP.NET API, how do you get what datatype is requested by an ajax call when you set requested datatype in ajax like so?
$.ajax({
url: url,
data: params,
dataType: "xml",
type: "GET",
statusCode: {
200: function (data) {
}
}
Then, in my controller, I would like to get whether I requested XML or JSON.
Thanks in advance
This goes in the accept http header - asp.net webapi will do most of the content type negotiation for you - see here
jQuery will put it in the accept header as application/json or application/xml and you can manually get it out of the request.Headers
If I am not mistaken, this information will translate as the 'Accept' header in you HTTP request. I'm not 100% sure as this might also only be info kept by JQuery to better decode the answer. In anyway, there is also an accepts parameter in the Ajax settings which sets the 'Accept' header of the request for sure. JQuery's documentation however says that the accepts parameter defaults to a value depending on the dataType parameter, so I would be tempted to say my first guess is right.
To retrieve the headers from the controller, simply call :
IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
var id = headerValues.FirstOrDefault();
(for error handling on this method see this Answer)

Dojo 1.8 web service call fails with status: 500 error code

dojo.xhrPost({
url: "Default.aspx/TestMethod",
handleAs: "json",
contentType: "application/json",
postData: dojo.toJson({ }),
load: function (result) {
debugger;
},
error: function (err) {
debugger;
}
});
That is the script I use to make a request to a WebMethod that is exposed in Default.aspx. The method is called TestMethod.
The error that I get is:
Unable to load Default.aspx/TestMethod status: 500
If you need any additional information please let me know.
*Note : I can call the method from the server side and it returns the results as intended.
I've been there. :(
Usually it is a problem with the format of the data that you are passing in. For instance, if your WebMethod has a parameter that is an int and you are passing a string, you will get a failure like this.
I would use a tool like Fiddler http://www.fiddler2.com/fiddler2/ to see what you are sending to the method.
Also turn on what ever server side logging and tracing that you have and use it. One source that is useful for 500 errors (which tend to happen before "your" server code is reached) is Asp.net health monitoring.
There is more info about setting that up and using it at http://msdn.microsoft.com/en-us/library/bb398933(v=vs.100).aspx

Categories

Resources