title: Fetch Command Between React Native and C# WebAPI on Localhost Returns Network Request Failed error
body: <p>I'm having an issue in React Native in Android and iOS where I'm trying to run a <code>fetch</code> command to point to a C# WebAPI endpoint running on my <code>localhost</code>.  I keep getting the following error:</p>
  <p><code>[TypeError: Network request failed]</code></p>
  <p>I notice that if I have the <code>fetch</code> command point to an external source (see comment in the code below) that the <code>fetch</code> works just fine.  But for a <code>localhost</code> connection, I can't get this thing to work at all.</p>
  <p>Here's the code for my login page in React Native:</p>
  <pre><code>import &quot;react-native-gesture-handler&quot;;
  import { StatusBar } from &quot;expo-status-bar&quot;;
  import React, { useState, Component } from &quot;react&quot;;
  import {
    StyleSheet,
    Text,
    TextInput,
    View,
    Button,
    Dimensions,
    TouchableOpacity,
  } from &quot;react-native&quot;;
  import { NavigationContainer } from &quot;@react-navigation/native&quot;;
  import { createStackNavigator } from &quot;@react-navigation/stack&quot;;
  import NetInfo from &quot;@react-native-community/netinfo&quot;;
  import { getUniqueId } from &quot;react-native-device-info&quot;;
  import { API_URL, PRIMARY_COLOR, QUATERNARY_COLOR } from &quot;../env.json&quot;;
  import * as Linking from &quot;expo-linking&quot;;
  
  var width = Dimensions.get(&quot;window&quot;).width - 20;
  
  const LogInTheUser = (emailAddress, password) =&gt; {
    console.log(`${API_URL}/Login`);
    let userInfo = fetch(`https://localhost:44371/api/Login`, {
      //&quot;https://devapi.flouriish.io/api/Login&quot;, {
      method: &quot;POST&quot;,
      cache: &quot;no-cache&quot;,
      mode: &quot;cors&quot;,
      headers: {
        &quot;Content-Type&quot;: &quot;application/json&quot;,
      },
      body: JSON.stringify({
        emailAddress: emailAddress,
        password: password,
        ipAddress: ipAddress,
        deviceUUID: deviceUUID,
      }),
    })
      .then((response) =&gt; response.json())
      .then((responseData) =&gt; {
        console.log(responseData);
        return responseData;
      })
      .catch((error) =&gt; console.warn(error));
  };
  
  const deviceUUID = getUniqueId();
  let ipAddress = &quot;127.0.0.1&quot;;
  NetInfo.fetch().then((state) =&gt; {
    ipAddress = state.details.ipAddress;
  });
  
  export default class Login extends Component {
    state = {
      emailAddress: &quot;&quot;,
      password: &quot;&quot;,
    };
    static navigationOptions = {
      title: &quot;ResetPassword&quot;,
    };
  
    render() {
      return (
        &lt;View style={styles.login}&gt;
          &lt;Text style={styles.label}&gt;Email Address&lt;/Text&gt;
          &lt;TextInput
            style={styles.input}
            placeholder=&quot;Email Address&quot;
            placeholderTextColor={PRIMARY_COLOR}
            onChangeText={(value) =&gt; this.setState({ emailAddress: value })}
            value={this.state.emailAddress}
          /&gt;
          &lt;Text style={styles.label}&gt;Password&lt;/Text&gt;
          &lt;TextInput
            style={styles.input}
            placeholder=&quot;Password&quot;
            placeholderTextColor={PRIMARY_COLOR}
            onChangeText={(value) =&gt; this.setState({ password: value })}
            value={this.state.password}
            secureTextEntry={true}
          /&gt;
          &lt;Text style={styles.label}&gt;IP Address: {ipAddress}&lt;/Text&gt;
          &lt;Text style={styles.label}&gt;Device UUID: {deviceUUID}&lt;/Text&gt;
          &lt;Button
            title=&quot;Login&quot;
            color={PRIMARY_COLOR}
            onPress={() =&gt;
              LogInTheUser(this.state.emailAddress, this.state.password)
            }
          /&gt;
          &lt;TouchableOpacity
            style={styles.label}
            onPress={() =&gt; this.props.navigation.navigate(&quot;ForgotPassword&quot;)}
          &gt;
            &lt;Text style={{ color: PRIMARY_COLOR }}&gt;Forgot Password?&lt;/Text&gt;
          &lt;/TouchableOpacity&gt;
  
          &lt;StatusBar style=&quot;auto&quot; /&gt;
        &lt;/View&gt;
      );
    }
  }
  
  const styles = StyleSheet.create({
    login: {
      flex: 1,
      backgroundColor: QUATERNARY_COLOR,
      alignItems: &quot;center&quot;,
    },
    label: {
      marginTop: 10,
      color: PRIMARY_COLOR,
      marginBottom: 10,
    },
    input: {
      height: 40,
      width: width,
      margin: 12,
      borderWidth: 1,
      borderColor: PRIMARY_COLOR,
      color: PRIMARY_COLOR,
    },
  });
  </code></pre>
  <p>Here's the <code>AndroidManifest.xml</code> for the React Native app:</p>
  <pre><code>&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; package=&quot;com.akmaziofrontend&quot;&gt;
    &lt;uses-permission android:name=&quot;android.permission.INTERNET&quot;/&gt;
    &lt;uses-permission android:name=&quot;android.permission.SYSTEM_ALERT_WINDOW&quot;/&gt;
    &lt;uses-permission android:name=&quot;android.permission.READ_PHONE_STATE&quot;/&gt;
    &lt;uses-permission android:name=&quot;android.permission.VIBRATE&quot;/&gt;
    &lt;uses-permission android:name=&quot;android.permission.MODIFY_AUDIO_SETTINGS&quot;/&gt;
    &lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot;/&gt;
    &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot;/&gt;
    &lt;application android:name=&quot;.MainApplication&quot;
                 android:label=&quot;@string/app_name&quot;
                 android:icon=&quot;@mipmap/ic_launcher&quot;
                 android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
                 android:allowBackup=&quot;false&quot;
                 android:theme=&quot;@style/AppTheme&quot;
                 android:usesCleartextTraffic=&quot;true&quot;&gt;
      &lt;meta-data android:name=&quot;expo.modules.updates.EXPO_UPDATE_URL&quot; android:value=&quot;https://exp.host/@akmazio/akmazio-frontend&quot;/&gt;
      &lt;meta-data android:name=&quot;expo.modules.updates.EXPO_SDK_VERSION&quot; android:value=&quot;41.0.0&quot;/&gt;
      &lt;meta-data android:name=&quot;expo.modules.updates.ENABLED&quot; android:value=&quot;true&quot;/&gt;
      &lt;meta-data android:name=&quot;expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH&quot; android:value=&quot;ALWAYS&quot;/&gt;
      &lt;meta-data android:name=&quot;expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS&quot; android:value=&quot;0&quot;/&gt;
      &lt;activity
          android:name=&quot;.MainActivity&quot;
          android:label=&quot;@string/app_name&quot;
          android:configChanges=&quot;keyboard|keyboardHidden|orientation|screenSize|uiMode&quot;
          android:launchMode=&quot;singleTask&quot;
          android:windowSoftInputMode=&quot;adjustResize&quot;
          android:theme=&quot;@style/Theme.App.SplashScreen&quot;&gt;
        &lt;intent-filter&gt;
          &lt;action android:name=&quot;android.intent.action.MAIN&quot;/&gt;
          &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot;/&gt;
        &lt;/intent-filter&gt;
        &lt;intent-filter&gt;
          &lt;action android:name=&quot;android.intent.action.VIEW&quot;/&gt;
          &lt;category android:name = &quot;android.intent.category.DEFAULT&quot;/&gt;
          &lt;category android:name=&quot;android.intent.category.BROWSABLE&quot;/&gt;
          &lt;data android:scheme = &quot;flouriish&quot; /&gt;
        &lt;/intent-filter&gt;
      &lt;/activity&gt;
      &lt;activity android:name=&quot;com.facebook.react.devsupport.DevSettingsActivity&quot;/&gt;
    &lt;/application&gt;
  &lt;/manifest&gt;
  </code></pre>
  <p>Here's the code for the API endpoint found at <a href="https://localhost:44371/api/Login" rel="nofollow noreferrer">https://localhost:44371/api/Login</a>:</p>
  <pre><code>using akmazio_api.Classes;
  using akmazio_api.Contexts;
  using akmazio_api.Models;
  using Microsoft.EntityFrameworkCore;
  using Microsoft.Extensions.Configuration;
  using System;
  using System.Collections.Generic;
  using System.Data;
  using System.Data.SqlClient;
  using System.Linq;
  using System.Security;
  using System.Text;
  using System.Threading.Tasks;
  
  namespace akmazio_api.Services
  {
      public class LoginService : BaseService
      {
          public LoginService(IConfiguration configuration, DatabaseContext context)
              : base(configuration, context) { }
  
          public User Login(Login login)
          {
              var user = Context.Users
                  .Include(x =&gt; x.UserRole)
                  .Include(x =&gt; x.UserType)
                  .Include(x =&gt; x.Business)
                  .Include(x =&gt; x.Business.Address)
                  .Include(x =&gt; x.Address)
                  .Single(x =&gt; x.EmailAddress == login.EmailAddress &amp;&amp; x.IsVerified);
              var computedHash = Cryptography.ComputeHash(login.Password, user.Salt);
  
              if (!user.PasswordHash.Equals(computedHash))
              {
                  throw new SecurityException(&quot;User login credentials are not valid&quot;);
              }
              else
              {
                  var userLoginTokens = Context.UserLoginTokens
                      .Include(x =&gt; x.User)
                      .Where(x =&gt; x.User.UserId == user.UserId &amp;&amp;
                          x.IPAddress == login.IPAddress &amp;&amp; x.DeviceUUID == login.DeviceUUID);
                  
                  if (userLoginTokens.Any())
                  {
                      var token = userLoginTokens.First().Token;
                      user.Token = token;
                      return user.GetScrubbedUser();
                  }
                  else
                  {
                      var userLoginToken = new UserLoginToken()
                      {
                          User = user,
                          Token = Guid.NewGuid().ToString(),
                          IPAddress = login.IPAddress,
                          DeviceUUID = login.DeviceUUID
                      };
                      Context.UserLoginTokens.Add(userLoginToken);
                      Context.SaveChanges();
                      user.Token = userLoginToken.Token;
                      return user.GetScrubbedUser();
                  }
              }
          }
      }
  }
  </code></pre>
  <p>Here's the <code>Startup.cs</code> file that enables CORS:</p>
  <pre><code>using akmazio_api.Contexts;
  using Microsoft.AspNetCore.Builder;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.AspNetCore.HttpOverrides;
  using Microsoft.AspNetCore.HttpsPolicy;
  using Microsoft.AspNetCore.Mvc;
  using Microsoft.EntityFrameworkCore;
  using Microsoft.Extensions.Configuration;
  using Microsoft.Extensions.DependencyInjection;
  using Microsoft.Extensions.Hosting;
  using Microsoft.Extensions.Logging;
  using Microsoft.Net.Http.Headers;
  using Microsoft.OpenApi.Models;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Threading.Tasks;
  
  namespace akmazio_api
  {
      public class Startup
      {
          public Startup(IWebHostEnvironment env)
          {
              var builder = new ConfigurationBuilder();
              if (!env.IsProduction())
              {
                  builder
                      .SetBasePath(env.ContentRootPath)
                      .AddJsonFile($&quot;appsettings.{env.EnvironmentName}.json&quot;, optional: false, reloadOnChange: true)
                      .AddEnvironmentVariables();
              }
              else
              {
                  builder
                      .SetBasePath(env.ContentRootPath)
                      .AddJsonFile(&quot;appsettings.json&quot;, optional: true, reloadOnChange: true)
                      .AddEnvironmentVariables();
              }
              Configuration = builder.Build();
          }
  
          public IConfiguration Configuration { get; }
  
          // This method gets called by the runtime. Use this method to add services to the container.
          public void ConfigureServices(IServiceCollection services)
          {
              services.AddSingleton(Configuration);
              services.AddControllers();
              services.AddSwaggerDocument(settings =&gt;
              {
                  settings.Version = &quot;v1&quot;;
                  settings.Title = &quot;Akmazio Flouriish API&quot;;
              });
              services.AddCors(o =&gt; o.AddPolicy(&quot;DevPolicy&quot;, builder =&gt;
              {
                  builder.AllowAnyOrigin()
                         .AllowAnyMethod()
                         .AllowAnyHeader();
              }));
              services.AddCors(o =&gt; o.AddPolicy(&quot;ProdPolicy&quot;, builder =&gt;
              {
                  builder.WithOrigins(&quot;https://flouriish.io&quot;)
                         .AllowAnyMethod()
                         .AllowAnyHeader();
              }));
              services.AddDbContext&lt;DatabaseContext&gt;(option =&gt;
                  option.UseSqlServer(Configuration[&quot;ConnectionStrings:DatabaseConnection&quot;]));
              services.AddDatabaseDeveloperPageExceptionFilter();
          }
  
          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
          public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
          {
              if (env.IsDevelopment() || env.IsEnvironment(&quot;Local&quot;))
              {
                  app.UseOpenApi();
                  app.UseSwaggerUi3();
                  app.UseSwaggerUI(c =&gt; c.SwaggerEndpoint(&quot;/swagger/v1/swagger.json&quot;, &quot;akmazio_api v1&quot;));
                  app.UseExceptionHandler(&quot;/error-local-development&quot;);
              }
              else
              {
                  app.UseExceptionHandler(&quot;/error&quot;);
              }
  
              app.UseHttpsRedirection();
  
              app.UseRouting();
  
              app.UseAuthorization();
              app.UseAuthentication();
  
              if (env.IsDevelopment() || env.IsEnvironment(&quot;Local&quot;))
              {
                  app.UseCors(&quot;DevPolicy&quot;);
              }
              else if (env.IsProduction())
              {
                  app.UseCors(&quot;ProdPolicy&quot;);
              }
  
              app.UseEndpoints(endpoints =&gt;
              {
                  endpoints.MapControllers();
              });
  
              app.UseForwardedHeaders(new ForwardedHeadersOptions
              {
                  ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
              });
          }
      }
  }
  </code></pre>
  <p>Does anybody here have any idea how to fix this issue?  As you've seen I've tried setting up CORS fixes as well as adding cleartext traffic, but no juice.  Any suggestion is appreciated.</p>