“可重试”请求和CancellationToken / CancellationTokenSource

时间:2018-05-04 15:32:32

标签: c# cancellationtokensource

我正在向Windows窗体应用程序添加新功能,在用户填写地址字段集合之后,我等待几秒钟,然后通过美国人口普查的地理编码API查询该地址的地理编码。用户可能不会在第一时间输入正确的信息,他们需要修复数据并重新请求。当发生这种情况时,我想取消请求并提交一个新请求。该请求是从System.Timers.Timer事件回调启动的,该回调当前使用存储在窗体视图模型上的字段中的现有CancellationTokenSource,并将CancellationTokenSource的Token传递给Task.Run,​​并传递给它运行的异步lambda函数,如下所示:

private void OnServiceAddressChangedTimerElapsed(object sender, System.Timers.ElapsedEventArgs args)
{
    Task.Run(async () => {
        var geocode = await Geocoder.GetGeocodeAsync(
            ServiceAddress.Line1,
            ServiceAddress.Line2,
            ServiceAddress.City,
            ServiceAddress.State,
            ServiceAddress.Zip,
            _gpsLookupCancellationSource.Token
        );

        GPSCoordinates.Latitude = geocode?.Latitude;
        GPSCoordinates.Longitude = geocode?.Longitude;
    }, _gpsLookupCancellationSource.Token);
}

我遇到的问题是OnServiceAddressChanged函数(当前每次地址字段中的文本发生变化时都会调用,最终会在用户离开字段或由按钮触发时更改为,但无论如何) ,当数据发生变化时,我正在取消_gpsLookupCancellationSource,所以当我稍后在OnServiceAddressChangedTimerElapsed函数中重用它时,它已被取消:

private void OnServiceAddressChanged(object sender, EventArgs args)
{
    if (!String.IsNullOrWhiteSpace(ServiceAddress.Line1) &&
        !String.IsNullOrWhiteSpace(ServiceAddress.City) &&
        !String.IsNullOrWhiteSpace(ServiceAddress.State) &&
        !String.IsNullOrWhiteSpace(ServiceAddress.Zip)
    )
    {
        _serviceAddressChangedTimer.Stop();
        _gpsLookupCancellationSource.Cancel();
        _serviceAddressChangedTimer.Start();
    }
}

虽然我认为我理解为什么它现在不能正常工作(因为CTS在第一次更改字段后已被取消),我不理解处理_gpsLookupCancellationSource的正确方法。我认为当OnServiceAddressChanged函数运行时,它应该取消旧源,然后在重新启动计时器之前创建一个新源但我不能处理它,因为我的理解是从它创建的令牌可能持有对该源的引用知道它被删除并检查它是否被取消可能会导致ObjectDisposedException。这样做的正确方法是什么?是否可以处置CTS,而其令牌可能会或可能不会检查他们的IsCancellationRequested属性?我甚至需要明确处理CTS吗?是否有一种更简单的方法可以完成所有这些我完全忽略的方法?感谢所有读你的人!

0 个答案:

没有答案
相关问题