public static string ToCommaSeparatedString(this Microsoft.Xrm.Sdk.EntityCollection value) { if (value == null) { return("None"); } string output = string.Empty; foreach (Microsoft.Xrm.Sdk.Entity record in value.Entities) { if (record.Contains("partyid")) { if (!(output.Equals(String.Empty))) { output += ", "; } Microsoft.Xrm.Sdk.EntityReference entRef = (Microsoft.Xrm.Sdk.EntityReference)record.Attributes["partyid"]; output += entRef.Name + ""; } else if (record.Contains("addressused")) { string emailAddress = (string)record["addressused"]; if (!(emailAddress.Equals(String.Empty))) { if (!(output.Equals(String.Empty))) { output += ", "; } output += emailAddress; } } else if (record.Contains("name")) { string name = (string)record["name"]; if (!(name.Equals(String.Empty))) { if (!(output.Equals(String.Empty))) { output += ", "; } output += name; } } else if (record.Contains("crmcs_name")) { string name = (string)record["crmcs_name"]; if (!(name.Equals(String.Empty))) { if (!(output.Equals(String.Empty))) { output += ", "; } output += name; } } } return(output); }
public Guid?CreateTaskToCRMIncident(string ticketnumber, TimeItem timeItem) { try { Microsoft.Xrm.Sdk.Query.QueryExpression GetCasesByTicketNumber = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = "incident", ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet(true) }; GetCasesByTicketNumber.Criteria.AddCondition("ticketnumber", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, ticketnumber); Microsoft.Xrm.Sdk.EntityCollection CaseResults = _service.RetrieveMultiple(GetCasesByTicketNumber); if (CaseResults.Entities.Count < 1) { return(null); } Microsoft.Xrm.Sdk.Entity followup = new Microsoft.Xrm.Sdk.Entity("task"); if (timeItem.title != null) { followup["subject"] = timeItem.title.Replace(ticketnumber, ""); } if (timeItem.description != null) { followup["description"] = timeItem.description; } if (timeItem.isBillable == true && timeItem.isBillable != null) { followup["actualdurationminutes"] = (int)TimeSpan.Parse(timeItem.time).TotalMinutes; followup["hsal_nonbillableduration"] = 0; } else { followup["actualdurationminutes"] = 0; followup["hsal_nonbillableduration"] = (int)TimeSpan.Parse(timeItem.time).TotalMinutes; } followup["actualstart"] = DateTime.UtcNow; followup["regardingobjectid"] = CaseResults.Entities[0].ToEntityReference(); Guid taskId = _service.Create(followup); Microsoft.Crm.Sdk.Messages.SetStateRequest req = new Microsoft.Crm.Sdk.Messages.SetStateRequest(); req.EntityMoniker = new Microsoft.Xrm.Sdk.EntityReference("task", taskId); req.State = new Microsoft.Xrm.Sdk.OptionSetValue(1); req.Status = new Microsoft.Xrm.Sdk.OptionSetValue((5)); _service.Execute(req); return(taskId); } catch (Exception ex) { //log error throw ex; } }
public Guid?CreateExternalComment(string ticketnumber, TimeItem timeItem) { try { Microsoft.Xrm.Sdk.Query.QueryExpression GetCasesByTicketNumber = new Microsoft.Xrm.Sdk.Query.QueryExpression { EntityName = "incident", ColumnSet = new Microsoft.Xrm.Sdk.Query.ColumnSet(true) }; GetCasesByTicketNumber.Criteria.AddCondition("ticketnumber", Microsoft.Xrm.Sdk.Query.ConditionOperator.Equal, ticketnumber); Microsoft.Xrm.Sdk.EntityCollection CaseResults = _service.RetrieveMultiple(GetCasesByTicketNumber); if (CaseResults.Entities.Count < 1) { return(null); } Microsoft.Xrm.Sdk.Entity comment = new Microsoft.Xrm.Sdk.Entity("hsal_externalcomments"); if (timeItem.title != null) { comment["subject"] = timeItem.title.Replace(ticketnumber, ""); } if (timeItem.description != null) { comment["description"] = timeItem.description; } comment["regardingobjectid"] = CaseResults.Entities[0].ToEntityReference(); Guid externalCommentId = _service.Create(comment); Microsoft.Crm.Sdk.Messages.SetStateRequest req = new Microsoft.Crm.Sdk.Messages.SetStateRequest(); req.EntityMoniker = new Microsoft.Xrm.Sdk.EntityReference("hsal_externalcomments", externalCommentId); req.State = new Microsoft.Xrm.Sdk.OptionSetValue(1); req.Status = new Microsoft.Xrm.Sdk.OptionSetValue((2)); _service.Execute(req); return(externalCommentId); } catch (Exception ex) { //log error throw ex; } }
public void Execute(IServiceProvider serviceProvider) { var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); var toolOrgService = serviceFactory.CreateOrganizationService(null); var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); var userId = context.UserId; var message = context.MessageName; var stage = context.Stage; var isAsync = context.Mode == 1; var type = message.Contains("_") ? CrmEventType.CustomPlugin : (CrmEventType)Enum.Parse(typeof(CrmEventType), context.MessageName); IPluginContext pluginContext = new Services.PluginContext(this.UnsecureConfig, this.SecureConfig, context, type, userId); using (var serviceCache = new Reflection.ServiceCache(context, serviceFactory, tracingService, pluginContext, this.UnsecureConfig, this.SecureConfig)) { var entityName = context.PrimaryEntityName; if (entityName == "none" || Reflection.Types.MESSAGE_WITHOUT_PRIMARY_ENTITY.Contains(message)) { entityName = null; } var methods = PluginMethodCache.ForPlugin(this.GetType(), stage, message, entityName, context.Mode == 1); var logs = new System.Collections.Generic.List <string>(); try { foreach (var method in methods) { #region evaluate if needed - based on If attributes if (method.IfAttribute != null) { var con = Reflection.MethodConditionEvaluater.Evaluate(method.IfAttribute, context); if (!con) { continue; } } #endregion var nextlog = $"{method.Name}("; #region find out if method is relevant, looking a target fields if (message == Attributes.StepAttribute.MessageEnum.Update.ToString() && !method.FilterAllProperties) { var targetEntity = (Microsoft.Xrm.Sdk.Entity)context.InputParameters["Target"]; if (!method.IsRelevant(targetEntity)) { continue; } } #endregion #region now resolve all parameters var args = new object[method.Parameters.Length]; var ix = 0; System.ComponentModel.INotifyPropertyChanged mergedimage = null; System.ComponentModel.INotifyPropertyChanged target = null; var comma = ""; foreach (var p in method.Parameters) { nextlog += $"{comma}{p?.FromType?.FullName}"; comma = ", "; if (p.IsInputParameter) { if (context.InputParameters.ContainsKey(p.Name)) { args[ix] = context.InputParameters[p.Name]; } else { if (p.Name != null) { if (p.Name.ToLower() == nameof(this.UnsecureConfig).ToLower()) { args[ix] = this.UnsecureConfig; } else if (p.Name.ToLower() == nameof(this.SecureConfig).ToLower()) { args[ix] = this.SecureConfig; } else { args[ix] = null; } } else { args[ix] = null; } } } else { args[ix] = serviceCache.Resolve(p, toolOrgService); } #region set TargetAttributes if (message == "Create" || message == "Update") { if (p.IsMergedimage || p.IsPreimage || p.IsPostimage) { var tap = args[ix].GetType().GetProperty("TargetAttributes"); if (tap != null) { var tg = (Microsoft.Xrm.Sdk.Entity)context.InputParameters["Target"]; tap.SetValue(args[ix], tg.Attributes); } } } #endregion #region set preimage attributes if (p.IsMergedimage || p.IsTarget || p.IsPreimage || p.IsPostimage) { if (message == "Update" || message == "Delete") { if (context.PreEntityImages != null && context.PreEntityImages.Values != null) { var col = new AttributeCollection(); foreach (Entity pre in context.PreEntityImages.Values) { foreach (var at in pre.Attributes) { if (!col.Keys.Contains(at.Key)) { col.Add(at.Key, at.Value); } } } var tap = args[ix].GetType().GetProperty("PreimageAttributes"); if (tap != null) { tap.SetValue(args[ix], col); } } } } #endregion #region add property notification to ensure mirror of set in pre state on merged images if (stage <= 20 && message == "Update") { if (p.IsMergedimage) { mergedimage = (System.ComponentModel.INotifyPropertyChanged)args[ix]; } if (p.IsTarget) { target = args[ix] as System.ComponentModel.INotifyPropertyChanged; } } #endregion ix++; } #endregion #region add mergedimage eventlistener if applicable PropertyMirror mergedimageMirror = null; PropertyMirror targetMirror = null; if (stage <= 20 && message == "Update") { if (mergedimage != null) { var tg = (Microsoft.Xrm.Sdk.Entity)context.InputParameters["Target"]; mergedimageMirror = new PropertyMirror(tg); mergedimage.PropertyChanged += mergedimageMirror.MirrorpropertyChanged; } if (mergedimage != null && target != null) { targetMirror = new PropertyMirror((Microsoft.Xrm.Sdk.Entity)mergedimage); target.PropertyChanged += targetMirror.MirrorpropertyChanged; } } #endregion #region run the method var inError = false; nextlog += ")"; try { logs.Add($"before: {nextlog}"); var result = method.Invoke(this, args); logs.Add($"after: {nextlog}"); if (result != null && method.OutputProperties != null && method.OutputProperties.Count > 0) { foreach (var key in method.OutputProperties.Keys) { var output = method.OutputProperties[key]; var value = key.GetValue(result); if (value != null) { #region map strongly typed entities back to base entities to allow correct serrialization back to client if (value is Microsoft.Xrm.Sdk.Entity e && value.GetType() != typeof(Microsoft.Xrm.Sdk.Entity)) { var entity = new Microsoft.Xrm.Sdk.Entity(e.LogicalName, e.Id); entity.Attributes = e.Attributes; value = entity; } if (value is Microsoft.Xrm.Sdk.EntityCollection ec && ec.Entities != null && ec.Entities.Count > 0) { var final = new Microsoft.Xrm.Sdk.EntityCollection { EntityName = ec.EntityName }; foreach (var ent in ec.Entities) { if (ent.GetType() == typeof(Microsoft.Xrm.Sdk.Entity)) { final.Entities.Add(ent); } else { var entity = new Microsoft.Xrm.Sdk.Entity(ent.LogicalName, ent.Id); entity.Attributes = ent.Attributes; final.Entities.Add(entity); } } value = final; } #endregion context.OutputParameters[output.LogicalName] = value; } } } } catch (Microsoft.Xrm.Sdk.InvalidPluginExecutionException) { inError = true; throw; } catch (System.Reflection.TargetInvocationException te) { inError = true; if (te.InnerException != null && te.InnerException is Microsoft.Xrm.Sdk.InvalidPluginExecutionException) { throw te.InnerException; } if (te.InnerException != null) { throw new InvalidPluginExecutionException(te.InnerException.Message, te.InnerException); } throw new InvalidPluginExecutionException(te.Message, te); } catch (Exception be) { inError = true; if (be.GetType().BaseType?.FullName == "Kipon.Xrm.Exceptions.BaseException") { // it is not a unit test, its the real thing, so we map the exception to a supported exception to allow message to parse all the way to the client throw new InvalidPluginExecutionException($"{be.GetType().FullName}: {be.Message}", be); } throw new InvalidPluginExecutionException(be.Message, be); } finally { if (!inError) { #region cleanup mirror if (stage <= 20) { if (mergedimageMirror != null) { mergedimage.PropertyChanged -= mergedimageMirror.MirrorpropertyChanged; mergedimageMirror = null; } if (targetMirror != null) { target.PropertyChanged -= targetMirror.MirrorpropertyChanged; targetMirror = null; } } #endregion #region prepare for next method serviceCache.OnStepFinalize(); #endregion } } #endregion } } catch (Exception ex) { tracingService.Trace(ex.Message); tracingService.Trace(ex.GetType().FullName); tracingService.Trace(ex.StackTrace); foreach (var l in logs) { tracingService.Trace(l); } throw; } } }
/// <summary>internal</summary> public QuickFindResult(int error, EntityCollection entities) { this.errorCode = error; this.data = entities; this.queryColumnSet = (DataCollection <string>)null; }
private static string MapAttributesToJsonTemplate(Microsoft.Xrm.Sdk.Entity record, string jsonTemplate, string orgUrl, bool doHyperlinks = true, bool doLinksAsAdaptive = true) { try { if (!string.IsNullOrEmpty(jsonTemplate)) { foreach (KeyValuePair <string, object> kvp in record.Attributes) { if (!jsonTemplate.Contains("{" + kvp.Key + "}")) { // move to next element if not detected within the template continue; } string type = kvp.Value.GetType().Name.ToLower(); string value = kvp.Value.ToString(); string hyperlink = string.Empty; switch (type) { case ("entityreference"): { Microsoft.Xrm.Sdk.EntityReference refVal = (Microsoft.Xrm.Sdk.EntityReference)kvp.Value; value = refVal.Name; if (doHyperlinks) { hyperlink = orgUrl + "/main.aspx?forceUCI=1&etn=" + refVal.LogicalName + "&id=" + refVal.Id + "&pagetype=entityrecord"; } break; } case ("optionsetvalue"): { value = record.GetValueDisplayString(kvp.Key); break; } case ("datetime"): { DateTime dtVal = (DateTime)kvp.Value; value = dtVal.ToString("dd/MM/yyyy"); break; } case ("money"): { Money mVal = (Money)kvp.Value; value = mVal.Value.ToString("#,###,##0"); break; } case ("entitycollection"): { if (kvp.Value != null) { Microsoft.Xrm.Sdk.EntityCollection collection = (Microsoft.Xrm.Sdk.EntityCollection)kvp.Value; value = collection.ToCommaSeparatedString(); } else { value = "None"; } break; } default: { object o = kvp.Value; if (o != null) { value = o.ToString(); } else { value = ""; } break; } } if (!String.IsNullOrEmpty(hyperlink)) { if (doLinksAsAdaptive) { // In AdaptiveCards, Links are formatted as [caption](url link) jsonTemplate = jsonTemplate.Replace("{" + kvp.Key.ToLower() + "}", "[" + value + "](" + hyperlink + ")"); } else { jsonTemplate = jsonTemplate.Replace("{" + kvp.Key.ToLower() + "}", hyperlink); } } else { jsonTemplate = jsonTemplate.Replace("{" + kvp.Key.ToLower() + "}", value); } if (orgUrl != null) { jsonTemplate = jsonTemplate.Replace("{recordurl}", orgUrl + "/main.aspx?" + "etn=" + record.LogicalName + "&id=%7B" + record.Id + "%7D" + "&pagetype=entityrecord" + "&forceUCI=1"); } } // final step - remove all occuring strings by "{ and }" - effectively blanking the unmapped schemas string result = jsonTemplate; while (true) { int indexOfOpen = result.IndexOf("\"{"); int indexOfClose = result.IndexOf("}\"", indexOfOpen + 1); if (indexOfOpen < 0 && indexOfClose < 0) { break; } result = result.Substring(0, indexOfOpen) + "\"" + result.Substring(indexOfClose + 1); } if (result != jsonTemplate) { jsonTemplate = result; } } return(jsonTemplate); } catch (Exception e) { throw new Exception("SS21.Examples.TeamBot.AdaptiveCardFactory.MapAttributesToJsonTemplate :: ERROR :: Unable to map attributes to JSON template due to the following reason/s " + Environment.NewLine + e.Message); } }
public static string ProcessDynamicContent(Microsoft.Xrm.Sdk.Entity record, string jsonTemplate) { try { JObject jobject = JObject.Parse(jsonTemplate); JArray a = JArray.Parse(jobject["body"].ToString()); JArray newArray = new JArray(); foreach (JObject o in a.Children <JObject>()) { bool dynamicContent = false; string schemaName = string.Empty; foreach (JProperty p in o.Properties()) { if (p.Name.Equals("dynamicContent")) { dynamicContent = true; } if (p.Name.Equals("text")) { // extract schema name between { } ex. {description} // schemaName = description schemaName = (string)o["text"]; if (!string.IsNullOrEmpty(schemaName)) { schemaName = schemaName.Substring(1, schemaName.Length - 2); } } } // placeholder json for new textbox element string jsonElement = @"{ ""type"": ""TextBlock"", ""text"": """", ""wrap"": true, }"; if (!String.IsNullOrEmpty(schemaName)) { // get value by schema name from Record if (record.Contains(schemaName)) { string fieldValue = (string)record[schemaName]; // remove html and perform string split fieldValue = ConvertHTMLToText(fieldValue); if (record.LogicalName == "email") { // remove any emails after the first detected email in the chain int stringPosition = fieldValue.IndexOf("From:"); if (stringPosition != -1) { fieldValue = fieldValue.Substring(0, stringPosition); } // attempt to remove signature by mapping from name Microsoft.Xrm.Sdk.EntityCollection collection = (Microsoft.Xrm.Sdk.EntityCollection)record["from"]; string fromValue = collection.ToCommaSeparatedString(); stringPosition = fieldValue.IndexOf(fromValue); if (stringPosition != -1) { fieldValue = fieldValue.Substring(0, stringPosition); } } // dodge - replace multiple line break characters with a unique break string fieldValue = Regex.Replace(fieldValue, "[\r\n\f]", "/crmcs/", System.Text.RegularExpressions.RegexOptions.IgnoreCase); string[] fieldValues = fieldValue.Split(new string[] { "/crmcs/" }, StringSplitOptions.None); for (int i = 0; i < fieldValues.Length; i++) { string value = fieldValues[i]; if (!string.IsNullOrEmpty(value)) { JObject newElement = null; if (i == 0) { // first value to replace current element newElement = o; } else { // next value set as new textbox element newElement = JObject.Parse(jsonElement); } newElement["text"] = value; newArray.Add(newElement); } } } else { // do nothing } } else { newArray.Add(o); } } jobject["body"] = newArray; // return formatted JSON Template as string to keep things consistent return(jobject.ToString()); } catch (Exception ex) { throw new Exception("ProcessDynamicContent :: " + ex.Message); } }