public void Execute(IServiceProvider serviceProvider) { var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); 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 = (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)) { var entityName = context.PrimaryEntityName; if (Reflection.Types.MESSAGE_WITHOUT_PRIMARY_ENTITY.Contains(message)) { entityName = null; } var methods = PluginMethodCache.ForPlugin(this.GetType(), stage, message, entityName, context.Mode == 1); foreach (var method in methods) { #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; foreach (var p in method.Parameters) { args[ix] = serviceCache.Resolve(p); if (stage <= 20) { if (p.IsMergedimage) { mergedimage = (System.ComponentModel.INotifyPropertyChanged)args[ix]; } if (p.IsTarget) { target = args[ix] as System.ComponentModel.INotifyPropertyChanged; } } ix++; } #endregion #region add mergedimage eventlistener if applicable PropertyMirror mergedimageMirror = null; PropertyMirror targetMirror = null; if (stage <= 20) { 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 try { method.Invoke(this, args); } finally { #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 } } }
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; } } }
public void Execute(IServiceProvider serviceProvider) { var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); var userId = context.UserId; var message = context.MessageName; if (message != "Retrieve" && message != "RetrieveMultiple") { throw new InvalidPluginExecutionException($"Unsupported message in VirtualEntityPlugin { message }. Only Retrieve and RetrieveMultiple is supported"); } var type = (CrmEventType)Enum.Parse(typeof(CrmEventType), context.MessageName); IPluginContext pluginContext = new Services.PluginContext(this.UnsecureConfig, this.SecureConfig, context, type, userId); IOrganizationService toolOrgService = null; if (type == CrmEventType.Retrieve || type == CrmEventType.RetrieveMultiple) { toolOrgService = serviceFactory.CreateOrganizationService(null); } using (var serviceCache = new Reflection.ServiceCache(context, serviceFactory, tracingService, pluginContext, this.UnsecureConfig, this.SecureConfig)) { var method = PluginMethodCache.ForPlugin(this.GetType(), 30, message, context.PrimaryEntityName, context.Mode == 1).Single(); var args = new object[method.Parameters.Length]; var ix = 0; Microsoft.Xrm.Sdk.Entity datasource = null; foreach (var p in method.Parameters) { if (p.Name != null && p.Name.ToLower() == "datasource") { if (datasource == null) { throw new NotImplementedException(); } args[ix] = datasource; } else { args[ix] = serviceCache.Resolve(p, toolOrgService); } ix++; } var result = method.Invoke(this, args); if (result != null) { if (message == "Retrieve") { var be = result as Microsoft.Xrm.Sdk.Entity; if (be == null) { throw new InvalidPluginExecutionException("Return from virtual antity Retrieve must be of type Microsoft.Xrm.Sdk.Entity"); } if (be.GetType() != typeof(Microsoft.Xrm.Sdk.Entity)) { var fr = new Microsoft.Xrm.Sdk.Entity { Id = be.Id, LogicalName = be.LogicalName }; fr.Attributes = be.Attributes; be = fr; } this.RemoveNullValues(be); context.OutputParameters["BusinessEntity"] = be; } if (message == "RetrieveMultiple") { var bes = result as Microsoft.Xrm.Sdk.EntityCollection; if (bes == null) { throw new InvalidPluginExecutionException("Return from virtual entity RetrieveMultiple must be of type Microsoft.Xrm.Sdk.EntityCollection"); } var entities = bes.Entities.ToArray(); bes.Entities.Clear(); foreach (var be in entities) { if (be.GetType() == typeof(Microsoft.Xrm.Sdk.Entity)) { bes.Entities.Add(be); } else { var fr = new Microsoft.Xrm.Sdk.Entity { Id = be.Id, LogicalName = be.LogicalName }; fr.Attributes = be.Attributes; bes.Entities.Add(fr); } } foreach (var fe in bes.Entities) { this.RemoveNullValues(fe); } context.OutputParameters["BusinessEntityCollection"] = bes; } } } }