【问题标题】:Microsoft.Azure.Mobile Client - Handling Server Error using custom IMobileServiceSyncHandler - Xamarin FormsMicrosoft.Azure.Mobile 客户端 - 使用自定义 IMobileServiceSyncHandler 处理服务器错误 - Xamarin Forms
【发布时间】:2019-02-16 17:26:57
【问题描述】:

我已根据 Microsoft Sample 在我的 Xamarin Forms 应用程序中提供的文档/示例实现了 Azure - 离线同步。

在提供的示例/文档中,他们使用的是默认服务处理程序。

// 简单的错误/冲突处理。真正的应用程序会通过 IMobileServiceSyncHandler 处理各种错误,如网络状况、服务器冲突等。

因为如果 Pull/Push 失败,我需要实现 3 次重试逻辑根据文档,我创建了一个自定义服务处理程序( IMobileServiceSyncHandler)。

请在此处找到我的代码逻辑。

public class CustomSyncHandler : IMobileServiceSyncHandler
{
    public async Task<JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation)
    {
        MobileServiceInvalidOperationException error = null;
        Func<Task<JObject>> tryExecuteAsync = operation.ExecuteAsync;

        int retryCount = 3;
        for (int i = 0; i < retryCount; i++)
        {
            try
            {
                error = null;
                var result = await tryExecuteAsync();
                return result;
            }
            catch (MobileServiceConflictException e)
            {
                error = e;
            }
            catch (MobileServicePreconditionFailedException e)
            {
                error = e;
            }
            catch (MobileServiceInvalidOperationException e)
            {
                error = e;
            }
            catch (Exception e)
            {
                throw e;
            }

            if (error != null)
            {
                if(retryCount <=3) continue;
                else
                {
                     //Need to implement
                     //Update failed, reverting to server's copy.
                }
            }
        }
        return null;
    }

    public Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
    {
        return Task.FromResult(0);
    }
}

但我不确定如何处理/恢复服务器副本以防所有 3 次重试失败。

在 TODO 示例中,他们根据 MobileServicePushFailedException。但是当我们实现 IMobileServiceSyncHandler 时,这是可用的。 此外,如果我们包含自定义 IMobileServiceSyncHandler,它不会在 PushAsync / PullAsync 之后执行代码。万一出现异常,即使是 try catch 也不会触发。

        try
        {
            await this.client.SyncContext.PushAsync();

            await this.todoTable.PullAsync(
                //The first parameter is a query name that is used internally by the client SDK to implement incremental sync.
                //Use a different query name for each unique query in your program
                "allTodoItems",
                this.todoTable.CreateQuery());
        }
        catch (MobileServicePushFailedException exc)
        {
            if (exc.PushResult != null)
            {
                syncErrors = exc.PushResult.Errors;
            }
        }

        // Simple error/conflict handling. A real application would handle the various errors like network conditions,
        // server conflicts and others via the IMobileServiceSyncHandler.
        if (syncErrors != null)
        {
            foreach (var error in syncErrors)
            {
                if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
                {
                    //Update failed, reverting to server's copy.
                    await error.CancelAndUpdateItemAsync(error.Result);
                }
                else
                {
                    // Discard local change.
                    await error.CancelAndDiscardItemAsync();
                }

                Debug.WriteLine(@"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]);
            }
        }
    }

注意

在我的应用程序中,我只尝试重试 3 次,以防出现任何服务器错误。我不是在寻找解决冲突的方法。这就是我没有添加相同代码的原因。

如果有人遇到类似问题并解决了,请提供帮助。

斯特兹。

【问题讨论】:

    标签: azure xamarin.forms azure-mobile-services


    【解决方案1】:

    您说您不是在尝试解决冲突,但您需要通过接受对象的服务器版本或更新客户端操作来以一种或另一种方式解决它们(可能不告诉用户发生了什么)。否则,它会在每次重试操作时不断告诉您相同的冲突。

    您需要有一个 Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncHandler 类的子类,它会覆盖 OnPushCompleteAsync() 以处理冲突和其他错误。让我们调用类 SyncHandler:

    public class SyncHandler : MobileServiceSyncHandler
    {
        public override async Task OnPushCompleteAsync(MobileServicePushCompletionResult result)
        {
            foreach (var error in result.Errors)
            {
                await ResolveConflictAsync(error);
            }
            await base.OnPushCompleteAsync(result);
        }
    
        private static async Task ResolveConflictAsync(MobileServiceTableOperationError error)
        {
            Debug.WriteLine($"Resolve Conflict for Item: {error.Item} vs serverItem: {error.Result}");
    
            var serverItem = error.Result;
            var localItem = error.Item;
    
            if (Equals(serverItem, localItem))
            {
                // Items are the same, so ignore the conflict
                await error.CancelAndUpdateItemAsync(serverItem);
            }
            else // check server item and local item or the error for criteria you care about
            {
                // Cancels the table operation and discards the local instance of the item.
                await error.CancelAndDiscardItemAsync();
            }
        }
    }
    

    在初始化 MobileServiceClient 时包含此 SyncHandler() 的实例:

    await MobileServiceClient.SyncContext.InitializeAsync(store, new SyncHandler()).ConfigureAwait(false);
    

    阅读MobileServiceTableOperationError,了解您可以处理的其他冲突以及解决这些冲突的方法。

    【讨论】:

      【解决方案2】:

      异常带有服务器版本的副本。因此,在我的IMobileServiceSyncHandler 实现中,我只返回error.Value,这似乎可行。

      可以在this MSDN blog 中找到此类逻辑的更广泛示例。

      同一作者还有另一个示例,他展示了如何解决冲突以支持服务器副本或客户端副本,here

      【讨论】:

      • 不,它不会给你像 MobileServicePushFailedException 这样的特定错误。它只会触发 MobileServiceInvalidOperationException。那么调用这个方法await error.CancelAndUpdateItemAsync(error.Result);呢?
      • 我在同步处理程序中捕获 MobileServiceInvalidOperationException 并记录 (a) 异常 (b) operation.Table.TableName 和 (c) operation.Item.GetValue("id")?.ToString() ?? ""。这已经(到目前为止!)证明了我需要知道的所有内容,以便了解同步失败的原因。
      • 我不打电话给error.CancelAndUpdateItemAsync(error.Result);——我只是从ExecuteTableOperationAsync返回异常的Value属性,这一切都神奇地起作用了!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-01
      • 1970-01-01
      • 2011-03-05
      • 2021-07-27
      • 2011-04-07
      • 2011-01-03
      • 2017-01-10
      相关资源
      最近更新 更多