question

Elado avatar image
0 Votes"
Elado asked JennyTran-3128 edited

Error fetching data from ASP.NET in ReactJS

I'm using ReactJS with functional components for my front-end trying to fetch data from the ASP.NET WebService,

from File.jsx

const URL = 'http://localhost:63579/WebService.asmx'

  const productList = () => {
     fetch(URL + '/ProductList') // It shows the error is here
       .then((response) => response.json())
       .then((data) => {
         settingResults(data);
         console.log(' fetch settingResults' + data);
       });
   };

Error:

Access to fetch at 'http://localhost:63579/WebService.asmx/ProductList' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

net::ERR_FAILED



My Chrome broswer and Visual Studio errors are in Hebrew and I can't change the language English , many people has tried but non received the answer how to do it.

Error (translated):


Application server error '/'.
The application template is not recognized for a URL that ends unexpectedly in '/ ProductList'.








dotnet-csharpdotnet-aspnet-generaldotnet-aspnet-core-webapi
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

cooldadtx avatar image
1 Vote"
cooldadtx answered cooldadtx commented

This is a CORS issue. CORS is what prevents a malicious user from injecting code into your web app that does something on a remote server without your knowledge. CORS is a security feature of the browser. When enabled (and it should be) your app is limited to talking to the URLs that you approve or in the same domain. This prevents someone from injecting additional scripts.

The specific error here is that your web app appears to be hosted at localhost:3000 but the web service you're calling is at localhost:63579. Since the domains are different CORS blocks the call for security reasons. The correct workaround is to go into your app's CORS configuration (happens at startup in ASP.NET) and add the domain(s) you want your app to communicate without outside the app's URL. Since this is environment-specific you'll most likely want to put this info into your config file and load it at runtime based upon the environment. You can read how to do that here.

· 8
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@cooldadtx
So I need to change my URL http://localhost:63579/
to http://localhost:3001/ (the URL of VS Code) ?

but where do I change it ? It's not in the Properties.

My project is ASP .NET Empty Website, it's different than the Web API 2 page you linked in your comment, for example it doesnt have "TestController "

0 Votes 0 ·

No. This is a CORS configuration issue. Did you read the link I posted on how to configure CORS in ASP.NET? This shows the method you must call on app startup for your API and what you need to apply to your API controller. For web services there isn't such an option. Here's a good article on how you can configure the older web service ASP.NET projects to support CORS although it seems like that has already been done perhaps.

It isn't clear if you have an MVC app that your React app is talking to or just a react front end. For React refer to the following discussion on how to get it configured properly with CORS. I don't use React so I cannot explain the particulars.

0 Votes 0 ·

It seems you added a mention of ASP.NET empty website after I started posting my comment. So you have an ASP.NET app that is configured that just hosts your React app, Did you enable CORS in that project?

0 Votes 0 ·
Show more comments

@cooldadtx
Front end - ReactJS to --> ASP net website to --> SQL Server
as I wrote in my comment

0 Votes 0 ·
AgaveJoe avatar image
1 Vote"
AgaveJoe answered Elado edited

ASMX is not a REST service as explained several times in your other recent threads. Configure ASMX to handle CORS and REST. Uncomment the [System.Web.Script.Services.ScriptService] in the code behind.

Add the following service protocols to web.config for HTTP GET and POST.

   <system.web>
     <compilation debug="true" targetFramework="4.7.2" />
     <httpRuntime targetFramework="4.7.2" />
     <webServices>
       <protocols>
         <add name="HttpGet"/>
         <add name="HttpPost"/>
       </protocols>
     </webServices>
   </system.web>

The following configuration adds the CORS headers to the HTTP responses from the ASMX services. It is important to understand that ASMX existed well before React.

   <system.webServer>
     <httpProtocol>
       <customHeaders>
         <add name="Access-Control-Allow-Headers" value="accept, content-type" />
         <add name="Access-Control-Allow-Origin" value="https://localhost:44363"/>
         <add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" />
       </customHeaders>
     </httpProtocol>
   </system.webServer>

The Access-Control-Allow-Origin value is the domain making the HTTP request. Use the React client application domain.

As explained in your other threads, Web API is a far better choice for modern frameworks like React because most service APIs expect a JSON response and REST documented services. ASMX returns XML/SOAP and uses WSDL documentation services. React APIs expect REST documentation not XML.

