【问题标题】:What is the best way of handling repeating HTTPClient calls in Xamarin/.NET?在 Xamarin/.NET 中处理重复 HTTPClient 调用的最佳方法是什么?
【发布时间】:2020-01-09 18:43:13
【问题描述】:

我正在开发一个 Xamarin.Forms Android 应用程序,该应用程序要求手机每 15 秒 ping 一次服务器。我所有的调用都是异步的,它们都具有“await”属性,这包括在 Device.StartTimer 对象中找不到的主类中的所有主要用户函数。例如,在按钮单击、登录和注销时注册数据。对于 15 秒的 ping,我使用的是 Device.StartTimer 函数,我没有遇到太多问题,但有时我确实注意到响应确实重叠,但是我认为“等待”声明会处理响应重叠,因为我读到 Device.StartTimer 在主线程上工作。我做错了什么?有没有更好的方法来管理定时 HTTPClient 调用?

我尝试将 await 属性应用于函数以确保调用不会重叠。有一条关于在主线程上运行的 Device.StartTimer 的注释,所以我认为我的所有异步等待函数都会受到尊重。在主类中包含异步函数。

//Function to ping to the server every 15 seconds
private void StartOfflineTimer()
{
    Device.StartTimer(TimeSpan.FromSeconds(15.0), () =>
    {
        if(timerOffline)
        {
            Task.Run(async () =>
                if(await InformarOfflineAsync(Settings.AccessToken, idRutaOffline))
                {
                    DependencyService.Get<ILogUtils>().GuardarLine("**Device conected.."); 
                }
                else
                {
                    DependencyService.Get<ILogUtils>().GuardarLine("**Device disconnected..");
                }
            );
        }
        return timerOffline;
    });
}

//Default Example of how I handle ALL HTTPClient calls on the app, including calls that are in the main classes, not embedded in a device timer. All of these calls are inside their own public async Task<ExampleObject> function. Once again all of the functions that make these calls have an "await" attribute.


var jsonRequest = await Task.Run(() => JsonConvert.SerializeObject(requestObj));

var httpContent = new StringContent(jsonRequest, Encoding.UTF8, "application/json");

using (var httpClient = new HttpClient())
{
    httpClient.Timeout = TimeSpan.FromSeconds(10.0);
    var httpResponse = await httpClient.PostAsync(Constants.BaseUrl + "login/validarOffline", httpContent);
    ExampleObjectResponseObj exampleObject = new ExampleObjectResponseObj();
    var responseContent = await httpResponse.Content.ReadAsStringAsync();
    ExampleObjectResponseObj = JsonConvert.DeserializeObject<InformDataResponseObj>(responseContent);
    return ExampleObjectResponseObj;
}

HTTPClient 响应可能会重叠,或者有时会重叠并同时发送。

【问题讨论】:

  • 你不应该在 using 语句中使用 HTTP 客户端,每次创建新客户端时,套接字都不会被清理,因此这最终会填满你的套接字连接,而是使用静态实例HTTP 客户端,并且只实例化一次。
  • 另外,使用 System.Timers.Timer 而不是 Device.StartTimer
  • @Hawkzey 我在另一篇文章中读到,在 using 语句中将其用作 var 以确保每次重新实例化它时都关闭连接。但我会尝试你的建议。这个应用最多可以运行 6 天,你觉得一个 HTTP Client 的静态实例能持续那么久吗?
  • @Jason 感谢您的建议,我在用于设计的功能上没有遇到 Device.StartTimer 的问题(例如,显示 4 秒的验证弹出窗口)。但是您认为 System.Timers.Timer 会处理我的“等待”声明不被尊重吗?
  • @Hawkzey 你能指出一个没有处理套接字的情况吗?

标签: c# xamarin xamarin.forms https xamarin.android


【解决方案1】:

上面的代码并不完整,也不足以提供非常详细和准确的答案,但仍然可以回答大多数问题:

  • 您在Task.Run 中运行计时器回调,因此它不在主线程中运行
  • 如果您想在 UI 线程中运行 HttpClient,它可能会阻止重叠,但希望您的应用完全没有响应。
  • 为防止重叠,您可以使用多种方法,但很可能您正在寻找SemaphoreSlim

【讨论】:

  • 我的应用程序还没有完全没有响应,但是你的意思是最终在 UI 线程上运行 httpclient 会使 httpclient 最终停止吗?或者我会有 UI 问题?
  • 在等待 httprequest 期间,如果您在主线程上执行此操作,您将无法与应用程序交互。最终,如果时间过长,应用可能会崩溃。
【解决方案2】:

如果您不希望调用重叠,请不要使用计时器,而是使用有延迟的循环:

Task.Run(async () =>
{
    const TimeSpan checkInterval = TimeSpan.FromSeconds(15);

    while (true)
    {
        var callTime = DateTime.UtcNow;
        try
        {
            await server.Ping();
        }
        catch (Exception exception)
        {
            HandleException(exception);
        }

        var elapsedTime = DateTime.UtcNow - callTime;
        var timeToWait = checkInterval - elapsedTime;
        if (timeToWait > TimeSpan.Zero)
        {
            await Task.Delay(timeToWait);
        }
    }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-30
    • 1970-01-01
    • 2020-08-30
    • 2010-09-06
    • 2017-09-30
    相关资源
    最近更新 更多