Polly - “无法访问关闭的流”

问题描述 投票:0回答:2

我正在将 Xamarin 应用程序升级到 MAUI,并考虑将事物解耦一些。在我有一个处理对 API 的所有请求的数据存储之前,现在我为应用程序的每个部分都有一个服务,请求从该服务发送到 HttpManager,问题是当策略重试时,它第一次工作,但在第二次重试失败,并显示消息“无法访问关闭的流”。搜索了一下但找不到解决办法。

我从 viewModel 调用该服务。

LoginViewModel.cs

readonly IAuthService _authService;

public LoginViewModel(IAuthService authService)
{
    _authService = authService;
}

[RelayCommand]
private async Task Login()
{
    ...
   
    var loginResponse = await _authService.Login(
        new LoginDTO(QRSettings.StaffCode, Password, QRSettings.Token));

    ...
}

在服务中我设置将数据发送到HttpManager并处理响应

AuthService.cs

private readonly IHttpManager _httpManager;

public AuthService(IHttpManager manager)
{
   _httpManager = manager;
}

public async Task<ServiceResponse<string>> Login(LoginDTO model)
{
    var json = JsonConvert.SerializeObject(model);
    var content = new StringContent(json, Encoding.UTF8, "application/json");
    var response = await _httpManager.PostAsync<string>("Auth/Login", content);

    ...
}

我在这里发送请求。

HttpManager.cs

readonly IConnectivity _connectivity;

readonly AsyncPolicyWrap _retryPolicy = Policy
   .Handle<TimeoutRejectedException>()
   .WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1), (exception, timespan, retryAttempt, context) =>
   {
       App.AppViewModel.RetryTextVisible = true;
       App.AppViewModel.RetryText = $"Attempt number {retryAttempt}...";
   })
   .WrapAsync(Policy.TimeoutAsync(11, TimeoutStrategy.Pessimistic));

HttpClient HttpClient;

public HttpManager(IConnectivity connectivity)
{
    _connectivity = connectivity;

    HttpClient = new HttpClient();
}

public async Task<ServiceResponse<T>> PostAsync<T>(string endpoint, HttpContent content, bool shouldRetry = true)
{
    ...

    // Post request
    var response = await Post($""http://10.0.2.2:5122/{endpoint}", content, shouldRetry);

    ...
}

async Task<HttpResponseMessage> Post(string url, HttpContent content, bool shouldRetry)
{
    if (shouldRetry)
    {
        // This is where the error occurs, in the PostAsync
        var response = await _retryPolicy.ExecuteAndCaptureAsync(async token =>
            await HttpClient.PostAsync(url, content, token), CancellationToken.None);

        ...
    }

    ...
}

如果重要的话,这就是毛伊岛计划

...

private static MauiAppBuilder RegisterServices(this MauiAppBuilder builder)
{
    ...

    builder.Services.AddSingleton<IHttpManager, HttpManager>();
    builder.Services.AddSingleton<IAuthService, AuthService>();

    return builder;
}

不知道问题出在哪里... 我尝试了各种尝试/捕获,尝试在网上寻找解决方案,但没有运气。 第二次重试时,它总是给出该错误

c# dotnet-httpclient maui polly retry-logic
2个回答
2
投票

免责声明:在评论部分,我建议倒带底层流。这个建议是错误的,我纠正一下。

TL;DR:您无法重复使用需要重新创建的

HttpContent
对象。


为了能够使用 POST 动词执行重试尝试,您需要为每次尝试重新创建

HttpContent
负载。

有多种方法可以修复代码:

将序列化字符串作为参数传递

async Task<HttpResponseMessage> Post(string url, string content, bool shouldRetry)
{
    if (shouldRetry)
    {
        var response = await _retryPolicy.ExecuteAndCaptureAsync(async token =>
            await HttpClient.PostAsync(url, new StringContent(content, Encoding.UTF8, "application/json"), token), CancellationToken.None);

        ...
    }

    ...
}

将要序列化的对象作为参数传递

async Task<HttpResponseMessage> Post(string url, object content, bool shouldRetry)
{
    if (shouldRetry)
    {
        var response = await _retryPolicy.ExecuteAndCaptureAsync(async token =>
            await HttpClient.PostAsync(url, JsonContent.Create(content), token), CancellationToken.None);

        ...
    }

    ...
}
  • 这里我们利用 .NET 5 中引入的
    JsonContent
    类型

将要序列化的对象作为参数#2传递

async Task<HttpResponseMessage> Post(string url, object content, bool shouldRetry)
{
    if (shouldRetry)
    {
        var response = await _retryPolicy.ExecuteAndCaptureAsync(async token =>
            await HttpClient.PostAsJsonAsync(url, content, token), CancellationToken.None);

        ...
    }

    ...
}

0
投票

我只是把它放在那里,因为当我在 maui 中使用 post 对我用 azure 编写的 Web 服务进行 Web 服务调用时,遇到了这个流关闭错误。我正在将一些旧代码从 xamarin 转换为 maui。我把头发拔了几个小时。然后我查看了我正在使用的服务器名称和协议。我无意中使用了 http 作为协议。我改用 https,所有错误都消失了。

© www.soinside.com 2019 - 2024. All rights reserved.