/// <summary> /// Unregister entities and cascade the operation /// </summary> /// <param name="org">Organization to be used</param> /// <param name="crmEntity">Entities to be unregistered. If these are not invalid entities, only one can be specified</param> /// <param name="cascadeOperation">Cascade the operation</param> /// <param name="prog">ProgressIndicator to indicate success</param> /// <returns>Statistics of what was unregistered</returns> public static Dictionary <string, int> Unregister(CrmOrganization org, ProgressIndicator prog, params ICrmEntity[] crmEntity) { if (org == null) { throw new ArgumentNullException("org"); } else if (crmEntity == null || crmEntity.Length == 0) { throw new ArgumentNullException("crmEntity"); } Collection <Guid> serviceEndpointList = new Collection <Guid>(); Collection <Guid> assemblyList = new Collection <Guid>(); Collection <Guid> pluginList = new Collection <Guid>(); Collection <Guid> stepList = new Collection <Guid>(); Collection <Guid> secureConfigList = new Collection <Guid>(); Collection <Guid> imageList = new Collection <Guid>(); //Create the list of various objects that need to be unregistered foreach (ICrmEntity entity in crmEntity) { switch (entity.EntityType) { case ServiceEndpoint.EntityLogicalName: serviceEndpointList.Add(entity.EntityId); break; case PluginAssembly.EntityLogicalName: assemblyList.Add(entity.EntityId); break; case PluginType.EntityLogicalName: pluginList.Add(entity.EntityId); break; case Entities.SdkMessageProcessingStep.EntityLogicalName: stepList.Add(entity.EntityId); break; case SdkMessageProcessingStepImage.EntityLogicalName: imageList.Add(entity.EntityId); break; default: throw new NotImplementedException("Type = " + entity.EntityType.ToString()); } } //Retrieve the up-to-date list of steps for the service endpoints and add them to the unregister list foreach (Guid stepId in RetrieveStepIdsForServiceEndpoint(org, serviceEndpointList)) { if (!stepList.Contains(stepId)) { stepList.Add(stepId); } } //Retrieve the up-to-date list of plugins for the assemblies and add them to the unregister list foreach (Guid pluginId in RetrievePluginIdsForAssembly(org, assemblyList)) { if (!pluginList.Contains(pluginId)) { pluginList.Add(pluginId); } } //Retrieve the up-to-date list of steps for the plugins and add them to the unregister list foreach (Guid stepId in RetrieveStepIdsForPlugins(org, pluginList)) { if (!stepList.Contains(stepId)) { stepList.Add(stepId); } } //Retrieve all of the profiler steps that need to be deleted for (int i = stepList.Count - 1; i >= 0; i--) { CrmPluginStep step; if (org.Steps.TryGetValue(stepList[i], out step)) { Guid profilerStepId = step.ProfilerStepId.GetValueOrDefault(); if (Guid.Empty != profilerStepId && profilerStepId != step.StepId) { stepList.Add(profilerStepId); } } } //Retrieve the up-to-date list of secure configs for the steps and add them to the unregister list foreach (Guid secureConfigId in RetrieveSecureConfigIdsForStepId(org, stepList)) { if (!secureConfigList.Contains(secureConfigId)) { secureConfigList.Add(secureConfigId); } } //Retrieve the up-to-date list of images for the steps and add them to the unregister list foreach (Guid imageId in RetrieveImageIdsForStepId(org, stepList)) { if (!imageList.Contains(imageId)) { imageList.Add(imageId); } } //Loop through each object and delete them Dictionary <string, int> deleteStats = new Dictionary <string, int>(); int totalSteps = secureConfigList.Count + 1; if (serviceEndpointList.Count != 0) { deleteStats.Add(serviceEndpointList.Count == 1 ? "ServiceEndpoint" : "ServiceEndpoints", serviceEndpointList.Count); totalSteps += serviceEndpointList.Count; } if (assemblyList.Count != 0) { deleteStats.Add(assemblyList.Count == 1 ? "Assembly" : "Assemblies", assemblyList.Count); totalSteps += assemblyList.Count; } if (pluginList.Count != 0) { deleteStats.Add(pluginList.Count == 1 ? "Plugin" : "Plugins", pluginList.Count); totalSteps += pluginList.Count; } if (stepList.Count != 0) { deleteStats.Add(stepList.Count == 1 ? "Step" : "Steps", stepList.Count); totalSteps += stepList.Count; } if (imageList.Count != 0) { deleteStats.Add(imageList.Count == 1 ? "Image" : "Images", imageList.Count); totalSteps += imageList.Count; } try { if (prog != null) { prog.Initialize(totalSteps, "Unregistering Images"); } foreach (Guid imageId in imageList) { org.OrganizationService.Delete(SdkMessageProcessingStepImage.EntityLogicalName, imageId); if (prog != null) { prog.Increment(); } } if (prog != null) { prog.SetText("Unregistering Steps"); } foreach (Guid stepId in stepList) { org.OrganizationService.Delete(SdkMessageProcessingStep.EntityLogicalName, stepId); if (prog != null) { prog.Increment(); } } if (prog != null) { prog.SetText("Unregistering Secure Configuration"); } foreach (Guid secureConfigId in secureConfigList) { org.OrganizationService.Delete(SdkMessageProcessingStepSecureConfig.EntityLogicalName, secureConfigId); if (prog != null) { prog.Increment(); } } if (prog != null) { prog.SetText("Unregistering Plugins"); } foreach (Guid pluginId in pluginList) { org.OrganizationService.Delete(PluginType.EntityLogicalName, pluginId); if (prog != null) { prog.Increment(); } } if (prog != null) { prog.SetText("Unregistering Assemblies"); } foreach (Guid assemblyId in assemblyList) { org.OrganizationService.Delete(PluginAssembly.EntityLogicalName, assemblyId); if (prog != null) { prog.Increment(); } } if (prog != null) { prog.SetText("Unregistering ServiceEndpoints"); } foreach (Guid serviceEndpointId in serviceEndpointList) { org.OrganizationService.Delete(ServiceEndpoint.EntityLogicalName, serviceEndpointId); if (prog != null) { prog.Increment(); } } } finally { if (prog != null) { prog.Complete(true); } } return(deleteStats); }
private void btnRegister_Click(object sender, EventArgs e) { const string ERROR_CAPTION = "Registration Error"; string ERROR_MESSAGE; if (m_currentAssembly == null) { ERROR_MESSAGE = "There was an error while registering the selected plugins. Please check the Registration Log for more information."; } else { ERROR_MESSAGE = "There was an error while updating the selected plugins. Please check the Registration Log for more information."; } #region Extract Plugin Registration Information m_progRegistration.Complete(true); //Just in case it has incorrect information //Determine the source type. If we are talking about an assembly on disk, verify that it exists if (GetAssemblySourceType() == CrmAssemblySourceType.Disk) { if (string.IsNullOrEmpty(txtServerFileName.Text.Trim())) { MessageBox.Show("If the Registration Location is Disk, the \"File Name on Server\" must be specified", "Missing Information", MessageBoxButtons.OK, MessageBoxIcon.Warning); m_progRegistration.Complete(false); return; } } //Create a list of currently selected plugins bool assemblyCanBeIsolated = true; Dictionary <string, CrmPlugin> checkedPluginList = new Dictionary <string, CrmPlugin>(); foreach (ICrmTreeNode node in trvPlugins.CheckedNodes) { if (node.NodeType == CrmTreeNodeType.Plugin || node.NodeType == CrmTreeNodeType.WorkflowActivity) { CrmPlugin plugin = (CrmPlugin)node; if (CrmPluginIsolatable.No == plugin.Isolatable) { assemblyCanBeIsolated = false; } checkedPluginList.Add(plugin.TypeName, plugin); } } //Check if there are any plugins selected if (checkedPluginList.Count == 0) { MessageBox.Show("No plugins have been selected from the list. Please select at least one and try again.", "No Plugins Selected", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } //Verify that a valid isolation mode has been selected if (radIsolationSandbox.Checked && !assemblyCanBeIsolated) { MessageBox.Show("Since some of the plug-ins cannot be isolated, the assembly cannot be marked as Isolated.", "Isolation", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } //Reload the assembly string assemblyPath = AssemblyPathControl.FileName; CrmPluginAssembly assembly; if (string.IsNullOrEmpty(assemblyPath)) { //Clone the existing assembly assembly = (CrmPluginAssembly)m_currentAssembly.Clone(false); } else { assembly = RegistrationHelper.RetrievePluginsFromAssembly(assemblyPath); //Retrieve the source type and determine if the assembly.SourceType = GetAssemblySourceType(); if (CrmAssemblySourceType.Disk != assembly.SourceType) { assembly.ServerFileName = null; } else { assembly.ServerFileName = txtServerFileName.Text; } } // Ensure the checked items were all found in the assembly var registerPluginList = new List <CrmPlugin>(); var pluginList = new List <CrmPlugin>(); var removedPluginList = new List <CrmPlugin>(); var missingPluginList = new List <CrmPlugin>(); try { Parallel.ForEach(assembly.Plugins.Values, (currentPlugin) => { var foundPlugin = m_registeredPluginList.Where(x => x.TypeName.ToLowerInvariant() == currentPlugin.TypeName.ToLowerInvariant()).FirstOrDefault(); var alreadyExisted = (m_registeredPluginList != null && foundPlugin != null); if (alreadyExisted) { currentPlugin.AssemblyId = m_currentAssembly.AssemblyId; currentPlugin.PluginId = foundPlugin.PluginId; } if (checkedPluginList.ContainsKey(currentPlugin.TypeName)) { registerPluginList.Add(currentPlugin); if (currentPlugin.PluginType == CrmPluginType.Plugin) { pluginList.Add(currentPlugin); } } else if (alreadyExisted) { removedPluginList.Add(currentPlugin); } }); if (m_registeredPluginList != null) { Parallel.ForEach(m_registeredPluginList, (currentRecord) => { if (!assembly.Plugins.Values.ToList().Any(x => x.TypeName.ToLowerInvariant() == currentRecord.TypeName.ToLowerInvariant())) { missingPluginList.Add(currentRecord); } }); } } catch (Exception ex) { ErrorMessageForm.ShowErrorMessageBox(this, "Unable to load the specified Plugin Assembly", "Plugins", ex); return; } //Update the assembly with the information specified by the user assembly.IsolationMode = GetIsolationMode(); if (missingPluginList.Count != 0) { var list = missingPluginList.Select(x => x.TypeName).Aggregate((name01, name02) => name01 + "\n" + name02); MessageBox.Show($"Following plugin are missing in the assembly:\n\n{list}\n\nRegistration cannot continue!", "Plugins are missing", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } //An assembly with plugins must be strongly signed if (pluginList.Count != 0) { if (string.IsNullOrEmpty(assembly.PublicKeyToken)) { MessageBox.Show("Assemblies containing Plugins must be strongly signed. Sign the Assembly using a KeyFile.", "Strong Names Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } } //Check if there are any plugins selected that were in the assembly. if (registerPluginList.Count == 0) { MessageBox.Show("No plugins have been selected from the list. Please select at least one and try again.", "No Plugins Selected", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } else { assembly.ClearPlugins(); } //If we are doing an Update, do some special processing if (m_currentAssembly != null) { assembly.AssemblyId = m_currentAssembly.AssemblyId; } #endregion #region Register Plugin m_progRegistration.Initialize(registerPluginList.Count + removedPluginList.Count, "Preparing Registration"); int registeredAssemblies = 0; int ignoredAssemblies = 0; int updatedAssemblies = 0; bool createAssembly; //Check whether the plugin exists. If it exists, should we use the existing one? var retrieveDateList = new List <ICrmEntity>(); try { Guid pluginAssemblyId = Guid.Empty; if (m_currentAssembly != null) { if (chkUpdateAssembly.Checked) { string originalGroupName = RegistrationHelper.GenerateDefaultGroupName(m_currentAssembly.Name, new Version(m_currentAssembly.Version)); string newGroupName = RegistrationHelper.GenerateDefaultGroupName(assembly.Name, new Version(assembly.Version)); var updateGroupNameList = new List <PluginType>(); foreach (var plugin in m_currentAssembly.Plugins) { if (plugin.PluginType == CrmPluginType.WorkflowActivity && string.Equals(plugin.WorkflowActivityGroupName, originalGroupName)) { updateGroupNameList.Add(new PluginType() { Id = plugin.PluginId, WorkflowActivityGroupName = newGroupName }); } } //Do the actual update to the assembly RegistrationHelper.UpdateAssembly(m_org, assemblyPath, assembly, updateGroupNameList.ToArray()); m_currentAssembly.Name = assembly.Name; m_currentAssembly.Culture = assembly.Culture; m_currentAssembly.CustomizationLevel = assembly.CustomizationLevel; m_currentAssembly.PublicKeyToken = assembly.PublicKeyToken; m_currentAssembly.ServerFileName = assembly.ServerFileName; m_currentAssembly.SourceType = assembly.SourceType; m_currentAssembly.Version = assembly.Version; m_currentAssembly.IsolationMode = assembly.IsolationMode; retrieveDateList.Add(m_currentAssembly); foreach (var type in updateGroupNameList) { var plugin = m_currentAssembly.Plugins[type.Id]; plugin.WorkflowActivityGroupName = type.WorkflowActivityGroupName; retrieveDateList.Add(plugin); } updatedAssemblies++; } else if (!chkUpdateAssembly.Visible && assembly.IsolationMode != m_currentAssembly.IsolationMode) { var updateAssembly = new PluginAssembly() { Id = assembly.AssemblyId, IsolationMode = new OptionSetValue((int)assembly.IsolationMode) }; m_org.OrganizationService.Update(updateAssembly); m_currentAssembly.ServerFileName = assembly.ServerFileName; m_currentAssembly.SourceType = assembly.SourceType; m_currentAssembly.IsolationMode = assembly.IsolationMode; retrieveDateList.Add(m_currentAssembly); updatedAssemblies++; } assembly = m_currentAssembly; createAssembly = false; m_progRegistration.Increment(); m_orgControl.RefreshAssembly(m_currentAssembly, false); } else { createAssembly = true; m_progRegistration.Increment(); } } catch (Exception ex) { m_progRegistration.Increment("ERROR: Occurred while checking whether the assembly exists"); ErrorMessageForm.ShowErrorMessageBox(this, ERROR_MESSAGE, ERROR_CAPTION, ex); m_progRegistration.Complete(false); return; } //Register the assembly (if needed) if (createAssembly) { try { assembly.AssemblyId = RegistrationHelper.RegisterAssembly(m_org, assemblyPath, assembly); assembly.Organization = m_org; retrieveDateList.Add(assembly); } catch (Exception ex) { m_progRegistration.Increment("ERROR: Error occurred while registering the assembly"); ErrorMessageForm.ShowErrorMessageBox(this, ERROR_MESSAGE, ERROR_CAPTION, ex); m_progRegistration.Complete(false); return; } registeredAssemblies++; m_progRegistration.Increment("SUCCESS: Plugin Assembly was registered"); } else if (m_currentAssembly == null) { ignoredAssemblies++; m_progRegistration.Increment("INFORMATION: Assembly was not registered"); } else { if (chkUpdateAssembly.Checked) { m_progRegistration.Increment("SUCCESS: Assembly was updated"); } else { m_progRegistration.Increment("INFORMATION: Assembly was not updated"); } } //Check to see if the assembly needs to be added to the list if (!m_org.Assemblies.ContainsKey(assembly.AssemblyId)) { m_org.AddAssembly(assembly); //Update the Main Form try { m_orgControl.AddAssembly(assembly); m_progRegistration.Increment(); } catch (Exception ex) { m_progRegistration.Increment("ERROR: Error occurred while updating the Main form for the assembly"); ErrorMessageForm.ShowErrorMessageBox(this, ERROR_MESSAGE, ERROR_CAPTION, ex); m_progRegistration.Complete(false); return; } } else { m_progRegistration.Increment(); } // Register the Plugin bool createPlugin; int registeredPlugins = 0; int ignoredPlugins = 0; int errorsPlugins = 0; foreach (var currentPlugin in registerPluginList) { currentPlugin.AssemblyId = assembly.AssemblyId; //Check if the plugin exists bool pluginUpdate = m_registeredPluginList != null && m_registeredPluginList.Any(x => x.TypeName.ToLowerInvariant() == currentPlugin.TypeName.ToLowerInvariant()); try { Guid pluginTypeId = Guid.Empty; if (pluginUpdate || (!createAssembly && RegistrationHelper.PluginExists(m_org, currentPlugin.TypeName, assembly.AssemblyId, out pluginTypeId))) { if (pluginUpdate) { createPlugin = false; } else { m_progRegistration.AppendText(string.Format("INFORMATION: Plugin Type Name is already being used by PluginType {0}.", pluginTypeId)); switch (MessageBox.Show(string.Format("The specified name \"{0}\" is already registered. Skip the registration of this plugin?\n\nPlease note the plugins may not be the same.", currentPlugin.TypeName), "Plugin Already Exists", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)) { case DialogResult.Yes: createPlugin = false; currentPlugin.PluginId = pluginTypeId; currentPlugin.Organization = assembly.Organization; break; case DialogResult.No: createPlugin = true; break; case DialogResult.Cancel: m_progRegistration.AppendText("ABORTED: Plugin Registration has been aborted by the user."); m_progRegistration.Complete(false); return; default: throw new NotImplementedException(); } } m_progRegistration.Increment(); } else { createPlugin = true; m_progRegistration.Increment(); } } catch (Exception ex) { m_progRegistration.Increment(string.Format("ERROR: Occurred while checking if {0} is already registered.", currentPlugin.TypeName)); ErrorMessageForm.ShowErrorMessageBox(this, ERROR_MESSAGE, ERROR_CAPTION, ex); m_progRegistration.Complete(false); return; } //Create the plugin (if necessary) if (createPlugin) { try { Guid pluginId = currentPlugin.PluginId; currentPlugin.PluginId = RegistrationHelper.RegisterPlugin(m_org, currentPlugin); currentPlugin.Organization = m_org; if (pluginId != currentPlugin.PluginId && assembly.Plugins.ContainsKey(pluginId)) { assembly.RemovePlugin(pluginId); } retrieveDateList.Add(currentPlugin); m_progRegistration.Increment(string.Format("SUCCESS: Plugin {0} was registered.", currentPlugin.TypeName)); registeredPlugins++; } catch (Exception ex) { m_progRegistration.Increment(2, string.Format("ERROR: Occurred while registering {0}.", currentPlugin.TypeName)); ErrorMessageForm.ShowErrorMessageBox(this, ERROR_MESSAGE, ERROR_CAPTION, ex); errorsPlugins++; continue; } } else { if (!pluginUpdate) { ignoredPlugins++; } m_progRegistration.Increment(); } //Check if the plugin needs to be added to the list if (!assembly.Plugins.ContainsKey(currentPlugin.PluginId)) { assembly.AddPlugin(currentPlugin); //Update the main form try { m_orgControl.AddPlugin(currentPlugin); m_progRegistration.Increment(); } catch (Exception ex) { m_progRegistration.Increment(string.Format("ERROR: Occurred while updating the Main form for {0}.", currentPlugin.TypeName)); ErrorMessageForm.ShowErrorMessageBox(this, ERROR_MESSAGE, ERROR_CAPTION, ex); m_progRegistration.Complete(false); return; } } else { m_progRegistration.Increment(); } } // Unregister plugins that were unchecked int updatedPlugins = 0; foreach (var currectPlugin in removedPluginList) { //Check if the plugin exists try { RegistrationHelper.Unregister(m_org, currectPlugin); m_progRegistration.Increment(3, string.Format("SUCCESS: Plugin {0} was unregistered.", currectPlugin.TypeName)); m_orgControl.RemovePlugin(currectPlugin.PluginId); updatedPlugins++; } catch (Exception ex) { m_progRegistration.Increment(3, string.Format("ERROR: Occurred while unregistering {0}.", currectPlugin.TypeName)); ErrorMessageForm.ShowErrorMessageBox(this, ERROR_MESSAGE, ERROR_CAPTION, ex); errorsPlugins++; } } //Update the entities whose Created On / Modified On dates changed try { OrganizationHelper.UpdateDates(m_org, retrieveDateList); m_progRegistration.Increment("SUCCESS: Created On / Modified On dates updated"); } catch (Exception ex) { m_progRegistration.Increment("ERROR: Unable to update Created On / Modified On dates"); ErrorMessageForm.ShowErrorMessageBox(this, "Unable to update Created On / Modified On dates", "Update Error", ex); } #endregion m_progRegistration.AppendText("SUCCESS: Selected Plugins have been registered"); m_progRegistration.Complete(false); MessageBox.Show(string.Format("The selected Plugins have been registered.\n{0} Assembly Registered\n{1} Assembly Ignored\n{2} Assembly Updated\n{3} Plugin(s) Registered\n{4} Plugin(s) Ignored\n{5} Plugin(s) Encountered Errors\n{6} Plugin(s) Removed", registeredAssemblies, ignoredAssemblies, updatedAssemblies, registeredPlugins, ignoredPlugins, errorsPlugins, updatedPlugins), "Registered Plugins", MessageBoxButtons.OK, MessageBoxIcon.Information); if (errorsPlugins == 0) { Close(); } }