protected virtual void OnApplyChangeFailed(ApplyChangeFailedEventArgs args) { if (ApplyChangeFailed != null) { ApplyChangeFailed(this, args); } }
static void ApplyChangedFailed(object sender, ApplyChangeFailedEventArgs e) { e.Action = ApplyAction.Continue; return; // tables name string serverTableName = e.Conflict.RemoteChanges.TableName; string clientTableName = e.Conflict.LocalChanges.TableName; // server row in conflict var dmRowServer = e.Conflict.RemoteChanges.Rows[0]; var dmRowClient = e.Conflict.LocalChanges.Rows[0]; // Example 1 : Resolution based on rows values if ((int)dmRowServer["ClientID"] == 100 && (int)dmRowClient["ClientId"] == 0) { e.Action = ApplyAction.Continue; } else { e.Action = ApplyAction.RetryWithForceWrite; } // Example 2 : resolution based on conflict type // Line exist on client, not on server, force to create it //if (e.Conflict.Type == ConflictType.RemoteInsertLocalNoRow || e.Conflict.Type == ConflictType.RemoteUpdateLocalNoRow) // e.Action = ApplyAction.RetryWithForceWrite; //else // e.Action = ApplyAction.RetryWithForceWrite; }
static void SqlSyncProvider_ApplyChangedFailed(object sender, ApplyChangeFailedEventArgs e) { // Note: LocalChange table name may be null if the record does not exist on the server. So use the remote table name. string tableName = e.Conflict.RemoteChange.TableName; // Line exist on client, not on server, force to create it if (e.Conflict.Type == ConflictType.LocalNoRowRemoteUpdate) { e.Action = ApplyAction.Rollback; } else { e.Action = ApplyAction.Continue; } }
//<snippetOCS_CS_Conflicts_ClientApplyChangeFailed> private void SampleClientSyncProvider_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { //Log event data from the client side. EventLogger.LogEvents(sender, e); //Force write any inserted server rows that are in conflict //when they are downloaded. if (e.Conflict.ConflictType == ConflictType.ClientInsertServerInsert) { e.Action = ApplyAction.RetryWithForceWrite; } if (e.Conflict.ConflictType == ConflictType.ClientUpdateServerUpdate) { //Logic goes here. } if (e.Conflict.ConflictType == ConflictType.ErrorsOccurred) { //Logic goes here. } }
private void SampleServerSyncProvider_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { //Verbose tracing includes information about conflicts. In this application, //Verbose tracing is disabled, and we have decided to flag conflicts with a //warning. //Check if Verbose tracing is enabled and if the conflict is an error. //If the conflict is not an error, we write a warning to the trace file //with information about the conflict. //<snippetOCS_CS_Tracing_ApplyChangeFailed> if (SyncTracer.IsVerboseEnabled() == false && e.Conflict.ConflictType != ConflictType.ErrorsOccurred) { DataTable conflictingServerChange = e.Conflict.ServerChange; DataTable conflictingClientChange = e.Conflict.ClientChange; int serverColumnCount = conflictingServerChange.Columns.Count; int clientColumnCount = conflictingClientChange.Columns.Count; StringBuilder clientRowAsString = new StringBuilder(); StringBuilder serverRowAsString = new StringBuilder(); for (int i = 0; i < clientColumnCount; i++) { clientRowAsString.Append(conflictingClientChange.Rows[0][i] + " | "); } for (int i = 0; i < serverColumnCount; i++) { serverRowAsString.Append(conflictingServerChange.Rows[0][i] + " | "); } SyncTracer.Warning(1, "CONFLICT DETECTED FOR CLIENT {0}", e.Session.ClientId); SyncTracer.Warning(2, "** Client change **"); SyncTracer.Warning(2, clientRowAsString.ToString()); SyncTracer.Warning(2, "** Server change **"); SyncTracer.Warning(2, serverRowAsString.ToString()); } //</snippetOCS_CS_Tracing_ApplyChangeFailed> }
//Create client and server log files, and write to them //based on data from the ApplyChangeFailedEventArgs. public static void LogEvents(object sender, ApplyChangeFailedEventArgs e) { string logFile = String.Empty; string site = String.Empty; if (sender is SampleServerSyncProvider) { logFile = "ServerLogFile.txt"; site = "server"; } else if (sender is SampleClientSyncProvider) { logFile = "ClientLogFile.txt"; site = "client"; } StreamWriter streamWriter = File.AppendText(logFile); StringBuilder outputText = new StringBuilder(); outputText.AppendLine("** CONFLICTING CHANGE OR ERROR AT " + site.ToUpper() + " **"); outputText.AppendLine("Table for which error or conflict occurred: " + e.TableMetadata.TableName); outputText.AppendLine("Sync stage: " + e.Conflict.SyncStage); outputText.AppendLine("Conflict type: " + e.Conflict.ConflictType); //If it is a data conflict instead of an error, print out //the values of the rows at the client and server. if (e.Conflict.ConflictType != ConflictType.ErrorsOccurred && e.Conflict.ConflictType != ConflictType.Unknown) { DataTable serverChange = e.Conflict.ServerChange; DataTable clientChange = e.Conflict.ClientChange; int serverRows = serverChange.Rows.Count; int clientRows = clientChange.Rows.Count; int serverColumns = serverChange.Columns.Count; int clientColumns = clientChange.Columns.Count; for (int i = 0; i < serverRows; i++) { outputText.Append("Server row: "); for (int j = 0; j < serverColumns; j++) { outputText.Append(serverChange.Rows[i][j] + " | "); } outputText.AppendLine(String.Empty); } for (int i = 0; i < clientRows; i++) { outputText.Append("Client row: "); for (int j = 0; j < clientColumns; j++) { outputText.Append(clientChange.Rows[i][j] + " | "); } outputText.AppendLine(String.Empty); } } if (e.Conflict.ConflictType == ConflictType.ErrorsOccurred) { outputText.AppendLine("Error message: " + e.Error.Message); } streamWriter.WriteLine(DateTime.Now.ToShortTimeString() + " | " + outputText.ToString()); streamWriter.Flush(); streamWriter.Dispose(); }
private void SampleServerSyncProvider_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { //Log information for the ApplyChangeFailed event. EventLogger.LogEvents(sender, e); //Respond to four different types of conflicts: // * ClientDeleteServerUpdate // * ClientUpdateServerDelete // * ClientInsertServerInsert // * ClientUpdateServerUpdate // if (e.Conflict.ConflictType == ConflictType.ClientDeleteServerUpdate) { //With the commands we are using, the default is for the server //change to win and be applied to the client. Here, we accept the //default on the server side. We also set ConflictResolver.ServerWins //for this conflict in the client provider. This ensures that the server //change is applied to the client during the download phase. Console.WriteLine(String.Empty); Console.WriteLine("***********************************"); Console.WriteLine("A client delete / server update conflict was detected."); e.Action = ApplyAction.Continue; Console.WriteLine("The server change will be applied at the client."); Console.WriteLine("***********************************"); Console.WriteLine(String.Empty); } //<snippetOCS_CS_Conflicts_ServerApplyChangeFailed> if (e.Conflict.ConflictType == ConflictType.ClientUpdateServerDelete) { //For client-update/server-delete conflicts, we force the client //change to be applied at the server. The stored procedure specified for //customerSyncAdapter.UpdateCommand accepts the @sync_force_write parameter //and includes logic to handle this case. Console.WriteLine(String.Empty); Console.WriteLine("***********************************"); Console.WriteLine("A client update / server delete conflict was detected."); e.Action = ApplyAction.RetryWithForceWrite; Console.WriteLine("The client change was retried at the server with RetryWithForceWrite."); Console.WriteLine("***********************************"); Console.WriteLine(String.Empty); } //</snippetOCS_CS_Conflicts_ServerApplyChangeFailed> if (e.Conflict.ConflictType == ConflictType.ClientInsertServerInsert) { //Similar to how we handled the client-delete/server-update conflict. //In this case, we set ConflictResolver.FireEvent and use RetryWithForceWrite //for this conflict in the client provider. This is equivalent to //ConflictResolver.ServerWins, and ensures that the server //change is applied to the client during the download phase. Console.WriteLine(String.Empty); Console.WriteLine("***********************************"); Console.WriteLine("A client insert / server insert conflict was detected."); e.Action = ApplyAction.Continue; Console.WriteLine("The server change will be applied at the client."); Console.WriteLine("***********************************"); Console.WriteLine(String.Empty); } if (e.Conflict.ConflictType == ConflictType.ClientUpdateServerUpdate) { //For client-update/server-update conflicts, we want to //allow the user to specify the conflict resolution option. // //It is possible for the Conflict object from the //server to have more than one row. Because our custom //resolution code only works with one row at a time, //we only allow the user to select a resolution //option if the object contains a single row. if (e.Conflict.ServerChange.Rows.Count > 1) { Console.WriteLine(String.Empty); Console.WriteLine("***********************************"); Console.WriteLine("A client update / server update conflict was detected."); e.Action = ApplyAction.Continue; Console.WriteLine("The server change will be applied at the client."); Console.WriteLine("***********************************"); Console.WriteLine(String.Empty); } else { Console.WriteLine(String.Empty); Console.WriteLine("***********************************"); Console.WriteLine("A client update / server update conflict was detected."); Console.WriteLine("Conflicting rows are displayed below."); Console.WriteLine("***********************************"); //Get the conflicting changes from the Conflict object //and display them. The Conflict object holds a copy //of the changes; updates to this object will not be //applied. To make changes, use the Context object, //which is demonstrated in the next section of code //under ' case "CU" '. DataTable conflictingServerChange = e.Conflict.ServerChange; DataTable conflictingClientChange = e.Conflict.ClientChange; int serverColumnCount = conflictingServerChange.Columns.Count; int clientColumnCount = conflictingClientChange.Columns.Count; Console.WriteLine(String.Empty); Console.WriteLine("Server row: "); Console.Write(" | "); //Display the server row. for (int i = 0; i < serverColumnCount; i++) { Console.Write(conflictingServerChange.Rows[0][i] + " | "); } Console.WriteLine(String.Empty); Console.WriteLine(String.Empty); Console.WriteLine("Client row: "); Console.Write(" | "); //Display the client row. for (int i = 0; i < clientColumnCount; i++) { Console.Write(conflictingClientChange.Rows[0][i] + " | "); } Console.WriteLine(String.Empty); Console.WriteLine(String.Empty); //Ask for a conflict resolution option. Console.WriteLine("Enter a resolution option for this conflict:"); Console.WriteLine("SE = server change wins"); Console.WriteLine("CL = client change wins"); Console.WriteLine("CU = custom resolution (combine rows)"); string conflictResolution = Console.ReadLine(); conflictResolution.ToUpper(); switch (conflictResolution) { case "SE": //Again, this this is the default for the commands we are using: //the server change is persisted and then downloaded to the client. e.Action = ApplyAction.Continue; Console.WriteLine(String.Empty); Console.WriteLine("The server change will be applied at the client."); break; case "CL": //Override the default by specifying that the client row //should be applied at the server. The stored procedure specified //for customerSyncAdapter.UpdateCommand accepts the @sync_force_write //parameter and includes logic to handle this case. e.Action = ApplyAction.RetryWithForceWrite; Console.WriteLine(String.Empty); Console.WriteLine("The client change was retried at the server with RetryWithForceWrite."); break; case "CU": //Provide a custom resolution scheme that takes each conflicting //column and applies the combined contents of the column to the //client and server. This is not necessarily a resolution scheme //that you would use in production. Instead, it is used to //demonstrate the various ways you can interact with conflicting //data during synchronization. // //Get the ID for the conflicting row from the client data table, //and add it to a list of GUIDs. We update rows at the server //based on this list. Guid customerId = (Guid)conflictingClientChange.Rows[0]["CustomerId"]; _updateConflictGuids.Add(customerId); //Create a dictionary to hold the column ordinal and value for //any columns that are in confict. Dictionary <int, string> conflictingColumns = new Dictionary <int, string>(); string combinedColumnValue; //Determine which columns are different at the client and server. //We already looped through these columns once, but we wanted to //keep this code separate from the display code above. for (int i = 0; i < clientColumnCount; i++) { if (conflictingClientChange.Rows[0][i].ToString() != conflictingServerChange.Rows[0][i].ToString()) { //If we find a column that is different, combine the values from //the client and server, and write "| conflict |" between them. combinedColumnValue = conflictingClientChange.Rows[0][i] + " | conflict | " + conflictingServerChange.Rows[0][i]; conflictingColumns.Add(i, combinedColumnValue); } } //Loop through the rows in the Context object, which exposes //the set of changes that are uploaded from the client. //Note: In the ApplyChangeFailed event for the client provider, //you have access to the set of changes that was downloaded from //the server. DataTable allClientChanges = e.Context.DataSet.Tables["Customer"]; int allClientRowCount = allClientChanges.Rows.Count; int allClientColumnCount = allClientChanges.Columns.Count; for (int i = 0; i < allClientRowCount; i++) { //Find the changed row with the GUID from the Conflict object. if (allClientChanges.Rows[i].RowState == DataRowState.Modified && (Guid)allClientChanges.Rows[i]["CustomerId"] == customerId) { //Loop through the columns and check whether the column //is in the conflictingColumns dictionary. If it is, //update the value in the allClientChanges Context object. for (int j = 0; j < allClientColumnCount; j++) { if (conflictingColumns.ContainsKey(j)) { allClientChanges.Rows[i][j] = conflictingColumns[j]; } } } } //Apply the changed row with its combined values to the server. //This change will persist at the server, but it will not be //downloaded with the SelectIncrementalUpdate command that we use. //It will not download the change because it checks for the UpdateId, //which is still set to the client that made the upload. //We use the ChangesApplied event to set the UpdateId for the //change to a value that represents the server. This ensures //that the change is applied at the client during the download //phase of synchronization (see SampleServerSyncProvider_ChangesApplied). e.Action = ApplyAction.RetryWithForceWrite; Console.WriteLine(String.Empty); Console.WriteLine("The custom change was retried at the server with RetryWithForceWrite."); break; default: Console.WriteLine(String.Empty); Console.WriteLine("Not a valid resolution option."); break; } } Console.WriteLine(String.Empty); } }
void SampleClientSyncProvider_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { Console.Write("APPLYING CHANGES FAILED.."); }
protected override void OnApplyChangeFailed(ApplyChangeFailedEventArgs value) { Console.Write("applying changes failed.."); base.OnApplyChangeFailed(value); }
/// <summary> /// Handles the ApplyChangeFailed event of the syncAgent control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="Microsoft.Synchronization.Data.ApplyChangeFailedEventArgs"/> instance containing the event data.</param> /// <remarks>Documented by Dev03, 2009-02-12</remarks> private static void syncAgent_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { Trace.WriteLine(e.Error.ToString()); }
private void RelationalProviderProxy_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { throw new NotImplementedException(); }
/// #UPLOAD 2 private void ApplyChangesInternal(SyncGroupMetadata groupMetadata, DataSet dataSet, SyncSession syncSession, SyncContext syncContext) { SyncStage syncStage = SyncStage.UploadingChanges; foreach (SyncTableMetadata tableMetadata in groupMetadata.TablesMetadata) { SpSyncAdapter adapter = null; if (this.SyncAdapters.Contains(tableMetadata.TableName)) { adapter = this.SyncAdapters[tableMetadata.TableName]; } if (adapter == null) { throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Messages.InvalidTableName, tableMetadata.TableName)); } // SpSyncAnchor anchor if (!dataSet.Tables.Contains(tableMetadata.TableName)) { throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Messages.TableNotInSchema, tableMetadata.TableName)); } SyncTableProgress tableProgress = syncContext.GroupProgress.FindTableProgress(tableMetadata.TableName); DataTable dataTable = dataSet.Tables[tableMetadata.TableName]; try { Collection <SyncConflict> conflicts; int changesCount = dataTable.Rows.Count; adapter.Update(dataTable, Connection, out conflicts); if (conflicts != null) { foreach (SyncConflict conflict in conflicts) { ApplyChangeFailedEventArgs failureArgs = new ApplyChangeFailedEventArgs(tableMetadata, conflict, null, syncSession, syncContext, Connection, null); OnApplyChangeFailed(failureArgs); if (failureArgs.Action == ApplyAction.Continue) { if (conflict != null) { tableProgress.ChangesFailed++; tableProgress.Conflicts.Add(conflict); } } } } tableProgress.ChangesApplied = changesCount - tableProgress.ChangesFailed; } catch (Exception e) { SyncConflict conflict = new SyncConflict(ConflictType.ErrorsOccurred, SyncStage.UploadingChanges) { ErrorMessage = e.Message + ", InnerException:" + e.InnerException.ToString(), ServerChange = dataTable, ClientChange = dataTable }; ApplyChangeFailedEventArgs failureArgs = new ApplyChangeFailedEventArgs(tableMetadata, conflict, null, syncSession, syncContext, Connection, null); OnApplyChangeFailed(failureArgs); // handle errors? if (SyncTracer.IsErrorEnabled()) { SyncTracer.Error(e.ToString()); } } SyncProgressEventArgs args = new SyncProgressEventArgs(tableMetadata, tableProgress, groupMetadata, syncContext.GroupProgress, syncStage); OnSyncProgress(args); } }
void serverSyncProvider_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { //MessageBox.Show(e.Conflict.ErrorMessage); }
//Create client and server log files, and write to them //based on data from several EventArgs classes. public static void LogEvents(object sender, EventArgs e) { string logFile = String.Empty; string site = String.Empty; if (sender is SampleServerSyncProvider) { logFile = "ServerLogFile.txt"; site = "server"; } else if (sender is SampleClientSyncProvider) { logFile = "ClientLogFile.txt"; site = "client"; } StreamWriter streamWriter = File.AppendText(logFile); StringBuilder outputText = new StringBuilder(); if (e is ChangesSelectedEventArgs) { ChangesSelectedEventArgs args = (ChangesSelectedEventArgs)e; outputText.AppendLine("Client ID: " + args.Session.ClientId); outputText.AppendLine("Changes selected from " + site + " for group " + args.GroupMetadata.GroupName); outputText.AppendLine("Inserts selected from " + site + " for group: " + args.Context.GroupProgress.TotalInserts.ToString()); outputText.AppendLine("Updates selected from " + site + " for group: " + args.Context.GroupProgress.TotalUpdates.ToString()); outputText.AppendLine("Deletes selected from " + site + " for group: " + args.Context.GroupProgress.TotalDeletes.ToString()); } else if (e is ChangesAppliedEventArgs) { ChangesAppliedEventArgs args = (ChangesAppliedEventArgs)e; outputText.AppendLine("Client ID: " + args.Session.ClientId); outputText.AppendLine("Changes applied to " + site + " for group " + args.GroupMetadata.GroupName); outputText.AppendLine("Inserts applied to " + site + " for group: " + args.Context.GroupProgress.TotalInserts.ToString()); outputText.AppendLine("Updates applied to " + site + " for group: " + args.Context.GroupProgress.TotalUpdates.ToString()); outputText.AppendLine("Deletes applied to " + site + " for group: " + args.Context.GroupProgress.TotalDeletes.ToString()); } else if (e is SchemaCreatedEventArgs) { SchemaCreatedEventArgs args = (SchemaCreatedEventArgs)e; outputText.AppendLine("Schema creation for group: " + args.Table.SyncGroup.GroupName); outputText.AppendLine("Table: " + args.Table.TableName); outputText.AppendLine("Direction : " + args.Table.SyncDirection); outputText.AppendLine("Creation Option: " + args.Table.CreationOption); } //<snippetOCS_CS_Events_ApplyChangeFailedEventArgs> else if (e is ApplyChangeFailedEventArgs) { ApplyChangeFailedEventArgs args = (ApplyChangeFailedEventArgs)e; outputText.AppendLine("** APPLY CHANGE FAILURE AT " + site.ToUpper() + " **"); outputText.AppendLine("Table for which failure occurred: " + args.TableMetadata.TableName); outputText.AppendLine("Error message: " + args.Error.Message); } //</snippetOCS_CS_Events_ApplyChangeFailedEventArgs> else { outputText.AppendLine("Unknown event occurred"); } streamWriter.WriteLine(DateTime.Now.ToShortTimeString() + " | " + outputText.ToString()); streamWriter.Flush(); streamWriter.Dispose(); }