I would like to add Azure Offline sync feature to my XF app.
I could make it work, except this scenario: when app does not have network connection (it is in offline mode), add an item to the sync table. Then turn network on, start sync. In this case the item added in offline mode, does not appear in my server db, neither in my local one. So, my item is lost.
Is it a built-in feature, that should be somehow done by offline sync out of the box or should be implemented by me?
I used XF sample project on client and server side, that can be downloaded from Azure Portal when creating an App Service Mobile app.
Here is my code:
`public class PlaceItemManager
{
private IMobileServiceSyncTable _placeItemTable;
public PlaceItemManager ()
{
var store = new MobileServiceSQLiteStore("localstore.db");
store.DefineTable<BP_PlaceItem>();
App.MobileService.SyncContext.InitializeAsync(store);
_placeItemTable = App.MobileService.GetSyncTable<BPPlaceItem>();
}
public async Task<ObservableCollection<BPPlaceItem>> GetPlaceItemsAsync()
{
try
{
await SyncAsync();
IEnumerable<BP_PlaceItem> items = await _placeItemTable
.ToEnumerableAsync();
return new ObservableCollection<BPPlaceItem>(items);
}
catch (MobileServiceInvalidOperationException exc)
{
Debug.Assert (false, exc.Message);
Debug.WriteLine(@"Invalid sync operation: {0}", exc.Message);
}
catch (Exception exc)
{
Debug.Assert (false, exc.Message);
Debug.WriteLine(@"Sync error: {0}", exc.Message);
}
return null;
}
public async Task SaveItemAsync(BP_PlaceItem item)
{
if (item.ID == null)
{
await _placeItemTable.InsertAsync(item);
}
else
{
await _placeItemTable.UpdateAsync(item);
}
}
public async Task SyncAsync()
{
ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;
try
{
await App.MobileService.SyncContext.PushAsync();
await _placeItemTable.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
"allPlaceItems",
_placeItemTable.CreateQuery());
}
catch (MobileServicePushFailedException exc)
{
if (exc.PushResult != null)
{
Debug.Assert (false, exc.Message);
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)
{
Debug.Assert (false, error.TableName);
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"]);
}
}
}
}`