Клиент Microsoft.Azure.Mobile - Обработка ошибки сервера с использованием пользовательского IMobileServiceSyncHandler - Xamarin Forms - PullRequest
0 голосов
/ 12 сентября 2018

Я реализовал Azure - Автономную синхронизацию на основе документации / образца, предоставленного Microsoft Образец в моем приложении Xamarin Forms.

В предоставленном образце / документации они используют обработчик обслуживания по умолчанию.

// Простая обработка ошибок / конфликтов. Реальное приложение будет обрабатывать различные ошибки, такие как состояние сети, конфликты на сервере и другие, через IMobileServiceSyncHandler.

Так как мне нужно реализовать логику повторов 3 раза , если Pull / Push не удается. В соответствии с документацией, я создал собственный обработчик службы ( 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
        {
            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 раза в случае ошибки сервера. Я не ищу разрешения конфликтов. Именно поэтому я не добавил код для того же самого.

Если кто-то сталкивался с подобными проблемами и решил их, пожалуйста, помогите.

СТЭЦ.

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Вы говорите, что не пытаетесь разрешить конфликты, но вам нужно разрешить их тем или иным образом (возможно, не сообщая пользователю, что происходит), приняв версию объекта на сервере или обновив клиентскую операцию. В противном случае он будет просто сообщать вам об одном и том же конфликте каждый раз, когда будет повторять операцию.

У вас должен быть подкласс класса 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();
        }
    }
}

Включите экземпляр этого SyncHandler () при инициализации вашего MobileServiceClient:

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

Прочтите MobileServiceTableOperationError , чтобы увидеть другие конфликты, которые вы можете обработать, а также его методы, позволяющие разрешать их.

0 голосов
/ 12 сентября 2018

Исключением является копия версии сервера.Поэтому в моей реализации IMobileServiceSyncHandler я просто возвращаю error.Value, и это, похоже, работает.

Более подробный пример логики такого рода можно найти в этом блоге MSDN .

У того же автора есть еще один пример, где он показывает, как можно разрешить конфликт в пользу серверной копии или клиентской копии, здесь .

...