According to your previous threads and code, the ASMX service returns XML that contains an embedded JSON string. This is due to serializing the response twice. You'll need to create an XML doc and extract the JSON string from the XML doc. Then convert the JSON string to a JSON object.

 fetch('http://localhost:63579/WebService.asmx/ProductList')
     .then(response => response.text())
     .then(xml => (new window.DOMParser()).parseFromString(xml, "text/xml").documentElement.firstChild.textContent)
     .then(jsonStr => JSON.parse(jsonStr))
     .then(data => console.log(data));  

IMHO, it is much easier to return application/json content when implementing a React solution.

· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I used to work with the ASMX that returns XML/SOAP when I worked few years ago on a React Native mobile application.

The Web API is new to me, I watched with serious consideration few tutorials on YouTube and asked there questions, and I think I realize that it need to work with Postman software + changing the URL manually each time I want to invoke different method, and what about passing parameters... that is important because I need to insert at least 25 products.

Thanks

0 Votes 0 ·

@AgaveJoe
The same error with this code -

 const productList = () => {
     fetch('http://localhost:63579/WebService.asmx/ProductList')
       .then((response) => response.text())
       .then(
         (xml) =>
           new window.DOMParser().parseFromString(xml, 'text/xml')
             .documentElement.firstChild.textContent
       )
       .then((jsonStr) => JSON.parse(jsonStr))
       .then((data) => settingResults(data));
   };

120720-error.png


Some parts I don't understand yet - why all this for

 new window.DOMParser().parseFromString(xml, 'text/xml')
 .documentElement.firstChild.textContent

EDIT-UPDATE
not all I understand in the interfaces in the DAL BLL you did there.

0 Votes 0 ·
error.png (21.5 KiB)

The same error with this code -

I explained what you needed to do in my post! Your React application origin is http://localhost:3000 not 44363. My project uses port 44363.

Some parts I don't understand yet - why all this for

I explained this design issue many times across several of your threads. You design returns an XML string that contains a JSON string.

The client code must parse the XML, get the JSON string, then convert the string to a JSON object.

Review the dev branch which has Web API, ASMX, and JavaScript examples. It also fixes many, not all, of your bugs and design issues.

The main problem you are facing, is you do not understand the code. Therefore you do not understand how to fix the code when there is a error. The error you shared explicitly explains the origin bug but you have no idea what the error means.

0 Votes 0 ·

Of course I change my code to - <add name="Access-Control-Allow-Origin" value="http://localhost:3000"/> but the same error has accord as the image I put above.

I can't understand all codes and errors I'm a Junior Developer.

0 Votes 0 ·

I added SharedModel as class project and Product.cs but
trying to add reference to SharedModel in DAL BLL makes an error.
All these changes are not accepted I don't know why.

What is this for ?

     public interface IDAL
     {
         int AddProduct(Product product);
         List<Product> GetProductList();
         List<Product> GetProducts();
     }
0 Votes 0 ·

Thank you, I checked now and some how the fetch is working, I fon't know how, I didn't touch it nor change for two days and it's just working now.

Can you explain pleas e what are these parts :

response.text()) - why to text ?

And this -

.then(xml => (new window.DOMParser()).parseFromString(xml, "text/xml").documentElement.firstChild.textContent) - why to 'text/xml' ? and all the rest of the code.

I used to work with React Native so I don't understand this code.
I don't want to copy paste without understanding why and what is working.

0 Votes 0 ·
YijingSun-MSFT avatar image
1 Vote"
YijingSun-MSFT answered AgaveJoe edited

Hi @Elado ,
When a browser receives a non-simple HTTP request, the CORS protocol requires the browser to send a preflight request to the server and wait for approval (or a request for credentials) from the server before sending the actual request. therefore, a REST API resource needs to implement an OPTIONS method that can respond to the OPTIONS preflight request with at least the following response headers mandated by the Fetch standard:

  • Access-Control-Allow-Methods

  • Access-Control-Allow-Headers

  • Access-Control-Allow-Origin

Let's suppose we are making a POST request to a fictional JSON API at https://api.example.com with a Content-Type of application/json. The preflight request would be like this:

 OPTIONS / HTTP/1.1
 Host: api.example.com
 Origin: http://localhost:8100
 Access-Control-Request-Method: POST
 Access-Control-Request-Headers: Content-Type

