Reputation: 1136
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!
For possible solutions I've tried to
10.0.2.2:3004
since I'm on the android phone but no use.http://
and https://
but still no use.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
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.
Upvotes: 1