/// <summary> /// Handles the ChildInitialized event of the ForEachPending ReplicatorActivity. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="ReplicatorChildEventArgs"/> instance containing the event data.</param> private void ForEachPending_ChildInitialized(object sender, ReplicatorChildEventArgs e) { Logger.Instance.WriteMethodEntry(EventIdentifier.UpdateLookupsForEachPendingChildInitialized, "Resource: '{0}'.", e.InstanceData); try { // Cast the instance data as a Guid and prepare the read resource activity // by assigning a resource ID for update and the attributes to be read Guid resource = new Guid(); if (e.InstanceData != null) { resource = (Guid)((Guid?)e.InstanceData); } ReadResourceActivity read = e.Activity as ReadResourceActivity; if (read == null) { return; } read.ResourceId = resource; read.SelectionAttributes = this.PendingRequests[resource].Select(parameter => parameter.PropertyName).ToArray(); } finally { Logger.Instance.WriteMethodExit(EventIdentifier.UpdateLookupsForEachPendingChildInitialized, "Resource: '{0}'.", e.InstanceData); } }
/// <summary> /// Handles the ChildCompleted event of the ForEachPending ReplicatorActivity. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="ReplicatorChildEventArgs"/> instance containing the event data.</param> private void ForEachPending_ChildCompleted(object sender, ReplicatorChildEventArgs e) { Logger.Instance.WriteMethodEntry(EventIdentifier.UpdateLookupsForEachPendingChildCompleted, "Resource: '{0}'.", e.InstanceData); try { Guid resource = new Guid(); if (e.InstanceData != null) { resource = (Guid)((Guid?)e.InstanceData); } ReadResourceActivity read = e.Activity as ReadResourceActivity; if (read == null || read.Resource == null) { return; } List <UpdateRequestParameter> changes = new List <UpdateRequestParameter>(); foreach (UpdateRequestParameter parameter in this.PendingRequests[resource]) { // Read the current value of the attribute on the target resource object currentValue = read.Resource[parameter.PropertyName]; if (currentValue != null) { // FIM inconsistently returns reference values as either UniqueIdentifiers or Guids // To prevent repetitive checks, convert all UniqueIdentifiers to Guids, // and any List<UniqueIdentifier> to List<Guid> if (currentValue.GetType() == typeof(UniqueIdentifier)) { currentValue = ((UniqueIdentifier)currentValue).GetGuid(); } else if (currentValue.GetType() == typeof(List <UniqueIdentifier>)) { List <Guid> guidList = (from id in (List <UniqueIdentifier>) currentValue select id.GetGuid()).ToList(); currentValue = guidList; } } // Determine if the request represents a change based on type bool change = false; if (parameter.Mode == UpdateMode.Modify) { if (parameter.Value == null) { // If the new value is null, only submit the request parameter if the current value is not null change = currentValue != null; } else if (parameter.Value.GetType().IsGenericType&& parameter.Value.GetType().GetGenericTypeDefinition() == typeof(List <>)) { // If the new value is multi-valued, assume we are writing to a multi-valued attribute // When the current value is null, simply add all new values if (currentValue == null) { changes.AddRange(from object o in (IEnumerable)parameter.Value select new UpdateRequestParameter(parameter.PropertyName, UpdateMode.Insert, o)); } else { if (!(currentValue is IEnumerable)) { currentValue = new object[] { currentValue }; } // Identify all values that exist in the new list but not in the current list // and submit them as insert request parameters changes.AddRange(from object o in (IEnumerable)parameter.Value let contains = ((IEnumerable)currentValue).Cast <object>().Contains(o) where !contains select new UpdateRequestParameter(parameter.PropertyName, UpdateMode.Insert, o)); // Identify all values that exist in the current list but not in the new list // and submit them as remove request parameters changes.AddRange(from object o in (IEnumerable)currentValue let contains = ((IEnumerable)parameter.Value).Cast <object>().Contains(o) where !contains select new UpdateRequestParameter(parameter.PropertyName, UpdateMode.Remove, o)); } } else { // If the new value is not null and is single-valued, // determine if it represents a change to the existing attribute value if (currentValue == null) { change = true; } else { change = !currentValue.Equals(parameter.Value); } } } else { // Check if the insert or remove operation will result in a change // based on the values currently in the target attribute if (currentValue == null) { change = parameter.Mode == UpdateMode.Insert; } else if (parameter.Value != null && currentValue.GetType().IsGenericType&& currentValue.GetType().GetGenericTypeDefinition() == typeof(List <>)) { bool contains = ((IEnumerable)currentValue).Cast <object>().Any(o => o.Equals(parameter.Value)); switch (parameter.Mode) { case UpdateMode.Insert: change = !contains; break; case UpdateMode.Remove: change = contains; break; } } else { // Current value is not null and is not multivalued or we are trying to insert or remove a null value // The second possibility should have been caught earlier, while the second indicates that the calling activity has been misconfigured // Let the request through so the FIM Service can throw an error if appropriate change = true; } } // If the request parameter will result in a change, add it to the change list // Note that manipulation of multi-valued attributes via modify (overwrite) will have been // addressed via direct insertion of request parameters to the changes collection // In that scenario, change will always be false to prevent inclusion of the original request parameter if (change) { changes.Add(parameter); } } // If we have changes, add the request to the list that will be submitted if (changes.Count > 0) { this.UpdateRequests.Add(resource, changes); } } finally { Logger.Instance.WriteMethodExit(EventIdentifier.UpdateLookupsForEachPendingChildCompleted, "Resource: '{0}'.", e.InstanceData); } }