React Axios - C# WebAPI request token fails without a server error - c#

I have the following code:
var qs = require('qs');
const ROOT_URL = 'http://localhost:56765/';
const data = qs.stringify({ username, password, grant_type: 'password' });
axios.post(`${ROOT_URL}token`, data)
.then(response => {
debugger;
dispatch(authUser());
localStorage.setItem('token', response.data.token);
})
.catch((error) => {
debugger;
dispatch(authError(error.response));
});
When I run this code, I hit the debugger and the error object has Error: Network Error at createError (http://localhost:3000/static/js/bundle.js:2188:15) at XMLHttpRequest.handleError (http://localhost:3000/static/js/bundle.js:1724:14) in the catch block. However, in the network tab in Chrome, the Status code is 200, but when I click on the response/preview tabs of this request there is no data. If I click on continue, I actually get the token and other data in the response/preview tab as expected, but at this point it has already reached the catch block so will not hit the then block.
I have even debugged the back-end and it doesn't send back an error, so I assume this is a front end error. Does anyone know what is causing this?
Edit:
Just to add more details, if I change the request to work with fetch instead of axios, I am getting a different error TypeError: Failed to fetch. The code used for the call is:
fetch(`${ROOT_URL}token`, {
method: 'POST',
body: data
})
Also, this is an example of the postman request working correctly:

Finally found my answer. It turns out I had not enabled CORS in my WebAPI back-end for the /token endpoint. The way I was able to resolve this was by enabling CORS in the MyProject\Providers\ApplicationOAuthProvider.cs by adding the line context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); to the top of the method named GrantResourceOwnerCredentials. I do think there are better ways to enable CORS for the entire project which I will look into next!
Got some help from here about how to enable the CORS: Enable CORS for Web Api 2 and OWIN token authentication

It should work with fetch by adding content-type :
fetch(`${ROOT_URL}token`, {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
body: data
})
You can try this in axios too but it seems related to an axios bug, you can give a try by adding the params property :
axios.post(`${ROOT_URL}token`, data, params: data)

Related

React - Can't fetch image from URL but works in C#

I've a problem which I find a bit weird but it is surely obvious for you guys. I'm trying to fetch an image as blob and then convert it to base64 to store it in Azure storage later on. I get the URL for the image from an object and want to download it as base64 to my react app. I'm able to get the image and put it into a html image tag as source , and it works just fine, the image shows up. On my server I can get the image via a HTTP client request and get it just fine too.
In C#:
using (var client = new HttpClient())
using (HttpResponseMessage response2 =
await client.GetAsync("URL HERE"))
{
byte[] fileContents = await response2.Content.ReadAsByteArrayAsync()>
}
When I'm trying to fetch the image in my react app like this:
const response = await fetch('URL HERE');
OR
const response = await fetch('URL HERE', {
method: 'GET',
mode: 'no-cors',
headers: {},
});
OR
let file = await fetch('URL HERE',
{
method: 'GET',
mode: 'no-cors',
})
.then((r) => r.blob())
.then((blobFile) => {
return new File([blobFile], 'FileName', { type: 'image/png' });
});
Why is this happening in React but in C# everyting works fine and how to solve it? It eaither shows as CORS-error OR the blob is empty, size 0. If I click the link I reach the image so the URL is fine too.
Any suggestions?
Many thanks!
no-cors option is rarely a good way to fix cors errors. When you use React you use browser's system and browser send you a cors errors when it not receive a correct response. For example, if your server sends you a 500 error, oftenly you will not receive the 500 error but a cors error.
Did you try to make the same request from React with Postman ? I think, if it works woth C#, it will probaly works with Postman but just to try.
Did you make some console logs like this :
let file = await fetch('url')
.then(r => {
console.log(r);
return r.blob();
)
.then((blobResponse) => {
console.log(blobResponse);
return blobResponse; // if you want to dl the file make a new File is probably not necessary : URL.createObjectURL(blob)
});
Maybe it is a real CORS error and so you should check your server and API configuration. There is a lot of issues about it on internet.
If it is, try something like this on your API response : (do not keep 'Access-Control-Allow-Origin', '*' on production)
$response->headers->set('Access-Control-Expose-Headers', 'Access-Control-*');
$response->headers->set('Access-Control-Allow-Origin', '*');
$response->headers->set('Access-Control-Allow-Headers', '*');
$response->headers->set('Access-Control-Allow-Methods', 'HEAD, PUT, GET, POST, DELETE, OPTIONS');
$response->headers->set('Allow', 'HEAD, PUT, GET, POST, DELETE, OPTIONS');
Maybe you need too, to make a response for the OPTIONS http request. Browser send it before your request to ensure that your request will be received :
if ($request->getMethod() == 'OPTIONS') {
return $this->jsonResponse([]);
}

How can i integrate PrintFriendly API in asp.NET web form (https://www.printfriendly.com/)? [duplicate]

I'm calling this function from my asp.net form and getting following error on firebug console while calling ajax.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://anotherdomain/test.json. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
var url= 'http://anotherdomain/test.json';
$.ajax({
url: url,
crossOrigin: true,
type: 'GET',
xhrFields: { withCredentials: true },
accept: 'application/json'
}).done(function (data) {
alert(data);
}).fail(function (xhr, textStatus, error) {
var title, message;
switch (xhr.status) {
case 403:
title = xhr.responseJSON.errorSummary;
message = 'Please login to your server before running the test.';
break;
default:
title = 'Invalid URL or Cross-Origin Request Blocked';
message = 'You must explictly add this site (' + window.location.origin + ') to the list of allowed websites in your server.';
break;
}
});
I've done alternate way but still unable to find the solution.
Note: I've no server rights to make server side(API/URL) changes.
This happens generally when you try access another domain's resources.
This is a security feature for avoiding everyone freely accessing any resources of that domain (which can be accessed for example to have an exact same copy of your website on a pirate domain).
The header of the response, even if it's 200OK do not allow other origins (domains, port) to access the resources.
You can fix this problem if you are the owner of both domains:
Solution 1: via .htaccess
To change that, you can write this in the .htaccess of the requested domain file:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
If you only want to give access to one domain, the .htaccess should look like this:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin 'https://my-domain.example'
</IfModule>
Solution 2: set headers the correct way
If you set this into the response header of the requested file, you will allow everyone to access the resources:
Access-Control-Allow-Origin : *
OR
Access-Control-Allow-Origin : http://www.my-domain.example
Server side put this on top of <filename>.php:
header('Access-Control-Allow-Origin: *');
You can set specific domain restriction access:
header('Access-Control-Allow-Origin: https://www.example.com');
in your ajax request, adding:
dataType: "jsonp",
after line :
type: 'GET',
should solve this problem ..
hope this help you
If you are using Express js in backend you can install the package cors, and then use it in your server like this :
const cors = require("cors");
app.use(cors());
This fixed my issue
This worked for me:
Create php file that will download content of another domain page without using js:
<?
//file name: your_php_page.php
echo file_get_contents('http://anotherdomain/test.json');
?>
Then run it in ajax (jquery). Example:
$.ajax({
url: your_php_page.php,
//optional data might be usefull
//type: 'GET',
//dataType: "jsonp",
//dataType: 'xml',
context: document.body
}).done(function(data) {
alert("data");
});
You have to modify your server side code, as given below
public class CorsResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
}
}
You must have got the idea why you are getting this problem after going through above answers.
self.send_header('Access-Control-Allow-Origin', '*')
You just have to add the above line in your server side.
In a pinch, you can use this Chrome Extension to disable CORS on your local browser.
Allow CORS: Access-Control-Allow-Origin Chrome Extension

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