If the server is CORS enabled, it will parse the Access-Control-Request-* headers and understand that a POST request is trying to be made from http://localhost:8100 with a custom Content-Type.The server will then respond to this preflight.
If the returned origin and method don't match the ones from the actual request, or any of the headers used are not allowed, the request will be blocked by the browser and an error will be shown in the console. Otherwise, the request will be made after the preflight.Since the API expects JSON, all POST requests will have a Content-Type: application/json header and always be preflighted. So, I suggest your ASMX service need to return JSON format.

Best regards,
Yijing Sun


If the answer is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our  documentation  to enable e-mail notifications if you want to receive the related email notification for this thread.

· 13
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I still have the same error in the ReactJS Chrome browser even with this added part in web.confic, as I was suggested above -
( see my whole comment above for more code and error screenshot)


     <system.webServer>
          <httpProtocol>
            <customHeaders>
              <add name="Access-Control-Allow-Headers" value="accept, content-type" />
              <add name="Access-Control-Allow-Origin" value="https://localhost:3000"/>
              <add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" />
            </customHeaders>
          </httpProtocol>
        </system.webServer>


0 Votes 0 ·

Read the error!!! Your React app is on port 3000 not 44363. 44363 is my JavaScript client's port.

As recommended in your other thread(s), see the dev branch. The sample solution has Web API and ASMX examples along with JavaScript client examples. The sample code highlights why Web API is a far better approach than ASMX.

Keep in mind, Web API is designed to work with SPA clients like React. The ASMX framework predates React and does not have modern SPA features. Also the ASMX serialized response contains extra information like the object type name. If you configure the web method to return JSON, see my example, then the data is in the "d" object.

0 Votes 0 ·

I answer twice
Of course I change my code to - <add name="Access-Control-Allow-Origin" value="http://localhost:3000"/> but the same error has accord as the image I put above. I changed it back to 44363 because it didnt stop the error.

I can't run ShopWebSite1-Dev it has many errors
and it has too many files in it so I can't understand which one is what.

0 Votes 0 ·
Show more comments
Elado avatar image
0 Votes"
Elado answered AgaveJoe edited

@AgaveJoe

  [WebMethod]
     public string AddProduct(Product product)
     {
         return BLL.AddProduct(product);
     }

BLL.cs

public static string AddProduct(Product product)
{
int addProduct = DAL.AddProduct(product);
return new JavaScriptSerializer().Serialize(addProduct);
}

WebService
AddProduct

examination
The test form is only available for service operations that include basic data types as parameters.

This is why I pass parameters to the SQL

waste of time
just a huge waste, and another week with errors.







· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

This is why I pass parameters to the SQL waste of time just a huge waste, and another week with errors.

This is another example that shows you do not understand the code or the ASMX help screen. The ASMX help screen explain the test method is submitting a standard form POST to the web method. Your React client application will want to submit a JSON message. I added a test web method so you can see the POST. Use the browser's dev tools.

I added an AddProduct ASMX test client to the two other tests. Just run the WebApiSite project. This step requires that you understand how to start up multiple web projects in Visual Studio. I typically set the solution properties to start the "Current selection". Then select the project and press ctrl+F5. You can do this for each of the web projects. This is handy because it starts IIS Express and hosts the app indefinitely. Or mess around with the startup option to find a configuration that fits your needs.

Keep in mind, the Dev Branch has a Web API project and a test client which you should review.

Honestly, you really need to learn the technology rather than making so many assumptions.

0 Votes 0 ·
JennyTran-3128 avatar image
0 Votes"
JennyTran-3128 answered JennyTran-3128 edited

Hey, have you resolved this issue? There are 3 suggestions for your case:

  1. If you can deploy both server and frontend in the same domain, it works well and no need to fix any things, because you are accepted by CORS policy.

  2. If you need to deploy to 2 domain and there is no issue with privacy on your server side, and you can managed server side, just enable allow CORS for your server side. (Install-Package Microsoft.AspNet.WebApi.Cors).

  3. If the server side can't enabled "allow CORS", you need to make a proxy on your frontend like this video: https://youtu.be/4B5WgTiKIOY

Hope it help.


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.