我遇到了这个问题,在我的移动应用程序中,如果您在同步时按注销,它会崩溃。
Sync - 是我的应用程序的整个状态和信息输出的同步。
注销 - 之后我们清除所有数据和服务。
事实证明,当我们在同步期间(2秒)按下logout时,我们仍然会陷入 while 循环并访问
UpdateFrequencyInSeconds
字段,并且会发生崩溃。
private async void ThreadSync(CancellationToken token)
{
while (token.IsCancellationRequested is false)
{
await Sync().ConfigureAwait(false);
await Task.Delay(organizationAppSettingsService.UpdateFrequencyInSeconds * 1000).ConfigureAwait(false);
}
}
我确实找到了解决方案,但它并不完全干净和完美。 这就是它的工作原理。
private async void ThreadSync(CancellationToken token)
{
while (token.IsCancellationRequested is false)
{
var updateFrequencyInSeconds = organizationAppSettingsService.UpdateFrequencyInSeconds * 1000;
await Sync().ConfigureAwait(false);
await Task.Delay(updateFrequencyInSeconds).ConfigureAwait(false);
}
}
它也可以这样工作,但不太漂亮。
private async void ThreadSync(CancellationToken token)
{
while (token.IsCancellationRequested is false)
{
await Sync().ConfigureAwait(false);
if (token.IsCancellationRequested is false)
await Task.Delay(organizationAppSettingsService.UpdateFrequencyInSeconds * 1000).ConfigureAwait(false);
}
}
如果令牌被取消,是否有一些优雅的方法可以不执行字段检索? 它也不是这样工作的,首先发出请求,然后只发出令牌。
await Task.Delay(organizationAppSettingsService.UpdateFrequencyInSeconds * 1000, token).ConfigureAwait(false);
我正在尝试找到修复错误的最佳解决方案,我提出了三个选项,但它们并不完全干净。
同步方法
public async Task Sync()
{
if (networkManager.IsNetworkAvailable is false || IsSyncInProgress ||
(DateTime.Now - _lastSyncedTime).TotalSeconds < organizationAppSettingsService.UpdateFrequencyInSeconds)
return;
IsSyncInProgress = true;
_logger.LogInformation($"[BackgroundSync] Updating");
var waiting = Task.Delay(2000);
ShowSyncProgress?.Invoke();
try
{
UpdateLocation();
await ordersRepository.UpdateOrders(_courierLocations, _ordersDtos).ConfigureAwait(false);
var updateServiceInfo = !_lastServiceInfoUpdated.HasValue ||
(DateTime.Now - _lastServiceInfoUpdated.Value).TotalSeconds >=
IAppSettingsService.DefaultServiceRequestFrequency;
if (updateServiceInfo)
{
await UpdatePaymentTypes().ConfigureAwait(false);
_lastServiceInfoUpdated = DateTime.Now;
}
Synced = true;
_courierLocations.Clear();
var orders = Orders?.Where(x => (DateTime.Now - x.DeliveryDate).TotalHours < 24).ToList();
if (orders is null || orders.Any() is false)
{
SyncCompleted?.Invoke();
return;
}
await waiting;
SyncCompleted?.Invoke();
}
catch (SessionExpiredException)
{
await RecoverTransportSession().ConfigureAwait(false);
}
catch (Exception ex)
{
CatchSyncException(ex);
}
finally
{
_lastSyncedTime = DateTime.Now;
IsSyncInProgress = false;
HideSyncProgress?.Invoke();
_logger.LogInformation("[BackgroundSync] Update completed");
}
CancellationToken
很合作。您需要将令牌传递给Sync
和Task.Delay
。你也应该抓住并吞下OperationCanceledException
。
private async void ThreadSync(CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
await Sync(token).ConfigureAwait(false);
await Task.Delay(organizationAppSettingsService.UpdateFrequencyInSeconds * 1000, token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{ //
}
}
然后您需要实际使用令牌。您调用的所有这些函数都需要获取令牌并将其传递给任何接受它的函数。
public async Task Sync(CancellationToken token)
{
还有
var waiting = Task.Delay(2000, token);
还有
await ordersRepository.UpdateOrders(_courierLocations, _ordersDtos, token).ConfigureAwait(false);
还有
await UpdatePaymentTypes(token).ConfigureAwait(false);
不确定这个,你真的想在
catch
中中止吗?
await RecoverTransportSession(token).ConfigureAwait(false);
至于你实际上在做什么,这很奇怪,我同意你应该找到一种不同的方法来做到这一点。也许是
BackgroundService
,或者某种服务总线触发器,或者也许您只需要 WebSocket
和 SignalR 来避免轮询。