Microsoft.Azure.Mobile 客户端 - 使用自定义 IMobileServiceSyncHandler 处理服务器错误 - Xamarin Forms

2024-03-19

我已经根据 Microsoft 提供的文档/示例实现了 Azure - 离线同步Sample https://github.com/Azure/azure-mobile-apps-quickstarts/blob/master/client/xamarin.forms/ZUMOAPPNAME/TodoItemManager.cs在我的 Xamarin Forms 应用程序中。

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

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

因为我需要实施一个重试逻辑3次 if the 拉/推失败。根据文档,我创建了一个自定义服务处理程序(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 示例中,他们在哪里恢复它基于移动服务推送失败异常。但是当我们实施时这是可用的IMobileServiceSyncHandler。 更重要的是,如果我们包含自定义 IMobileServiceSyncHandler 它不会执行之后的代码推异步/拉异步。如果出现任何异常,即使 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"]);
            }
        }
    }

Note

在我的应用程序中,我只想在出现任何服务器错误时重试 3 次。我并不是要寻求解决冲突。这就是我没有添加相同代码的原因。

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

Stez.


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

您需要有 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);

阅读移动服务表操作错误 https://learn.microsoft.com/en-us/dotnet/api/microsoft.windowsazure.mobileservices.sync.mobileservicetableoperationerror?view=azure-dotnet查看您可以处理的其他冲突及其解决方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Microsoft.Azure.Mobile 客户端 - 使用自定义 IMobileServiceSyncHandler 处理服务器错误 - Xamarin Forms 的相关文章

随机推荐