HttpResponseMessage ReadAsStringAsync — исключение ObjectDispose_GenericAndroid

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 HttpResponseMessage ReadAsStringAsync — исключение ObjectDispose_Generic

Сообщение Anonymous »

При использовании .NET MAUI на Android HTTP-запросы время от времени терпят неудачу (в большинстве случаев один и тот же вызов оказывается успешным), поэтому я не могу понять, почему.
Это происходит в различные конечные точки.
Это исключение:

Код: Выделить всё

{"HttpRequestError":0,
"Message":"net_http_content_stream_copy_error",
"Data": null,
"InnerException":{
"ClassName":"System.ObjectDisposedException",
"Message":"ObjectDisposed_Generic",
"Data":null,
"InnerException":null,
"HelpURL":null,
"StackTraceString":"
at Java.Interop.JniPeerMembers.AssertSelf(IJavaPeerable )\n
at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualInt32Method(String , IJavaPeerable , JniArgumentValue* )\n
at Java.IO.InputStream.Read(Byte[] , Int32 , Int32 )\n   at Android.Runtime.InputStreamInvoker.Read(Byte[] , Int32 , Int32 )\n
at System.IO.Stream.c.b__38_0(Object 
)\n
at System.Threading.Tasks.Task`1[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].InnerInvoke()\n
at System.Threading.Tasks.Task.c.b__281_0(Object obj)\n
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object )\n--- End of stack trace from previous location ---\n
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object )\n
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& , Thread )\n--- End of stack trace from previous location ---\n
at System.IO.Stream.g__Core|27_0(Stream , Stream , Int32 , CancellationToken )\n
at System.IO.BufferedStream.CopyToAsyncCore(Stream , Int32 , CancellationToken )\n
at System.Net.Http.StreamToStreamCopy.g__DisposeSourceAsync|1_0(Task , Stream )\n
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task , MemoryStream )",
"RemoteStackTraceString":null,
"RemoteStackIndex":0,
"ExceptionMethod":null,
"HResult":-2146232798,
"Source":"Java.Interop",
"WatsonBuckets":null,
"ObjectName":"Java.IO.InputStreamInvoker"},
"Source":"System.Net.Http","HResult":-2146232798,"StackTrace":"
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task , MemoryStream )\n
at System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage , HttpCompletionOption , CancellationTokenSource , Boolean , CancellationTokenSource , CancellationToken )\n
at MDC_Room.Services.ApiService.d__5`1[[System.Collections.Generic.List`1[[MDC_Room.Model.DailyReport.ChildDailyReportListItemDto, MDC_Room, Version=6.8.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()"}
Служба, выполняющая вызов API, является одноэлементной (хотя для получения экземпляра IHttpClientFactor она использует IServiceProvider):

Код: Выделить всё

builder.Services.AddSingleton();

Код: Выделить всё

public async Task GetRequestAync(string url)
{
try
{
if (Connectivity.NetworkAccess == NetworkAccess.Internet)
{
var httpClientFactory = _serviceProvider.GetRequiredService();

using var httpClient = httpClientFactory.CreateClient(AppConstants.HttpClient);

using var response = await httpClient.GetAsync(url);

if (response != null &&  response.IsSuccessStatusCode)
{
return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
}
else
await ErrorUtility.HandleErrorAsync(response, url);
}
else
await SnackbarUtility.ShowErrorSnackbarAsync("No Internet Connection", "Ok", null);
}
catch (Exception ex)
{
ErrorUtility.LogError(ex, $"{nameof(ApiService)}.{nameof(GetRequestAync)}");
}
return default;
}
Единственное, что нужно сделать, — это обработчик делегирования для вставки токена в ответ:

Код: Выделить всё

    public class AuthenticationDelegatingHandler(IApiService _dataService) : DelegatingHandler
{
private const string TokenScheme = "Bearer";

protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Authorization = new AuthenticationHeaderValue(TokenScheme, AppUtility.AccessToken ?? await TokenUtility.GetAccessTokenAsync());

var response = await base.SendAsync(request, cancellationToken);

if (response.StatusCode == HttpStatusCode.Unauthorized)
{
var user = await RefreshTokenRequiredAsync(_dataService);

if (user == null)
return response;

request.Headers.Authorization = new AuthenticationHeaderValue(TokenScheme, user.AccessToken);
response = await base.SendAsync(request, cancellationToken);
}

return response;
}
private static async Task RefreshTokenRequiredAsync(IApiService _dataService)
{
var refreshToken = await TokenUtility.GetRefreshTokenAsync();
if (!string.IsNullOrWhiteSpace(refreshToken))
{
var input = new RefreshTokenDto
{
Token = refreshToken
};
var user = await _dataService.PostRequestAync(ApiEndPoints.Auth.RefreshToken, input);
if (user != null)
{
await SecureStorage.SetAsync(CacheKeys.User, JsonConvert.SerializeObject(user));
await SecureStorage.SetAsync(CacheKeys.AccessToken, user.AccessToken!);
await SecureStorage.SetAsync(CacheKeys.RefreshToken, user.RefreshToken);

AppShellEventUtility.SetUser(user);
}
return user;
}
return null;
}
}
}
и я использую Polly для повторной попытки:

Код: Выделить всё

builder.Services.AddHttpClient(AppConstants.HttpClient,
client =>
{
client.BaseAddress = new Uri(BaseUrl);
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
})
.AddHttpMessageHandler()
.AddPolicyHandler(GetRetryPolicy);

private static IAsyncPolicy GetRetryPolicy(HttpRequestMessage httpContext)
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == HttpStatusCode.GatewayTimeout)
.OrResult(msg => msg.StatusCode == HttpStatusCode.RequestTimeout)
.OrResult(msg => msg.StatusCode == HttpStatusCode.ServiceUnavailable)
.Or()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: GetRetryDelay);
}

private static TimeSpan GetRetryDelay(int retryAttempt)
{
return retryAttempt switch
{
1 => TimeSpan.FromMilliseconds(50),
2 => TimeSpan.FromMilliseconds(100),
_ => TimeSpan.FromMilliseconds(250),
};
}
Я просмотрел следующие сообщения и убедился, что операторы using размещены правильно, и считаю, что возвращаю DTO, как рекомендовано.
System.Net.Http.HttpRequestException Ошибка при копировании содержимого в поток
Запрос Web Api выдает «Ошибка при копировании содержимого в поток».
Я не уверен, что мне здесь не хватает, буду очень признателен за любую помощь/рекомендации!

Подробнее здесь: https://stackoverflow.com/questions/791 ... -exception
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • HttpResponseMessage ReadAsStringAsync — исключение ObjectDispose_Generic
    Anonymous » » в форуме Android
    0 Ответы
    27 Просмотры
    Последнее сообщение Anonymous
  • Response.content.readasstringasync() для объекта
    Anonymous » » в форуме C#
    0 Ответы
    14 Просмотры
    Последнее сообщение Anonymous
  • Получение ошибки. Невозможно преобразовать Generic.Comparer<Pair> в Generic.IComparer<int> при сравнении двух объектов в
    Anonymous » » в форуме C#
    0 Ответы
    37 Просмотры
    Последнее сообщение Anonymous
  • Невозможно преобразовать из 'System.Collections.Generic.IEnumerable> в строку[]
    Anonymous » » в форуме C#
    0 Ответы
    38 Просмотры
    Последнее сообщение Anonymous
  • Generic класса игнорируется конструктором Generic Pydantic
    Anonymous » » в форуме Python
    0 Ответы
    33 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Android»