Bad Request 400 requesting ASP.Net Core 3.0 from Flutter

3,295

Solution 1

Okay, I fixed the issue by a debugging it step by step.

It seems like the Android doesn't like the self-signed certificates, thus I couldn't really set it up to use HTTPS in the end.

What I did though is I made it work with sole HTTP and these are the steps:

  1. Change IIS to your local runtime environment (by default the name of the project)
  2. Delete app.UseHttpsRedirection(); in the server Configuration method

We now enabled HTTP requests to our server. What comes next is running the server through our local runtime environment (which we can change in a Debug button in VS).

Now, we should be able to access the api in our browser in the Android Emulator using an http request e.g. http://localhost:5000/weatherforcast. Remember that ASP.NET Core 3.0 by default serves the HTTPS on port 5001 and HTTP on 5000.

Next, Android uses an alias for the IP of the local machine the server is running, so instead of writing localhost:<port> we have to write 10.0.2.2:<port>

Lastly, I simplified the api call in the client to look like this:

static Future<Profile> getUserProfile() async {
    String url = 'http://10.0.2.2:5000/weatherforecast';
    final reply = await http.get('$url');
    var responseJson = json.decode(reply.body);
    return Profile.fromJson(responseJson);
  }

Solution 2

To solve this problem first we need to understand the way Android Emulator works:

First tip you should understand is that the Android emulator (a virtual device) has its own networking. So Google defines a magic IP address “10.0.2.2”. If you try to browse to this IP address, the requests would be routed to “127.0.0.1” loopback adapter of the host machine. (Later I will give you proof on the magic routing.)

It's simple: if you put localhost on the adress it will hit the own android emulator network. So if we put 10.0.0.2, that is converted to 127.0.0.1, and we are able to acess our machine network.

The problem is that IIS doesn't have a binding for https requests on 127.0.0.1:port address, just for localhost:port. Try yourself: run your .NET Core API, go to the browser and type in 127.0.0.1:port. You'll receive the 400 - Bad Request error right in your face.

So, how to make the IIS recognize the 127.0.0.1:port address?

You'll have to mess up with the ISS Express config file and add the binding manually. Follow the steps:

1 - Open your applicationHost.config project file. In VS2019, it is inside $(solutionDir)\.vs\{projectName}\config\applicationhost.config.

The .vs folder is hidden, so make sure to tell your file explorer to show hidden directories. For other Visual Studio versions, look this link: Where is the IIS Express configuration / metabase file found?

2 - CRTL + F to search for port:localhost and you'll find the binding lines that are already configured for your project.

3 - Insert a line for the https protocol and the 127.0.0.1:port adress. Your bindings now should look like this:

<bindings>
      <binding protocol="https" bindingInformation="*:port:localhost" /> 
      <binding protocol="https" bindingInformation="*:port:127.0.0.1" /> <!-- here is your line --> 
      <binding protocol="http" bindingInformation="*:otherPort:localhost" />
</bindings>

Now, go back to your browser and try to reach 127.0.0.1:port. You should make it without any errors. So does your Flutter application. Enjoy!

References: How to let android emulator acess IIS Express? - Lexstudio

Solution 3

Really useful.

Just one thing, I got stuck where you should

What comes next is running the server through our local runtime environment (which we can change in a Debug button in VS).

To do this:

  • Open the project properties and set the App URL to only http

enter image description here

Share:
3,295
skorejen
Author by

skorejen

Updated on December 14, 2022

Comments

  • skorejen
    skorejen over 1 year

    I am trying to connect Flutter's HttpClient to fetch data from my local server which is running on ASP.Net Core 3.0. The problem is I get the Error 400(Bad Request) each time I try.

    Here's the flutter code:

        String token = await SharedPreferencesService.getStringFromSF('idToken');
        var client = new HttpClient();
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) => true;
    
        HttpClientRequest request =
            await client.getUrl(Uri.parse('https://10.0.2.2:44383/weatherforcast'));
        request.headers.add('idToken', token);
    
        HttpClientResponse response = await request.close();
        String reply = await response.transform(utf8.decoder).join();
    

    The asp.net core 3.0 endpoint:

        [ApiController]
        [Route("[controller]")]
        public class WeatherForecastController : ControllerBase
        {
            [HttpGet]
            public User Get()
            {
                return new User { UserId = 1332, Username = "Michal" };
            }
        }
    

    The Error

    <HTML><HEAD><TITLE>Bad Request</TITLE>
    <META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
    <BODY><h2>Bad Request - Invalid Hostname</h2>
    <hr><p>HTTP Error 400. The request hostname is invalid.</p>
    

    I can confirm that I get the data in the browser as well as on postman. Thank you for the help.