Kaan Taze
Kaan Taze

Reputation: 1136

Accessing Web API from Hybrid Mobile App, Blazor Mobile

I'm working on a Blazor Hybrid App and currently trying to access a .NET Web API from my phone.

I have deployed a .NET Web Application to IIS. API returns just a WeatherForecast data (for those who're not familiar, data type is already defined in project and comes with the template) in JSON.

API Response is something like this:

[  
 {"date":"2020-09-18T15:55:27.4724752+03:00","temperatureC":-6,"temperatureF":22,"summary":"Hot"}, 

 {"date":"2020-09-19T15:55:27.4725087+03:00","temperatureC":27,"temperatureF":80,"summary":"Bracing"},
 
 {"date":"2020-09-20T15:55:27.4725155+03:00","temperatureC":54,"temperatureF":129,"summary":"Bracing"},
 
 {"date":"2020-09-21T15:55:27.4725221+03:00","temperatureC":1,"temperatureF":33,"summary":"Scorching"},
 
 {"date":"2020-09-22T15:55:27.4725302+03:00","temperatureC":-3,"temperatureF":27,"summary":"Chilly"}  
]

I deployed it to my localhost at port 3004. So both in my PC's browser and my mobile phone's browser I can successfully reach to this address and get this response.

However in my mobile application there is a method responsible for retrieving the data, defined as: AppState.cs:

public async Task<List<WeatherForecast>> GetForecastAsync()
{
     return await _http.GetFromJsonAsync<List<WeatherForecast>>("http://192.168.1.22:3004/weatherforecast");
}

and this is called from Index.razor:

@inject AppState appState

@if(todos == null){
<p> Loading </p>
}
else {
 // loop todos in foreach 
}

@code {
    
    List<Todo> todos;

    protected override async Task OnInitializedAsync()
    {
         todos = await appState.GetForecastAsync();
         appState.OnChange += UpdateState;
    }

This GET Request returns null. I've tried it with JSON placeholder from https://jsonplaceholder.typicode.com/todos/ (Changed the WeatherForecast to Todo of course) there was no problem!

My Attemps

For possible solutions I've tried to

Startup.cs

public void ConfigureServices(IServiceCollection services)
 {
            services.AddCors(options => options.AddDefaultPolicy(builder => builder.AllowAnyOrigin()));
            services.AddControllers();
}

//...

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
      //...
      app.UseHttpsRedirection();

      app.UseRouting();


      app.UseCors();

      app.UseAuthorization();

      //...
}

How can I reach the API from the mobile app?

Upvotes: 1

Views: 1505

Answers (1)

Kaan Taze
Kaan Taze

Reputation: 1136

After few hours of researching and trial and error I found it.

So I'll explain the flow step by step:

First when the page we want opens, we want to fetch the data from a remote database. In my case I call it from Index.razor, my home page:

Index.razor

@page "/"
@inject AppState appState
@implements IDisposable

@if (forecasts== null)
{
    <p>Null</p>
}
else
{
    @foreach (var forecast in forecasts)
    {
        <p>@forecast .Date</p>
        <p>@forecast .TemperatureC</p>
        <p>@forecast .TemperatureF</p>
        <p>@forecast .Summary</p>
    }
}
@code {
    List<WeatherForecast> forecasts;

    protected override async Task OnInitializedAsync()
    {
       forecasts = await appState.GetForecastAsync(); // We call the Get Forecast Async via appState
       appState.OnChange += UpdateState;
    }

    public void Dispose() => appState.OnChange -= UpdateState;

    private async Task UpdateState()
    {
        StateHasChanged();
    }


    public class WeatherForecast
    {
        public DateTime Date { get; set; }

        public int TemperatureC { get; set; }

        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

        public string Summary { get; set; }
    }
}

We need the AppState because we need to keep track of state, so it's like a state manager.

After that we jump to AppState.cs:

class AppState
{
       HttpClient _http;

       public AppState()
       {
           _http = new HttpClient() { BaseAddress = new Uri("http://192.168.1.22:3000/") };

       public async Task<List<WeatherForecast>> GetForecastAsync()
       {
           try
           {
               return await _http.GetFromJsonAsync<List<WeatherForecast>>("weatherforecast");
           }
           catch (Exception ex)
           {
               Debug.WriteLine(@"\tERROR {0}", ex.Message);
           }
           return new List<WeatherForecast>();
       }

    //There is also OnChange method here but it's irrelevant. 
}
  • I've downloaded ISSexpress-proxy and proxied the api to another port because I was having "Invalid hostname" error.

  • When initializing HttpClient I gave the baseAddress as my local IP, not 10.0.2.2 where you use to access to localhost on Android.

  • I was still getting errors on HTTP communication. In AndroidManifest.xml file I added android:targetSandboxVersion="1" to <manifest> and android:usesCleartextTraffic="true" to <application>. Thanks to this answer I found how to solve it.

Final Result

Android Screenshot

Upvotes: 1

Related Questions