В моем приложении Blazor WASM я написал (на стороне клиента) класс обслуживания с методом для вызова API веб-API. Сервер вернет ожидаемый результат IEnumerable<WeatherForecast>
или объект Microsoft.AspNetCore.Mvc.ProblemDetails
, объясняющий, что пошло не так.
При вызове метода пользовательский интерфейс (FetchData.razor) передает Action<IEnumerable<WeatherForecast>>
и * 1006. *. Только одно из этих действий должно быть выполнено, в зависимости от того, что возвращает сервер. Это позволяет классу обслуживания выбирать, что делать, основываясь на десериализованном JSON результате вызова API.
Использование (в FetchData.razor):
@page "/fetchdata"
@using BlazorApp1.Shared
@inject HttpClient Http
@inject WeatherForecastsService Service
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private IEnumerable<WeatherForecast> forecasts;
protected override async Task OnInitializedAsync()
{
await Service.GetAllAsync(
success => forecasts = success,
problem => Console.WriteLine("Handle this problem: " + problem.Detail));
}
}
Моя попытка реализации , ниже, не работает. Я уверен, что вызов API достигает правильной конечной точки API и возвращает JSON назад, но моя страница бритвы не заполняется сообщениями WeatherForecasts и не записывает подробности проблемы в консоль. Отладка в Blazor WASM (хотя и значительно улучшенная) все еще довольно трудна.
Я несколько дней возился с этим кодом, но потерпел неудачу. Кто-нибудь может помочь мне понять, что я делаю неправильно, пожалуйста?
public class WeatherForecastsService : ServiceBase
{
public WeatherForecastsService(
HttpClient client) : base(client)
{
}
public async Task GetAllAsync(
Action<IEnumerable<WeatherForecast>> actionOnSuccess,
Action<ProblemDetails> actionOnFailure,
CancellationToken cancellationToken = default)
{
await GetManyAsync("weatherforecast",
actionOnSuccess,
actionOnFailure,
cancellationToken);
}
}
public abstract class ServiceBase
{
public ServiceBase(HttpClient client)
{
Client = client;
}
protected HttpClient Client
{
get;
}
protected virtual async Task GetManyAsync<TExpected>(
string path,
Action<IEnumerable<TExpected>> actionOnSuccess,
Action<ProblemDetails> actionOnProblem,
CancellationToken cancellationToken = default)
where TExpected : class
{
string json = await GetJsonAsync(path, cancellationToken);
ProblemDetails? problem = Deserialize<ProblemDetails>(json);
if (problem is { })
{
var taskOnProblem = TaskFromAction(actionOnProblem, problem);
await taskOnProblem;
}
else
{
IEnumerable<TExpected>? expected = Deserialize<IEnumerable<TExpected>>(json);
expected = EnsureNotNull(expected);
var taskOnSuccess = TaskFromAction(actionOnSuccess, expected);
await taskOnSuccess;
}
}
private Task TaskFromAction<T>(Action<T> action, T state)
{
return new Task(ActionOfObjectFromActionOfT(action), state);
}
private Action<object> ActionOfObjectFromActionOfT<T>(Action<T> actionOfT)
{
return new Action<object>(o => actionOfT((T)o));
}
private IEnumerable<T> EnsureNotNull<T>(IEnumerable<T>? enumerable)
{
if (enumerable is null)
{
enumerable = new List<T>();
}
return enumerable;
}
private async Task<string> GetJsonAsync(string path, CancellationToken cancellationToken = default)
{
var response = await Client.GetAsync(path, cancellationToken);
return await response.Content.ReadAsStringAsync();
}
private T? Deserialize<T>(string json)
where T : class
{
try
{
return JsonSerializer.Deserialize<T>(json, null);
}
catch (JsonException)
{
return default;
}
}
}
Минимальный воспроизводимый пример моей неудачной попытки решить эту проблему можно найти здесь: https://github.com/BenjaminCharlton/AsyncBlazorRepro
Спасибо!