/// <summary> /// Executes the plug-in. /// </summary> /// <param name="serviceProvider">The service provider.</param> /// <remarks> /// For improved performance, Microsoft Dynamics CRM caches plug-in instances. /// The plug-in's Execute method should be written to be stateless as the constructor /// is not called for every invocation of the plug-in. Also, multiple system threads /// could execute the plug-in at the same time. All per invocation state information /// is stored in the context. This means that you should not use global variables in plug-ins. /// </remarks> public void Execute(IServiceProvider serviceProvider) { var sw = new Stopwatch(); if (serviceProvider == null) { throw new ArgumentNullException(nameof(serviceProvider)); } // Construct the Local plug-in context. var localContext = new LocalPluginContext(serviceProvider); localContext.Log($"Entity: {localContext.PrimaryEntityName}, Message: {localContext.MessageName}, Stage: {Enum.ToObject(typeof(Stages), localContext.Stage)}, Mode: {localContext.Mode}"); localContext.Log($"\r\nClass {ChildClassName}"); localContext.Log($"\r\nUserId\t\t\t\t{localContext.UserId}\r\nInitiatingUserId\t{localContext.InitiatingUserId}"); localContext.Log($"\r\nStart : {DateTime.Now:dd/MM/yyyy HH:mm:ss.fff}"); sw.Restart(); try { if (SendToRemoteDebugger(localContext)) { return; } IEnumerable <Step> steps; if (_isCustomApi) { steps = new List <Step> { new Step(this, localContext.MessageName, Stages.PostOperation, Modes.Synchronous, _customApiEntityName, _customApiMethodName) }; } else { steps = (from a in _newRegisteredEvents where ( localContext.IsStage(a.Stage) && localContext.IsMessage(a.Message) && localContext.Mode == a.Mode && (string.IsNullOrWhiteSpace(a.EntityName) || a.EntityName == localContext.PrimaryEntityName) ) select a); } var stage = Enum.ToObject(typeof(Stages), localContext.Stage); sw.Restart(); localContext.Log("------------------ Input Variables (before) ------------------"); localContext.DumpInputParameters(); localContext.Log("\r\n------------------ Shared Variables (before) ------------------"); localContext.DumpSharedVariables(); localContext.Log("\r\n---------------------------------------------------------------"); foreach (var step in steps) { sw.Restart(); if (step.Message == Messages.Update && step.FilteringAttributes.Any()) { var target = localContext.GetInputParameter <Entity>(InputParameters.Target); var useStep = false; foreach (var attributeName in target.Attributes.Select(a => a.Key)) { useStep |= step.FilteringAttributes.Contains(attributeName); } if (!useStep) { localContext.Log( "\r\n{0}.{5} is not fired because filteringAttributes filter is not met.", ChildClassName, localContext.PrimaryEntityName, localContext.MessageName, stage, localContext.Mode, step.Method.Name); continue; } } var entityAction = step.Method; localContext.Log($"\r\n\r\n{ChildClassName}.{step.Method.Name} is firing"); sw.Restart(); localContext.Log($"{ChildClassName}.{step.Method.Name} Start"); localContext.InvokeMethod(this, entityAction); localContext.Log($"{ChildClassName}.{step.Method.Name} End, duration : {sw.Elapsed}"); } if (localContext.IsStage(Stages.PreValidation) || localContext.IsStage(Stages.PreOperation)) { localContext.Log("\r\n\r\n------------------ Input Variables (after) ------------------"); localContext.DumpInputParameters(); localContext.Log("\r\n------------------ Shared Variables (after) ------------------"); localContext.DumpSharedVariables(); localContext.Log("\r\n---------------------------------------------------------------"); } } catch (FaultException <OrganizationServiceFault> e) { localContext.Log($"Exception: {e}"); // Handle the exception. throw; } catch (TargetInvocationException e) { localContext.Log($"Exception : {e.InnerException}"); if (e.InnerException != null) { if (e.InnerException is InvalidPluginExecutionException invalidPluginExecutionException) { throw invalidPluginExecutionException; } else { throw new InvalidPluginExecutionException(e.InnerException.Message); } } } catch (JsonException e) { throw new InvalidPluginExecutionException(e.ToString()); } finally { localContext.Log($"Exiting {ChildClassName}.Execute()"); localContext.Log($"End : {DateTime.Now:dd/MM/yyyy HH:mm:ss.fff}\r\n"); } }
private bool SendToRemoteDebugger(LocalPluginContext localContext) { if (!localContext.IsDebugContext) { localContext.Log("The context is genuine"); localContext.Log($"UnSecuredConfig : {UnSecuredConfig}"); //if (!string.IsNullOrEmpty(UnSecuredConfig) && UnSecuredConfig.Contains("debugSessions")) //{ // var debuggerUnsecuredConfig = JsonConvert.DeserializeObject<DebuggerUnsecureConfig>(UnSecuredConfig); // localContext.Log($"Debug session ids : {string.Join(",", debuggerUnsecuredConfig.DebugSessionIds)}"); var initiatingUserId = localContext.GetInitiatingUserId(); localContext.Log($"Initiating user Id : {initiatingUserId}"); var queryDebugSessions = BindingModelHelper.GetRetrieveAllQuery <DebugSession>(); queryDebugSessions.Criteria.AddCondition(DebugSessionDefinition.Columns.DebugeeId, ConditionOperator.Equal, initiatingUserId); queryDebugSessions.Criteria.AddCondition(DebugSessionDefinition.Columns.StateCode, ConditionOperator.Equal, DebugSessionState.Active.ToInt()); //queryDebugSessions.Criteria.AddCondition(DebugSessionDefinition.Columns.Id, ConditionOperator.In, debuggerUnsecuredConfig.DebugSessionIds.Cast<object>().ToArray()); var debugSession = localContext.AdminOrganizationService.RetrieveAll <DebugSession>(queryDebugSessions).FirstOrDefault(); localContext.Log($"Debug session : {debugSession}"); if (debugSession != null) { if (debugSession.SessionEnd >= DateTime.Today) { var remoteContext = localContext.RemoteContext; remoteContext.Id = Guid.NewGuid(); remoteContext.TypeAssemblyQualifiedName = GetType().AssemblyQualifiedName; remoteContext.UnsecureConfig = UnSecuredConfig; remoteContext.SecureConfig = SecuredConfig; var uri = new Uri($"{debugSession.RelayUrl}/{debugSession.HybridConnectionName}"); try { using var hybridConnection = new HybridConnection(debugSession.SasKeyName, debugSession.SasConnectionKey, uri.AbsoluteUri); var message = new RemoteDebuggerMessage(RemoteDebuggerMessageType.Context, remoteContext, remoteContext.Id); RemoteDebuggerMessage response; while (true) { localContext.Log("Sending context to local machine : {0}", message); response = hybridConnection.SendMessage(message).GetAwaiter().GetResult(); localContext.Log("Received response : {0}", response); if (response.MessageType == RemoteDebuggerMessageType.Context || response.MessageType == RemoteDebuggerMessageType.Exception) { break; } var request = response.GetOrganizationRequest(); var service = response.UserId.HasValue ? localContext.GetService(response.UserId.Value) : localContext.AdminOrganizationService; var organizationResponse = service.Execute(request); message = new RemoteDebuggerMessage(RemoteDebuggerMessageType.Response, organizationResponse, remoteContext.Id); } if (response.MessageType == RemoteDebuggerMessageType.Exception) { throw response.GetException(); } var updatedContext = response.GetContext <RemoteDebugExecutionContext>(); localContext.UpdateContext(updatedContext); return(true); } catch (HttpRequestException) { // Run the plugin as deploy if the remote debugger is not connected } } } //} } return(false); }