如何使用 Xamarin Forms 中的 HttpClient 成功减少 DNS 刷新超时?

我正在开发一个相当复杂的 Xamarin.Forms 应用程序。我们提出了很多 REST 请求。据报道,我们的应用程序没有及时尊重用于负载平衡的 DNS 故障转移,因此我开始调查。我正在运行 dnsmasq,所以我可以查看应用程序何时发出 DNS 请求。该代码目前正在使用HttpWebRequest,我注意到它至少间隔 10 分钟进行 DNS 查询。


我理解部分原因是因为大多数 .NET 网络位使用 keepalive 连接。如果我强制标头不使用 keepalive,我当然会看到更高的 DNS 查询率,但这会增加网络开销,因此这不是理想的解决方案。但我最初并没有看到一种明确的方法来控制如何HttpWebRequest进行 DNS 查询。


看起来很有希望我可以获得它的ServicePoint属性并设置ConnectionLeaseTimeout它。不幸的是,这会NotImplementedException导致 Xamarin,因此它不会成为任何解决方案的一部分。


我认为这可能HttpClient会更可配置。我看到很多关于如何正确使用它的讨论,如果你这样做,你需要为ServicePointManager.DnsRefreshTimeout你希望 DNS 频繁更新的用例设置一个较小的值。但这通常与获取ServicePoint所需端点的 和 修改 一起完成ConnectionLeaseTimeout,这是不可能的。


我一直在使用一个非常简单的应用程序进行测试,该应用程序重用 HttpClient 并在我按下按钮时发出相同的请求。用一个按钮将这个 ViewModel 放在一些 Xaml 后面:


using System;

using Xamarin.Forms;

using System.Net.Http;

using System.Net;


namespace TestDns {

    public class MainPageViewModel {


        private const string _URL = "http://www.example.com";


        private HttpClient _httpClient;


        private ServicePoint _sp;


        public MainPageViewModel() {

            var sp = ServicePointManager.FindServicePoint(new Uri(_URL));

            _sp = sp;

            //_sp.ConnectionLeaseTimeout = 100; // throws NIE


            _httpClient = new HttpClient();


            ServicePointManager.DnsRefreshTimeout = 100;

        }


        public Command WhenButtonIsClicked {

            get {

                return new Command(() => SendRequest());

            }

        }


        private async void SendRequest() {

            Console.WriteLine($"{_sp.CurrentConnections}");

            var url = "http://www.example.com";

            var response = await _httpClient.GetAsync(url);

            Console.WriteLine($"{response.Content}");

        }

    }

}

没想到ConnectionLeaseTimeout扔了 我希望这段代码只缓存 100 毫秒的 DNS 请求,我打算在更多面向生产的测试中选择一个更合理的时间范围,比如 2-3 分钟。但是由于我无法让这个简单的示例像我想要的那样运行,所以增加延迟似乎没有实际意义。


肯定有人在 Xamarin 应用程序中遇到过这个问题?我唯一的解决方案是深入研究并尝试使用本机网络结构吗?


人到中年有点甜
浏览 298回答 2
2回答

GCT1015

看来Java已经决定了解决“有些人不正确地实施DNS而忽略TTL”的解决方案是通过确保使用Java的设备不正确地实施DNS来使问题变得更糟。缓存中的所有 DNS 条目都使用一个 TTL。有一些哲学辩论,以及是什么让我在这个问题中找到了答案,我将其改编为答案。就 Xamarin 项目而言,将其添加到某处(我在 MainActivity 的早期选择):Java.Security.Security.SetProperty("networkaddress.cache.ttl",&nbsp;"<integer&nbsp;seconds>");将“<整数秒>”替换为所有 DNS 条目所需的 TTL。请注意,较低的值可能意味着您比以前进行了更多的 DNS 查询,如果您认真尝试节省网络字节,这可能是一个问题。我将 Terry Carmen 的答案选为“答案”。
打开App,查看更多内容
随时随地看视频慕课网APP