/// <summary> /// Extracts delimeted text block from XML document format /// </summary> /// <param name="xml">XML document containing the text block</param> /// <returns>Block with text-serialized CRM data</returns> public static string XmlSerializedToTextFile(XmlDocument xml) { XmlNode root = CintXML.FindChild(xml, "ShuffleData"); string sertype = CintXML.GetAttribute(root, "Type"); if (sertype == SerializationType.Text.ToString()) { XmlNode xText = CintXML.FindChild(root, "Text"); string text = xText.InnerText; return(text); } else { throw new ArgumentOutOfRangeException("xml", sertype, "XmlSerializedToTextFile called with xml document of incompatible serialization type"); } }
private List <string> GetMatchAttributes(XmlNode xMatch) { var result = new List <string>(); if (xMatch != null) { foreach (XmlNode xMatchAttr in xMatch.ChildNodes) { var matchattr = CintXML.GetAttribute(xMatchAttr, "Name"); if (string.IsNullOrEmpty(matchattr)) { throw new ArgumentOutOfRangeException("Match Attribute name not set"); } result.Add(matchattr); } } return(result); }
private string GetSolutionFilename(XmlNode xBlock, string name, string type) { log.StartSection("GetSolutionFilename"); string file = CintXML.GetAttribute(xBlock, "File"); if (string.IsNullOrWhiteSpace(file)) { file = name; } string path = CintXML.GetAttribute(xBlock, "Path"); if (string.IsNullOrWhiteSpace(path) && !string.IsNullOrWhiteSpace(definitionpath)) { path = definitionpath; } path += path.EndsWith("\\") ? "" : "\\"; string filename; if (type == "Managed") { filename = path + file + "_managed.zip"; } else if (type == "Unmanaged") { filename = path + file + ".zip"; } else { throw new ArgumentOutOfRangeException("Type", type, "Invalid Solution type"); } if (filename.Contains("%")) { IDictionary envvars = Environment.GetEnvironmentVariables(); foreach (DictionaryEntry de in envvars) { filename = filename.Replace("%" + de.Key.ToString() + "%", de.Value.ToString()); } } log.Log("Filename: {0}", filename); log.EndSection(); return(filename); }
private static void AddRelationFilter(ShuffleBlocks blocks, XmlNode xRelation, XmlNode xEntity, ILoggable log) { if (blocks != null && blocks.Count > 0) { var block = CintXML.GetAttribute(xRelation, "Block"); var attribute = CintXML.GetAttribute(xRelation, "Attribute"); var pkattribute = CintXML.GetAttribute(xRelation, "PK-Attribute"); var includenull = CintXML.GetBoolAttribute(xRelation, "IncludeNull", false); List <string> ids = new List <string>(); CintDynEntityCollection parentcoll = blocks.ContainsKey(block) ? blocks[block] : null; if (parentcoll != null && parentcoll.Count > 0) { foreach (CintDynEntity parent in parentcoll) { if (string.IsNullOrEmpty(pkattribute)) { ids.Add(parent.Id.ToString()); } else { ids.Add(parent.Property <EntityReference>(pkattribute, new EntityReference()).Id.ToString()); } } } else { // Adding temp guid to indicate "no matches", as ConditionOperator.In will fail if no values are given ids.Add(new Guid().ToString()); } if (!includenull) { CintFetchXML.AppendFilter(xEntity, "and", attribute, "in", ids.ToArray()); } else { var xFilter = CintFetchXML.AppendFilter(xEntity, "or"); CintFetchXML.AppendCondition(xFilter, attribute, "null"); CintFetchXML.AppendCondition(xFilter, attribute, "in", ids.ToArray()); } log.Log("Adding relation condition for {0} in {1} values in {2}.{3}", attribute, ids.Count, block, pkattribute); } }
private static string GetEntityDisplayString(XmlNode xMatch, CintDynEntity cdEntity) { var unique = new List <string>(); if (xMatch != null && xMatch.ChildNodes.Count > 0) { foreach (XmlNode xMatchAttr in xMatch.ChildNodes) { string matchdisplay = CintXML.GetAttribute(xMatchAttr, "Display"); if (string.IsNullOrEmpty(matchdisplay)) { matchdisplay = CintXML.GetAttribute(xMatchAttr, "Name"); } var matchvalue = "<null>"; if (cdEntity.Contains(matchdisplay, true)) { if (cdEntity.Entity[matchdisplay] is EntityReference) { // Don't use PropertyAsString, that would perform GetRelated that we don't want due to performance var entref = cdEntity.Property <EntityReference>(matchdisplay, null); if (!string.IsNullOrEmpty(entref.Name)) { matchvalue = entref.Name; } else { matchvalue = entref.LogicalName + ":" + entref.Id.ToString(); } } else { matchvalue = cdEntity.PropertyAsString(matchdisplay, "", false, false, true); } } unique.Add(matchvalue); } } if (unique.Count == 0) { unique.Add(cdEntity.Id.ToString()); } return(string.Join(", ", unique)); }
/// <summary>Get the current versions for all solutions defined in the definition file</summary> /// <remarks>Results will be placed in the public dictionary <c ref="ExistingSolutionVersions">ExistingSolutionVersions</c></remarks> public void GetCurrentVersions() { log.StartSection("GetCurrentVersions"); ExistingSolutionVersions = new Dictionary <string, Version>(); var xRoot = CintXML.FindChild(definition, "ShuffleDefinition"); var xBlocks = CintXML.FindChild(xRoot, "Blocks"); if (xBlocks != null) { var solutions = GetExistingSolutions(); foreach (XmlNode xBlock in xBlocks.ChildNodes) { if (xBlock.NodeType == XmlNodeType.Element) { switch (xBlock.Name) { case "DataBlock": break; case "SolutionBlock": var xmlNode = CintXML.FindChild(xBlock, "Export"); if (xmlNode != null) { var name = CintXML.GetAttribute(xBlock, "Name"); log.Log("Getting version for: {0}", name); foreach (var solution in solutions) { if (name.Equals(solution.Property("uniquename", ""), StringComparison.OrdinalIgnoreCase)) { ExistingSolutionVersions.Add(name, new Version(solution.Property("version", "1.0.0.0"))); log.Log("Version found: {0}", ExistingSolutionVersions[name]); } } } break; } } } } log.EndSection(); }
/// <summary> /// Import entities to CRM from dictionary of blocks /// </summary> /// <param name="blocks">Blocks with entities to import</param> /// <returns>Tuple with counters for: Created, Updated, Skipped and Failed records</returns> public Tuple <int, int, int, int, int, EntityReferenceCollection> ImportToCRM(ShuffleBlocks blocks) { log.StartSection("ImportToCRM"); if (definition == null) { throw new ArgumentNullException("Definition", "Shuffle definition must be specified to import data"); } int created = 0; int updated = 0; int skipped = 0; int deleted = 0; int failed = 0; EntityReferenceCollection references = new EntityReferenceCollection(); XmlNode xRoot = CintXML.FindChild(definition, "ShuffleDefinition"); XmlNode xBlocks = CintXML.FindChild(xRoot, "Blocks"); if (xBlocks != null) { guidmap = new Dictionary <Guid, Guid>(); stoponerror = CintXML.GetBoolAttribute(xRoot, "StopOnError", false); timeout = CintXML.GetIntAttribute(xRoot, "Timeout", -1); double savedtimeout = -1; if (timeout > -1) { try { SendLine("Setting timeout: {0} minutes", timeout); OrganizationServiceProxy orgsvcpxy = crmsvc.GetService <OrganizationServiceProxy>(); savedtimeout = orgsvcpxy.Timeout.TotalMinutes; orgsvcpxy.Timeout = new TimeSpan(0, timeout, 0); } catch (InvalidPluginExecutionException) { // Couldn't cast to correct service type, for some reason... savedtimeout = -1; } } int totalBlocks = xBlocks.ChildNodes.Count; int currentBlock = 0; foreach (XmlNode xBlock in xBlocks.ChildNodes) { currentBlock++; SendStatus(totalBlocks, currentBlock, -1, -1); if (xBlock.NodeType == XmlNodeType.Element) { switch (xBlock.Name) { case "DataBlock": string name = CintXML.GetAttribute(xBlock, "Name"); if (!blocks.ContainsKey(name)) { blocks.Add(name, new CintDynEntityCollection()); } Tuple <int, int, int, int, int, EntityReferenceCollection> dataresult = ImportDataBlock(xBlock, blocks[name]); created += dataresult.Item1; updated += dataresult.Item2; skipped += dataresult.Item3; deleted += dataresult.Item4; failed += dataresult.Item5; references.AddRange(dataresult.Item6); break; case "SolutionBlock": var solutionresult = ImportSolutionBlock(xBlock); switch (solutionresult) { case ItemImportResult.Created: created++; break; case ItemImportResult.Updated: updated++; break; case ItemImportResult.Skipped: skipped++; break; case ItemImportResult.Failed: failed++; break; } break; } } } SendStatus(0, 0, 0, 0); if (savedtimeout > -1) { OrganizationServiceProxy orgsvcpxy = crmsvc.GetService <OrganizationServiceProxy>(); orgsvcpxy.Timeout = new TimeSpan(0, (int)savedtimeout, 0); } } log.EndSection(); return(new Tuple <int, int, int, int, int, EntityReferenceCollection>(created, updated, skipped, deleted, failed, references)); }
/// <summary> /// Export entities from CRM to dictionary of blocks with entities /// </summary> /// <returns>Blocks with exported entities</returns> public ShuffleBlocks ExportFromCRM() { log.StartSection("ExportFromCRM"); if (definition == null) { throw new ArgumentNullException("Definition", "Shuffle definition must be specified to export data"); } ShuffleBlocks blocks = new ShuffleBlocks(); ExistingSolutionVersions = null; XmlNode xRoot = CintXML.FindChild(definition, "ShuffleDefinition"); XmlNode xBlocks = CintXML.FindChild(xRoot, "Blocks"); if (xBlocks != null) { stoponerror = CintXML.GetBoolAttribute(xRoot, "StopOnError", false); timeout = CintXML.GetIntAttribute(xRoot, "Timeout", -1); double savedtimeout = -1; if (timeout > -1) { SendLine("Setting timeout: {0} minutes", timeout); OrganizationServiceProxy orgsvcpxy = crmsvc.GetService <OrganizationServiceProxy>(); savedtimeout = orgsvcpxy.Timeout.TotalMinutes; orgsvcpxy.Timeout = new TimeSpan(0, timeout, 0); } int totalBlocks = xBlocks.ChildNodes.Count; int currentBlock = 0; foreach (XmlNode xBlock in xBlocks.ChildNodes) { currentBlock++; SendStatus(totalBlocks, currentBlock, -1, -1); if (xBlock.NodeType == XmlNodeType.Element) { switch (xBlock.Name) { case "DataBlock": CintDynEntityCollection cExported = ExportDataBlock(blocks, xBlock); string name = CintXML.GetAttribute(xBlock, "Name"); if (cExported != null) { if (blocks.ContainsKey(name)) { SendLine("Block already added: {0}", name); } else { blocks.Add(name, cExported); } } break; case "SolutionBlock": if (ExistingSolutionVersions == null) { GetCurrentVersions(); } ExportSolutionBlock(xBlock); break; } } } SendStatus(0, 0, 0, 0); if (savedtimeout > -1) { OrganizationServiceProxy orgsvcpxy = crmsvc.GetService <OrganizationServiceProxy>(); orgsvcpxy.Timeout = new TimeSpan(0, (int)savedtimeout, 0); } } log.EndSection(); return(blocks); }
/// <summary> /// Deserialize xml/string to blocks with entities /// </summary> /// <param name="serialized"></param> /// <returns>Optional, only required for SerializationType: Text</returns> public ShuffleBlocks Deserialize(XmlDocument serialized) { log.StartSection("Deserialize"); ShuffleBlocks result = new ShuffleBlocks(); if (serialized != null) { XmlNode root = CintXML.FindChild(serialized, "ShuffleData"); string sertype = CintXML.GetAttribute(root, "Type"); SendLine("Deserialize from {0}", sertype); if (sertype == SerializationType.Full.ToString() || sertype == SerializationType.Simple.ToString() || sertype == SerializationType.SimpleNoId.ToString() || sertype == SerializationType.SimpleWithValue.ToString() || sertype == SerializationType.Explicit.ToString()) { foreach (XmlNode xBlock in root.ChildNodes) { if (xBlock.NodeType == XmlNodeType.Element && xBlock.Name == "Block" && xBlock.ChildNodes.Count == 1) { string name = CintXML.GetAttribute(xBlock, "Name"); XmlDocument xml = new XmlDocument(); xml.AppendChild(xml.ImportNode(xBlock.ChildNodes[0], true)); CintDynEntityCollection cEntities = new CintDynEntityCollection(xml, crmsvc, log); SendLine("Block {0}: {1} records", name, cEntities.Count); result.Add(name, cEntities); } } } else if (sertype == SerializationType.Text.ToString()) { string strdelimeter = CintXML.GetAttribute(root, "Delimeter"); char delimeter = strdelimeter.Length == 1 ? strdelimeter[0] : '\t'; XmlNode xText = CintXML.FindChild(root, "Text"); StringReader reader = new StringReader(xText.InnerText); int line = 0; string name = ""; StringBuilder serializedblock = null; string current = reader.ReadLine(); while (current != null) { log.Log("Line {0:000}: {1}", line, current); if (current.StartsWith("<<<") && current.Contains(">>>")) { log.Log("Block start"); if (!string.IsNullOrWhiteSpace(name) && serializedblock != null) { CintDynEntityCollection cEntities = new CintDynEntityCollection(serializedblock.ToString(), delimeter, crmsvc, log); result.Add(name, cEntities); SendLine("Block {0}: {1} records", name, cEntities.Count); } name = current.Substring(3); name = name.Substring(0, name.IndexOf(">>>", StringComparison.Ordinal)); serializedblock = new StringBuilder(); } else { serializedblock.AppendLine(current); } current = reader.ReadLine(); line++; } if (!string.IsNullOrWhiteSpace(serializedblock.ToString())) { CintDynEntityCollection cEntities = new CintDynEntityCollection(serializedblock.ToString(), delimeter, crmsvc, log); result.Add(name, cEntities); SendLine("Block {0}: {1} records", name, cEntities.Count); } } } log.EndSection(); return(result); }
private CintDynEntityCollection ExportDataBlock(ShuffleBlocks blocks, XmlNode xBlock) { log.StartSection("ExportDataBlock"); string name = CintXML.GetAttribute(xBlock, "Name"); log.Log("Block: {0}", name); CintDynEntityCollection cExportEntities = null; if (xBlock.Name != "DataBlock") { throw new ArgumentOutOfRangeException("Type", xBlock.Name, "Invalid Block type"); } string entity = CintXML.GetAttribute(xBlock, "Entity"); string type = CintXML.GetAttribute(xBlock, "Type"); XmlNode xExport = CintXML.FindChild(xBlock, "Export"); if (xExport != null) { if (string.IsNullOrEmpty(entity)) { entity = CintXML.GetAttribute(xExport, "Entity"); } #region Define attributes XmlNode xAttributes = CintXML.FindChild(xExport, "Attributes"); bool allcolumns = false; List <string> lAttributes = new List <string>(); List <string> lNullAttributes = new List <string>(); if (xAttributes != null) { foreach (XmlNode xAttr in xAttributes.ChildNodes) { if (xAttr.Name == "Attribute") { string attr = CintXML.GetAttribute(xAttr, "Name"); log.Log("Adding column: {0}", attr); lAttributes.Add(attr.Replace("*", "%")); if (attr.Contains("*")) { allcolumns = true; log.Log("Found wildcard"); } else { bool includenull = CintXML.GetBoolAttribute(xAttr, "IncludeNull", false); if (includenull) { lNullAttributes.Add(attr); } } } } } else { allcolumns = true; lAttributes.Add("*"); log.Log("Attributes not specified, retrieving all"); } #endregion Define attributes if (type == "Entity" || string.IsNullOrEmpty(type)) { #region QueryExpression Entity log.StartSection("Export entity " + entity); QueryExpression qExport = new QueryExpression(entity); if (CintXML.GetBoolAttribute(xExport, "ActiveOnly", true)) { CintQryExp.AppendConditionActive(qExport.Criteria); } foreach (var xBlockChild in xBlock.ChildNodes.Cast <XmlNode>()) { if (xBlockChild.Name == "Relation") { AddRelationFilter(blocks, xBlockChild, qExport.Criteria, log); } } foreach (XmlNode xExpProp in xExport.ChildNodes) { if (xExport.NodeType == XmlNodeType.Element) { switch (xExpProp.Name) { case "#comment": case "Attributes": break; case "Filter": AddFilter(qExport, xExpProp); break; case "Sort": qExport.AddOrder( CintXML.GetAttribute(xExpProp, "Attribute"), CintXML.GetAttribute(xExpProp, "Type") == "Desc" ? OrderType.Descending : OrderType.Ascending); break; default: throw new ArgumentOutOfRangeException("Name", xExpProp.Name, "Invalid subitem to export block " + name); } } } if (allcolumns) { qExport.ColumnSet = new ColumnSet(true); } else { foreach (string attr in lAttributes) { qExport.ColumnSet.AddColumn(attr); } } #if DEBUG log.Log("Converting to FetchXML"); try { var fetch = CintQryExp.ConvertToFetchXml(qExport, crmsvc); log.Log("Exporting {0}:\n{1}", entity, fetch); } catch (Exception ex) { log.Log("Conversion error:"); log.Log(ex); } #endif cExportEntities = CintDynEntity.RetrieveMultiple(crmsvc, qExport, log); if (allcolumns) { SelectAttributes(cExportEntities, lAttributes, lNullAttributes); } SendLine("Block {0} - {1} records", name, cExportEntities.Count); log.EndSection(); #endregion QueryExpression Entity } else if (type == "Intersect") { #region FetchXML Intersect log.StartSection("Export intersect " + entity); XmlDocument xDoc = new XmlDocument(); XmlNode xEntity = CintFetchXML.Create(xDoc, entity); CintFetchXML.AddAttribute(xEntity, lAttributes.ToArray()); foreach (var xBlockChild in xBlock.ChildNodes.Cast <XmlNode>()) { if (xBlockChild.Name == "Relation") { AddRelationFilter(blocks, xBlockChild, xEntity, log); } } var fetch = xDoc.OuterXml; fetch = fetch.Replace("<fetch ", "<fetch {0} {1} "); // Detta för att se till att CrmServiceProxy.RetrieveMultiple kan hantera paging #if DEBUG log.Log("Exporting intersect entity {0}\n{1}", entity, fetch); #endif var qExport = new FetchExpression(fetch); cExportEntities = CintDynEntity.RetrieveMultiple(crmsvc, qExport, log); foreach (var cde in cExportEntities) { List <KeyValuePair <string, object> > newattributes = new List <KeyValuePair <string, object> >(); foreach (var attr in cde.Attributes) { if (attr.Value is Guid) { var attrname = attr.Key; string relatedentity = attrname.Substring(0, attrname.Length - (attrname.EndsWith("idone") || attrname.EndsWith("idtwo") ? 5 : 2)); newattributes.Add(new KeyValuePair <string, object>(attrname, new EntityReference(relatedentity, (Guid)attr.Value))); } } foreach (var newattr in newattributes) { if (!newattr.Key.Equals(cde.PrimaryIdAttribute)) { cde.AddProperty(newattr.Key, newattr.Value); } } } log.EndSection(); #endregion FetchXML Intersect } log.Log("Returning {0} records", cExportEntities.Count); } log.EndSection(); return(cExportEntities); }
private void AddRelationFilter(ShuffleBlocks blocks, XmlNode xRelation, FilterExpression filter, ILoggable log) { log.StartSection(MethodBase.GetCurrentMethod().Name); if (blocks != null && blocks.Count > 0) { var block = CintXML.GetAttribute(xRelation, "Block"); var attribute = CintXML.GetAttribute(xRelation, "Attribute"); var pkattribute = CintXML.GetAttribute(xRelation, "PK-Attribute"); var includenull = CintXML.GetBoolAttribute(xRelation, "IncludeNull", false); var entityName = xRelation.ParentNode.Attributes["Entity"].Value; var type = GetAttributeType(attribute, entityName); ConditionExpression cond = new ConditionExpression(); cond.AttributeName = attribute; cond.Operator = Microsoft.Xrm.Sdk.Query.ConditionOperator.In; List <object> ids = new List <object>(); CintDynEntityCollection parentcoll = blocks.ContainsKey(block) ? blocks[block] : null; if (parentcoll != null && parentcoll.Count > 0) { foreach (CintDynEntity parent in parentcoll) { if (string.IsNullOrEmpty(pkattribute)) { if (type == AttributeTypeCode.String) { ids.Add(parent.Id.ToString()); } else { ids.Add(parent.Id); } } else if (type == AttributeTypeCode.String) { ids.Add(parent.Property <EntityReference>(pkattribute, new EntityReference()).Id.ToString()); } else { ids.Add(parent.Property <EntityReference>(pkattribute, new EntityReference()).Id); } } } else { // Adding temp guid to indicate "no matches", as ConditionOperator.In will fail if no values are given ids.Add(new Guid()); } cond.Values.AddRange(ids); if (!includenull) { filter.AddCondition(cond); } else { var orfilter = new FilterExpression(LogicalOperator.Or); orfilter.AddCondition(attribute, Microsoft.Xrm.Sdk.Query.ConditionOperator.Null); orfilter.AddCondition(cond); filter.AddFilter(orfilter); } log.Log("Adding relation condition for {0} in {1} values in {2}.{3}", attribute, ids.Count, block, pkattribute); } log.EndSection(); }
private void AddFilter(QueryExpression qExport, XmlNode xExpProp) { string valuestring = CintXML.GetAttribute(xExpProp, "Value"); if (valuestring.Contains("{0}")) { throw new ArgumentOutOfRangeException("Name", "Filter", "Parameterized Filters not supported in embedded Shuffle Utils"); } string operstr = CintXML.GetAttribute(xExpProp, "Operator"); if (string.IsNullOrEmpty(operstr)) { operstr = "Equal"; } Microsoft.Xrm.Sdk.Query.ConditionOperator oper = (Microsoft.Xrm.Sdk.Query.ConditionOperator)Enum.Parse(typeof(Microsoft.Xrm.Sdk.Query.ConditionOperator), operstr, true); object value = null; if (oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.EqualBusinessId && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.EqualUserId && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.EqualUserLanguage && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.NotEqualBusinessId && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.NotEqualUserId && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.NotNull && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.Null && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.ThisMonth && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.ThisWeek && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.ThisYear && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.Today && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.Tomorrow && oper != Microsoft.Xrm.Sdk.Query.ConditionOperator.Yesterday) { switch (CintXML.GetAttribute(xExpProp, "Type").ToUpperInvariant()) { case "STRING": value = valuestring; break; case "INT": value = int.Parse(valuestring); break; case "BOOL": value = bool.Parse(valuestring); break; case "DATETIME": value = DateTime.Parse(valuestring); break; case "GUID": value = new Guid(valuestring); break; default: throw new ArgumentOutOfRangeException("Type", CintXML.GetAttribute(xExpProp, "Type"), "Invalid filter attribute type"); } } string attribute = CintXML.GetAttribute(xExpProp, "Attribute"); log.Log("Adding filter: {0} {1} {2}", attribute, oper, value); CintQryExp.AppendCondition(qExport.Criteria, LogicalOperator.And, attribute, oper, value); }
private void ExportSolutionBlock(XmlNode xBlock) { log.StartSection("ExportSolutionBlock"); if (xBlock.Name != "SolutionBlock") { throw new ArgumentOutOfRangeException("Type", xBlock.Name, "Invalid Block type"); } string name = CintXML.GetAttribute(xBlock, "Name"); log.Log("Block: {0}", name); string path = CintXML.GetAttribute(xBlock, "Path"); string file = CintXML.GetAttribute(xBlock, "File"); if (string.IsNullOrWhiteSpace(path) && !string.IsNullOrWhiteSpace(definitionpath)) { path = definitionpath; path += path.EndsWith("\\") ? "" : "\\"; } if (string.IsNullOrWhiteSpace(file)) { file = name; } XmlNode xExport = CintXML.FindChild(xBlock, "Export"); if (xExport != null) { string type = CintXML.GetAttribute(xExport, "Type"); string setversion = CintXML.GetAttribute(xExport, "SetVersion"); bool publish = CintXML.GetBoolAttribute(xExport, "PublishBeforeExport", false); string targetversion = CintXML.GetAttribute(xExport, "TargetVersion"); CintDynEntity cdSolution = GetAndVerifySolutionForExport(name); var currentversion = new Version(cdSolution.Property("version", "1.0.0.0")); SendLine("Solution: {0} {1}", name, currentversion); if (!string.IsNullOrWhiteSpace(setversion)) { SetNewSolutionVersion(setversion, cdSolution, currentversion); } if (publish) { SendLine("Publishing customizations"); crmsvc.Execute(new PublishAllXmlRequest()); } ExportSolutionRequest req = new ExportSolutionRequest() { SolutionName = name }; #if Crm8 if (!string.IsNullOrWhiteSpace(targetversion)) { req.TargetVersion = targetversion; } #endif XmlNode xSettings = CintXML.FindChild(xExport, "Settings"); if (xSettings != null) { req.ExportAutoNumberingSettings = CintXML.GetBoolAttribute(xSettings, "AutoNumbering", false); req.ExportCalendarSettings = CintXML.GetBoolAttribute(xSettings, "Calendar", false); req.ExportCustomizationSettings = CintXML.GetBoolAttribute(xSettings, "Customization", false); req.ExportEmailTrackingSettings = CintXML.GetBoolAttribute(xSettings, "EmailTracking", false); req.ExportGeneralSettings = CintXML.GetBoolAttribute(xSettings, "General", false); req.ExportMarketingSettings = CintXML.GetBoolAttribute(xSettings, "Marketing", false); req.ExportOutlookSynchronizationSettings = CintXML.GetBoolAttribute(xSettings, "OutlookSync", false); req.ExportRelationshipRoles = CintXML.GetBoolAttribute(xSettings, "RelationshipRoles", false); req.ExportIsvConfig = CintXML.GetBoolAttribute(xSettings, "IsvConfig", false); } if (type == "Managed" || type == "Both") { string filename = path + file + "_managed.zip"; SendLine("Exporting solution to: {0}", filename); req.Managed = true; ExportSolutionResponse exportSolutionResponse = (ExportSolutionResponse)crmsvc.Execute(req); byte[] exportXml = exportSolutionResponse.ExportSolutionFile; File.WriteAllBytes(filename, exportXml); } if (type == "Unmanaged" || type == "Both") { string filename = path + file + ".zip"; SendLine("Exporting solution to: {0}", filename); req.Managed = false; ExportSolutionResponse exportSolutionResponse = (ExportSolutionResponse)crmsvc.Execute(req); byte[] exportXml = exportSolutionResponse.ExportSolutionFile; File.WriteAllBytes(filename, exportXml); } } log.EndSection(); }
private Tuple <int, int, int, int, int, EntityReferenceCollection> ImportDataBlock(XmlNode xBlock, CintDynEntityCollection cEntities) { log.StartSection("ImportDataBlock"); int created = 0; int updated = 0; int skipped = 0; int deleted = 0; int failed = 0; EntityReferenceCollection references = new EntityReferenceCollection(); string name = CintXML.GetAttribute(xBlock, "Name"); log.Log("Block: {0}", name); SendStatus(name, null); SendLine(); switch (xBlock.Name) { case "DataBlock": string type = CintXML.GetAttribute(xBlock, "Type"); XmlNode xImport = CintXML.FindChild(xBlock, "Import"); if (xImport != null) { var includeid = CintXML.GetBoolAttribute(xImport, "CreateWithId", false); var save = CintXML.GetAttribute(xImport, "Save"); var delete = CintXML.GetAttribute(xImport, "Delete"); var updateinactive = CintXML.GetBoolAttribute(xImport, "UpdateInactive", false); var updateidentical = CintXML.GetBoolAttribute(xImport, "UpdateIdentical", false); var deprecatedoverwrite = CintXML.GetAttribute(xImport, "Overwrite"); if (!string.IsNullOrWhiteSpace(deprecatedoverwrite)) { SendLine("DEPRECATED use of attribute Overwrite!"); bool overwrite = CintXML.GetBoolAttribute(xImport, "Overwrite", true); save = overwrite ? "CreateUpdate" : "CreateOnly"; } if (string.IsNullOrWhiteSpace(save)) { // Default save = "CreateUpdate"; } if (string.IsNullOrWhiteSpace(delete)) { // Default delete = "None"; } XmlNode xMatch = CintXML.FindChild(xImport, "Match"); var matchattributes = GetMatchAttributes(xMatch); var updateattributes = !updateidentical?GetUpdateAttributes(cEntities) : new List <string>(); var preretrieveall = xMatch != null?CintXML.GetBoolAttribute(xMatch, "PreRetrieveAll", false) : false; SendLine(); SendLine("Importing block {0} - {1} records ", name, cEntities.Count); var i = 1; if (delete == "All" && (matchattributes.Count == 0)) { // All records shall be deleted, no match attribute defined, so just get all and delete all string entity = CintXML.GetAttribute(xBlock, "Entity"); var qDelete = new QueryExpression(entity); qDelete.ColumnSet.AddColumn(crmsvc.PrimaryAttribute(entity, log)); var deleterecords = CintDynEntity.RetrieveMultiple(crmsvc, qDelete, log); SendLine("Deleting ALL {0} - {1} records", entity, deleterecords.Count); foreach (var record in deleterecords) { SendLine("{0:000} Deleting existing: {1}", i, record); try { record.Delete(); deleted++; } catch (FaultException <OrganizationServiceFault> ex) { if (ex.Message.ToUpperInvariant().Contains("DOES NOT EXIST")) { // This may happen through delayed cascade delete in CRM SendLine(" ...already deleted"); } else { throw; } } i++; } } int totalRecords = cEntities.Count; i = 1; CintDynEntityCollection cAllRecordsToMatch = null; foreach (CintDynEntity cdEntity in cEntities) { string unique = cdEntity.Id.ToString(); SendStatus(-1, -1, totalRecords, i); try { Guid oldid = cdEntity.Id; Guid newid = Guid.Empty; ReplaceGuids(cdEntity, includeid); ReplaceUpdateInfo(cdEntity); unique = GetEntityDisplayString(xMatch, cdEntity); SendStatus(null, unique); if (type == "Entity" || string.IsNullOrEmpty(type)) { #region Entity if (matchattributes.Count == 0) { if (save == "Never" || save == "UpdateOnly") { skipped++; SendLine("{0:000} Not saving: {1}", i, unique); } else { if (!includeid) { cdEntity.Id = Guid.Empty; } if (SaveEntity(cdEntity, null, updateinactive, updateidentical, i, unique)) { created++; newid = cdEntity.Id; references.Add(cdEntity.Entity.ToEntityReference()); } } } else { var matches = GetMatchingRecords(cdEntity, matchattributes, updateattributes, preretrieveall, ref cAllRecordsToMatch); if (delete == "All" || (matches.Count == 1 && delete == "Existing")) { foreach (CintDynEntity cdMatch in matches) { SendLine("{0:000} Deleting existing: {1}", i, unique); try { cdMatch.Delete(); deleted++; } catch (FaultException <OrganizationServiceFault> ex) { if (ex.Message.ToUpperInvariant().Contains("DOES NOT EXIST")) { // This may happen through cascade delete in CRM SendLine(" ...already deleted"); } else { throw; } } } matches.Clear(); } if (matches.Count == 0) { if (save == "Never" || save == "UpdateOnly") { skipped++; SendLine("{0:000} Not creating: {1}", i, unique); } else { if (!includeid) { cdEntity.Id = Guid.Empty; } if (SaveEntity(cdEntity, null, updateinactive, updateidentical, i, unique)) { created++; newid = cdEntity.Id; references.Add(cdEntity.Entity.ToEntityReference()); } } } else if (matches.Count == 1) { var match = matches[0]; newid = match.Id; if (save == "CreateUpdate" || save == "UpdateOnly") { if (SaveEntity(cdEntity, match, updateinactive, updateidentical, i, unique)) { updated++; references.Add(cdEntity.Entity.ToEntityReference()); } else { skipped++; } } else { skipped++; SendLine("{0:000} Exists: {1}", i, unique); } } else { failed++; SendLine("Import object matches {0} records in target database!", matches.Count); SendLine(unique); } } if (!oldid.Equals(Guid.Empty) && !newid.Equals(Guid.Empty) && !oldid.Equals(newid) && !guidmap.ContainsKey(oldid)) { log.Log("Mapping IDs: {0} ==> {1}", oldid, newid); guidmap.Add(oldid, newid); } #endregion Entity } else if (type == "Intersect") { #region Intersect if (cdEntity.Attributes.Count != 2) { throw new ArgumentOutOfRangeException("Attributes", cdEntity.Attributes.Count, "Invalid Attribute count for intersect object"); } string intersect = CintXML.GetAttribute(xBlock, "IntersectName"); if (string.IsNullOrEmpty(intersect)) { intersect = cdEntity.Name; } EntityReference ref1 = (EntityReference)cdEntity.Attributes.ElementAt(0).Value; EntityReference ref2 = (EntityReference)cdEntity.Attributes.ElementAt(1).Value; CintDynEntity party1 = CintDynEntity.InitFromNameAndId(ref1.LogicalName, ref1.Id, crmsvc, log); CintDynEntity party2 = CintDynEntity.InitFromNameAndId(ref2.LogicalName, ref2.Id, crmsvc, log); try { party1.Associate(party2, intersect); created++; SendLine("{0} Associated: {1}", i.ToString().PadLeft(3, '0'), name); } catch (Exception ex) { if (ex.Message.Contains("duplicate")) { SendLine("{0} Association exists: {1}", i.ToString().PadLeft(3, '0'), name); skipped++; } else { throw; } } #endregion Intersect } } catch (Exception ex) { failed++; SendLine("\n*** Error record: {0} ***\n{1}", unique, ex.Message); log.Log(ex); if (stoponerror) { throw; } } i++; } SendLine("Created: {0} Updated: {1} Skipped: {2} Deleted: {3} Failed: {4}", created, updated, skipped, deleted, failed); } break; default: throw new ArgumentOutOfRangeException("Type", xBlock.Name, "Invalid Block type"); } log.EndSection(); return(new Tuple <int, int, int, int, int, EntityReferenceCollection>(created, updated, skipped, deleted, failed, references)); }
private void ValidatePreReqs(XmlNode xImport, Version thisversion) { log.StartSection("ValidatePreReqs"); XmlNode xPreReqs = CintXML.FindChild(xImport, "PreRequisites"); if (xPreReqs != null) { CintDynEntityCollection cSolutions = GetExistingSolutions(); foreach (XmlNode xPreReq in xPreReqs.ChildNodes) { if (xPreReq.NodeType == XmlNodeType.Element && xPreReq.Name == "Solution") { bool valid = false; string name = CintXML.GetAttribute(xPreReq, "Name"); string comparer = CintXML.GetAttribute(xPreReq, "Comparer"); var version = new Version(); log.Log("Prereq: {0} {1} {2}", name, comparer, version); if (comparer.Contains("this")) { version = thisversion; comparer = comparer.Replace("-this", ""); } else if (comparer != "any") { version = new Version(CintXML.GetAttribute(xPreReq, "Version").Replace('*', '0')); } foreach (CintDynEntity cdSolution in cSolutions) { if (cdSolution.Property("uniquename", "") == name) { log.Log("Found matching solution"); switch (comparer) { case "any": valid = true; break; case "eq": valid = new Version(cdSolution.Property("version", "1.0.0.0")).Equals(version); break; case "ge": valid = new Version(cdSolution.Property("version", "<undefined>")) >= version; break; default: throw new ArgumentOutOfRangeException("Comparer", comparer, "Invalid comparer value"); } } if (valid) { break; } } if (valid) { SendLine("Prerequisite {0} {1} {2} is satisfied", name, comparer, version); } else { SendLine("Prerequisite {0} {1} {2} is NOT satisfied", name, comparer, version); throw new Exception("Prerequisite NOT satisfied (" + name + " " + comparer + " " + version + ")"); } } } } else { log.Log("No prereqs for solution import"); } log.EndSection(); }
private ItemImportResult ImportSolutionBlock(XmlNode xBlock) { log.StartSection("ImportSolutionBlock"); var importResult = ItemImportResult.None; if (xBlock.Name != "SolutionBlock") { throw new ArgumentOutOfRangeException("Type", xBlock.Name, "Invalid Block type"); } XmlNode xImport = CintXML.FindChild(xBlock, "Import"); if (xImport != null) { string name = CintXML.GetAttribute(xBlock, "Name"); log.Log("Block: {0}", name); SendStatus(name, null); string type = CintXML.GetAttribute(xImport, "Type"); SendLine(); SendLine("Importing solution: {0}", name); string filename = GetSolutionFilename(xBlock, name, type); var version = ExtractVersionFromSolutionZip(filename); try { ValidatePreReqs(xImport, version); SolutionImportConditions ImportCondition = CheckIfImportRequired(xImport, name, version); if (ImportCondition != SolutionImportConditions.Skip) { if (DoImportSolution(xImport, filename, version)) { if (ImportCondition == SolutionImportConditions.Create) { importResult = ItemImportResult.Created; } else { importResult = ItemImportResult.Updated; } } else { importResult = ItemImportResult.Failed; log.Log("Failed during import"); } bool publish = CintXML.GetBoolAttribute(xImport, "PublishAll", false); if (publish) { SendLine("Publishing customizations"); crmsvc.Execute(new PublishAllXmlRequest()); } } else { importResult = ItemImportResult.Skipped; log.Log("Skipped due to import condition"); } } catch (Exception ex) { log.Log(ex); importResult = ItemImportResult.Failed; if (stoponerror) { throw; } } } log.EndSection(); return(importResult); }