HTTP Post to Web API 2 - Options request received and handled no further request received

I have a web application using MVC and AngularJS, which connects to a Web API 2 api, that I have set up in a separate project.
Currently I am able to retrieve information from the Api with no problems.
However when I try to do a HTTP Post I am getting no response, originally I was getting a problem with the pre-flight request failing, I have now handled this in my controller, however it does not send the proper request after it has got an OK message back.
I have included my code for the Angular Factory and the C# Controller in the API.
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class RegisterController : ApiController
{
public string Post()
{
return "success";
}
public HttpResponseMessage Options()
{
return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
}
}
var RegistrationFactory = function($http, $q, ApiAddress) {
return function(model) {
// $http.post(ApiAddress.getApiAddress() + '/Register/Post', model.ToString());
$http({
method: "POST",
url: ApiAddress.getApiAddress() + '/Register/Post',
data: model,
headers: { 'Content-Type': 'application/json; charset=utf-8' }
}).success(function(data) {
$location.path("/");
});
}
};
RegistrationFactory.$inject = ['$http', '$q', 'ApiAddress'];
Edit:
I am still not having any joy with this, however I tested in Internet Explorer and it works with no problems at all.
I have got it working in chrome by starting with web security disabled, however obviously this is not ideal as it will not work on a user PC with security enabled.
I see that you have done adaptation for CORS on the server side. But I cannot see any client side (javascript) adaptation. May be you should add the code below before calling the service.
$http.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
Let me know if this fixes the issue. Worked for me in all scenarios :)
It's strange that your GETs work, but your POSTs don't.
I would recommend running the code in Google Chrome with web security enabled (so we can watch it go wrong) and with the F12 Developer Options shown.
Select the Network tab, run your code, and watch what happens when the POST is called.
Does your service return a "200 OK" status, or some other value ?
Does any kind of Response get returned ?
It might be worth trying this, and appending a screenshot of the results in your original question. It might help to identify the cause.
I am still not having any joy with this, however I tested in Internet
Explorer and it works with no problems at all.
Btw, you don't have any single sign-on stuff setup in your company, do you ? We've had issues where IE works fine, but other browsers don't allow single sign-on. Just a thought...
CORS requires a OPTIONS-preflight which has HTTP headers in its response that tell the browser whether it is allowed to access the resource.
E.g. HTTP Response Headers:
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Origin: *
Because you have a custom Options handler in your C# controller, it seems those HTTP headers are not returned, stopping the browser to make the call after the preflight.
Avoid the Options method, and you should be good.

Handling errors raised by jQuery Ajax method

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.

Categories

Resources