从混合移动应用程序 Blazor Mobile 访问 Web API

Accessing Web API from Hybrid Mobile App, Blazor Mobile

我正在开发 Blazor 混合应用程序,目前正在尝试从我的 phone.

访问 .NET Web API

我已将 .NET Web 应用程序部署到 IIS。 API returns JSON.[=22 中只是一个WeatherForecast数据(对于那些不熟悉的人,数据类型已经在项目中定义并带有模板) =]

API 响应是这样的:

[  
 {"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"}  
]

我将它部署到本地主机的 3004 端口。因此在我的 PC 浏览器和手机 phone 浏览器中,我都可以成功到达该地址并获得此响应。

但是在我的移动应用程序中有一个方法负责检索数据,定义为: AppState.cs:

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

这是从 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;
    }

此 GET 请求 returns 为空。我已经用 https://jsonplaceholder.typicode.com/todos/ 中的 JSON 占位符进行了尝试(当然是将 WeatherForecast 更改为 Todo)没有问题!

我的尝试

对于我尝试过的可能的解决方案

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();

      //...
}

如何从移动应用程序到达 API?

经过几个小时的研究和反复试验,我找到了它。

所以我将逐步解释流程:

首先,当我们想要的页面打开时,我们要从远程数据库中获取数据。在我的例子中,我从 Index.razor 调用它,我的主页:

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; }
    }
}

我们需要 AppState,因为我们需要跟踪状态,所以它就像一个状态管理器。

之后我们跳转到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. 
}
  • 我已经下载 ISSexpress-proxy 并将 api 代理到另一个端口,因为我遇到“无效主机名”错误。

  • 在初始化 HttpClient 时,我将 baseAddress 作为我的本地 IP,而不是 10.0.2.2 您用来访问 Android.[=22= 上的本地主机的地方]

  • 我仍然遇到 HTTP 通信错误。在 AndroidManifest.xml 文件中,我将 android:targetSandboxVersion="1" 添加到 <manifest> 并将 android:usesCleartextTraffic="true" 添加到 <application>。感谢 我找到了解决方法。

最终结果