public async Task <JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation) { MobileServicePreconditionFailedException preconditionFailedException = null; JObject result = null; do { preconditionFailedException = null; try { result = await operation.ExecuteAsync(); } catch (MobileServicePreconditionFailedException ex) { preconditionFailedException = ex; } if (preconditionFailedException != null) { var serverItem = preconditionFailedException.Value.ToObject <T>(); operation.Item[MobileServiceSystemColumns.Version] = serverItem.Version; } }while (preconditionFailedException != null); return(result); }
public async Task DeleteAsync_ThrowsPreconditionFailedException_WhenMergeConflictOccurs() { await EnsureEmptyTableAsync <RoundTripTableItemWithSystemPropertiesType>(); string id = Guid.NewGuid().ToString(); IMobileServiceTable table = GetClient().GetTable("RoundTripTable"); var item = new JObject() { { "id", id }, { "name", "a value" } }; var inserted = await table.InsertAsync(item); item["version"] = "3q3A3g=="; MobileServicePreconditionFailedException expectedException = null; try { await table.DeleteAsync(item); } catch (MobileServicePreconditionFailedException ex) { expectedException = ex; } Assert.IsNotNull(expectedException); Assert.AreEqual(expectedException.Value["version"], inserted["version"]); Assert.AreEqual(expectedException.Value["name"], inserted["name"]); }
public async Task DeleteAsync_ThrowsPreconditionFailedException_WhenMergeConflictOccurs() { await EnsureEmptyTableAsync <ToDoWithSystemPropertiesType>(); string id = "an id"; IMobileServiceTable table = GetClient().GetTable("stringId_test_table"); var item = new JObject() { { "id", id }, { "String", "a value" } }; var inserted = await table.InsertAsync(item); item["version"] = "random"; MobileServicePreconditionFailedException expectedException = null; try { await table.DeleteAsync(item); } catch (MobileServicePreconditionFailedException ex) { expectedException = ex; } Assert.IsNotNull(expectedException); Assert.AreEqual(expectedException.Value["version"], inserted["version"]); Assert.AreEqual(expectedException.Value["String"], inserted["String"]); }
public async Task DeleteAsync_ThrowsPreconditionFailedException_WhenMergeConflictOccurs_Generic() { await EnsureEmptyTableAsync <ToDoWithSystemPropertiesType>(); string id = "an id"; IMobileServiceTable <ToDoWithSystemPropertiesType> table = GetClient().GetTable <ToDoWithSystemPropertiesType>(); // insert a new item var item = new ToDoWithSystemPropertiesType() { Id = id, String = "a value" }; await table.InsertAsync(item); Assert.IsNotNull(item.CreatedAt); Assert.IsNotNull(item.UpdatedAt); Assert.IsNotNull(item.Version); string version = item.Version; // Delete with wrong version item.Version = "abc"; item.String = "But wait!"; MobileServicePreconditionFailedException <ToDoWithSystemPropertiesType> expectedException = null; try { await table.DeleteAsync(item); } catch (MobileServicePreconditionFailedException <ToDoWithSystemPropertiesType> exception) { expectedException = exception; } Assert.IsNotNull(expectedException); Assert.AreEqual(expectedException.Response.StatusCode, HttpStatusCode.PreconditionFailed); string responseContent = await expectedException.Response.Content.ReadAsStringAsync(); JToken jtoken = responseContent.ParseToJToken(table.MobileServiceClient.SerializerSettings); string serverVersion = (string)jtoken["version"]; string stringValue = (string)jtoken["String"]; Assert.AreEqual(version, serverVersion); Assert.AreEqual(stringValue, "a value"); Assert.IsNotNull(expectedException.Item); Assert.AreEqual(version, expectedException.Item.Version); Assert.AreEqual(stringValue, expectedException.Item.String); // Delete one last time with the version from the server item.Version = serverVersion; await table.DeleteAsync(item); Assert.IsNull(item.Id); }
protected override bool ProceedInvokeException(Exception exception, out Toolkit.Events.ActionResult errorInfo) { MobileServiceInvalidOperationException mobileServiceInvalidOperationException = exception as MobileServiceInvalidOperationException; if (mobileServiceInvalidOperationException != null) { errorInfo = ActionResult.GetErrorResult(mobileServiceInvalidOperationException); return(true); } MobileServicePreconditionFailedException mobileServicePreconditionFailedException = exception as MobileServicePreconditionFailedException; if (mobileServicePreconditionFailedException != null) { errorInfo = ActionResult.GetErrorResult(mobileServicePreconditionFailedException); return(true); } errorInfo = ActionResult.ValidResult; return(false); }
public async Task <JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation) { MobileServicePreconditionFailedException preconditionFailedException = null; JObject result = null; do { preconditionFailedException = null; try { result = await operation.ExecuteAsync(); } catch (MobileServicePreconditionFailedException ex) { preconditionFailedException = ex; } // there is a conflict between the local version and the server version of the item if (preconditionFailedException != null) { // get the server's version of the item var serverItem = preconditionFailedException.Value.ToObject <T>(); // Replace the local pending item's version value with the server item's version value. // This will force the local change to override the server version. // This is somewhat destructive (clobbering), and not favorable for all scenarios. // See the below commented out code for an alternative strategy that is more conservative. operation.Item[MobileServiceSystemColumns.Version] = serverItem.Version; /* The following commented out lines do not force the local copy to the server. Instead, an error message is presented to the user. */ /* This could be improved even futher by presenting both versions of the data to the user and letting him/het decide with to keep. */ //var localItem = operation.Item.ToObject<Acquaintance>(); //RaiseDataSyncErrorEvent(new DataSyncErrorEventArgs<Acquaintance>(localItem, serverItem)); //operation.AbortPush(); //return result; } }while (preconditionFailedException != null); return(result); }
public async Task <JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation) { MobileServicePreconditionFailedException ex = null; JObject result = null; do { ex = null; try { this.test.Log("Attempting to execute the operation"); result = await operation.ExecuteAsync(); } catch (MobileServicePreconditionFailedException e) { ex = e; } if (ex != null) { this.test.Log("A MobileServicePreconditionFailedException was thrown, ex.Value = {0}", ex.Value); var serverItem = ex.Value; if (serverItem == null) { this.test.Log("Item not returned in the exception, trying to retrieve it from the server"); serverItem = (JObject)(await client.GetTable(operation.Table.TableName).LookupAsync((string)operation.Item["id"])); } var typedClientItem = operation.Item.ToObject <T>(); var typedServerItem = serverItem.ToObject <T>(); var typedMergedItem = conflictResolution(typedClientItem, typedServerItem); var mergedItem = JObject.FromObject(typedMergedItem); mergedItem[MobileServiceSystemColumns.Version] = serverItem[MobileServiceSystemColumns.Version]; this.test.Log("Merged the items, will try to resubmit the operation"); operation.Item = mergedItem; } } while (ex != null); return(result); }
public async Task <JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation) { JObject result = null; MobileServicePreconditionFailedException conflictError = null; do { try { result = await operation.ExecuteAsync(); } catch (MobileServicePreconditionFailedException e) { conflictError = e; } if (conflictError != null) { // There was a conflict on the server. Let's "fix" it by // forcing the client entity JObject serverItem = conflictError.Value; // In most cases, the server will return the server item in the request body // when a Precondition Failed is returned, but it's not guaranteed for all // backend types. if (serverItem == null) { serverItem = (JObject)(await operation.Table.LookupAsync((string)operation.Item[MobileServiceSystemColumns.Id])); } // Now update the local item with the server version operation.Item[MobileServiceSystemColumns.Version] = serverItem[MobileServiceSystemColumns.Version]; } } while (conflictError != null); return(result); }
public async Task <JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation) { JObject result = null; MobileServicePreconditionFailedException conflictError = null; Debug.WriteLine("Beginning Sync"); do { try { result = await operation.ExecuteAsync(); } catch (MobileServicePreconditionFailedException e) { conflictError = e; } catch (Exception ex) { Debug.WriteLine(ex.ToString()); } if (conflictError != null) { JObject serverItem = conflictError.Value; if (serverItem == null) { serverItem = (JObject)(await operation.Table.LookupAsync((string)operation.Item[MobileServiceSystemColumns.Id])); } serverItem[MobileServiceSystemColumns.Version] = operation.Item[MobileServiceSystemColumns.Version]; } } while (conflictError != null); return(result); }
public async Task <JObject> ExecuteTableOperationAsync(IMobileServiceTableOperation operation) { MobileServicePreconditionFailedException ex = null; JObject result = null; do { ex = null; try { result = await operation.ExecuteAsync(); } catch (MobileServicePreconditionFailedException e) { ex = e; } if (ex != null) { var serverItem = ex.Value; if (serverItem == null) { serverItem = (JObject)(await client.GetTable(operation.Table.TableName).LookupAsync((string)operation.Item["id"])); } var typedClientItem = operation.Item.ToObject <T>(); var typedServerItem = serverItem.ToObject <T>(); var typedMergedItem = conflictResolution(typedClientItem, typedServerItem); var mergedItem = JObject.FromObject(typedMergedItem); mergedItem[MobileServiceSystemColumns.Version] = serverItem[MobileServiceSystemColumns.Version]; operation.Item = mergedItem; } } while (ex != null); return(result); }
private static ZumoTest CreateOptimisticConcurrencyTest(string testName, Func <VersionedType, VersionedType, VersionedType> mergingPolicy) { return(new ZumoTest(testName, async delegate(ZumoTest test) { var client = ZumoTestGlobals.Instance.Client; var table = client.GetTable <VersionedType>(); DateTime now = DateTime.UtcNow; int seed = now.Year * 10000 + now.Month * 100 + now.Day; test.AddLog("Using seed: {0}", seed); Random rndGen = new Random(seed); var item = new VersionedType(rndGen); await table.InsertAsync(item); test.AddLog("[client 1] Inserted item: {0}", item); var client2 = new MobileServiceClient(client.ApplicationUri, client.ApplicationKey); var table2 = client.GetTable <VersionedType>(); var item2 = await table2.LookupAsync(item.Id); test.AddLog("[client 2] Retrieved the item"); item2.Name = Util.CreateSimpleRandomString(rndGen, 20); item2.Number = rndGen.Next(100000); test.AddLog("[client 2] Updated the item, will update on the server now"); await table2.UpdateAsync(item2); test.AddLog("[client 2] Item has been updated: {0}", item2); test.AddLog("[client 1] Will try to update; should fail"); MobileServicePreconditionFailedException <VersionedType> ex = null; try { item.Name = Util.CreateSimpleRandomString(rndGen, 20); await table.UpdateAsync(item); test.AddLog("[client 1] Error, the update succeeded, but it should have failed. Item = {0}", item); return false; } catch (MobileServicePreconditionFailedException <VersionedType> e) { test.AddLog("[client 1] Received expected exception; server item = {0}", e.Item); ex = e; } var serverItem = ex.Item; if (serverItem.Version != item2.Version) { test.AddLog("[client 1] Error, server item's version is not the same as the second item version"); return false; } var cachedMergedItem = mergingPolicy(item, serverItem); var mergedItem = mergingPolicy(item, serverItem); test.AddLog("[client 1] Merged item: {0}", mergedItem); test.AddLog("[client 1] Trying to update it again, should succeed this time"); await table.UpdateAsync(mergedItem); test.AddLog("[client 1] Updated the item: {0}", mergedItem); if (!cachedMergedItem.Equals(mergedItem)) { test.AddLog("[client 1] Error, the server version of the merged item doesn't match the client one"); return false; } test.AddLog("[client 2] Refreshing the item"); await table2.RefreshAsync(item2); test.AddLog("[client 2] Refreshed the item: {0}", item2); if (!item2.Equals(mergedItem)) { test.AddLog("[client] Error, item is different than the item from the client 1"); return false; } return true; })); }
public async Task DeleteAsync_ThrowsPreconditionFailedException_WhenMergeConflictOccurs_Generic() { string id = Guid.NewGuid().ToString(); var table = GetClient().GetTable <RoundTripTableItemWithSystemPropertiesType>(); // insert a new item var item = new RoundTripTableItemWithSystemPropertiesType() { Id = id, Name = "a value" }; await table.InsertAsync(item); Assert.IsNotNull(item.CreatedAt); Assert.IsNotNull(item.UpdatedAt); Assert.IsNotNull(item.Version); string version = item.Version; // Delete with wrong version item.Version = "3q3A3g=="; item.Name = "But wait!"; MobileServicePreconditionFailedException <RoundTripTableItemWithSystemPropertiesType> expectedException = null; try { await table.DeleteAsync(item); } catch (MobileServicePreconditionFailedException <RoundTripTableItemWithSystemPropertiesType> exception) { expectedException = exception; } Assert.IsNotNull(expectedException); Assert.AreEqual(expectedException.Response.StatusCode, HttpStatusCode.PreconditionFailed); string responseContent = await expectedException.Response.Content.ReadAsStringAsync(); RoundTripTableItemWithSystemPropertiesType serverItem = expectedException.Item; string serverVersion = serverItem.Version; string stringValue = serverItem.Name; Assert.AreEqual(version, serverVersion); Assert.AreEqual(stringValue, "a value"); Assert.IsNotNull(expectedException.Item); Assert.AreEqual(version, expectedException.Item.Version); Assert.AreEqual(stringValue, expectedException.Item.Name); // Delete one last time with the version from the server item.Version = serverVersion; await table.DeleteAsync(item); Assert.IsNull(item.Id); }
public async Task UpdateAsyncWitMergeConflict_Generic() { await EnsureEmptyTableAsync <RoundTripTableItemWithSystemPropertiesType>(); string id = Guid.NewGuid().ToString(); IMobileServiceTable <RoundTripTableItemWithSystemPropertiesType> table = GetClient().GetTable <RoundTripTableItemWithSystemPropertiesType>(); RoundTripTableItemWithSystemPropertiesType item = new RoundTripTableItemWithSystemPropertiesType() { Id = id, Name = "a value" }; await table.InsertAsync(item); Assert.IsNotNull(item.CreatedAt); Assert.IsNotNull(item.UpdatedAt); Assert.IsNotNull(item.Version); string version = item.Version; // Update item.Name = "Hello!"; await table.UpdateAsync(item); Assert.IsNotNull(item.Version); Assert.AreNotEqual(item.Version, version); string newVersion = item.Version; // Update again but with the original version item.Version = version; item.Name = "But wait!"; MobileServicePreconditionFailedException <RoundTripTableItemWithSystemPropertiesType> expectedException = null; try { await table.UpdateAsync(item); } catch (MobileServicePreconditionFailedException <RoundTripTableItemWithSystemPropertiesType> exception) { expectedException = exception; } Assert.IsNotNull(expectedException); Assert.AreEqual(expectedException.Response.StatusCode, HttpStatusCode.PreconditionFailed); Assert.IsNotNull(expectedException.Item); string serverVersion = expectedException.Item.Version; string stringValue = expectedException.Item.Name; Assert.AreEqual(newVersion, serverVersion); Assert.AreEqual(stringValue, "Hello!"); // Update one last time with the version from the server item.Version = serverVersion; await table.UpdateAsync(item); Assert.IsNotNull(item.Version); Assert.AreEqual(item.Name, "But wait!"); Assert.AreNotEqual(item.Version, serverVersion); await table.DeleteAsync(item); }