Production Enrollment Strategy for Dynamics CRM Plugin

CRM 2011 on delivery.

I have a plugin written in C #. This may cause exceptions or otherwise behave badly in production.

When this happens, I want to get information about the status and recent code execution to help me analyze the problem.

Ideally, I would like to:

  • If the code decides what I need to know about the problem, I want it to be able to tell me that there was a problem as soon as possible, without me, to see if the problem occurred.

  • I want information about the problem to be easily accessible to me. I do not want to have RDP on another machine and search for files.

  • I do not want registration to affect performance.

I think I'm looking for something like this:

  • Save the last n lines of the log in memory.
  • One function call to add a line to the log.
  • Calling one function to trigger an error record.
  • When there is a mistake, write to me saying that there is a problem. This contains summary information.
  • The email contains a link to a web page with full error information. Stack trace, error message, date, time, user, etc., Last n lines of the log.
  • It would be nice if there was a web page where all errors were shown, with filtering, sorting, etc.

I am new to CRM, but I used to develop such systems. Since CRM has been around for many years, I expect it to be available to it.

+6
source share
2 answers

To support your wish list, I would create the following objects:

Pluginlog

  • Contains the information you would like to save for successful plugin completions
  • Associated with the Plugin exception class. So you can see what happened before an exception occurred

PluginException

  • Contains any special exception information (user, context, stack trace)

Now open your wish list:

  • Save the last n lines of the log in memory.
    • Not sure if you want to register a specific plugin class or all plugin classes defined in a DLL, I will take a specific plugin class:
    • Create a static ConcurrentQueue for the plugin
  • Calling one function to add a line to the log.
    • Create a single function that creates a PluginLog object in memory (without creating it in the CRM database) and adds it to the queue.
    • If length> n, dequeue.
  • Calling one function to trigger an error record.
    • Again, this is what you need to create. Basically, I create a PLuginException object in CRM, and then remove all the elements from the queue, populating the plugin exception identifier and saving it in CRM.
  • When there is a mistake, write to me saying that there is a problem. This contains summary information.
    • As long as the domain application context for the executable plugin has the necessary rights (not sure if it works in CRM Online), this should be trivial.
  • The email contains a link to a web page with full error information. Stack trace, error message, date, time, user, etc., Last n lines of the log.
    • You can create a link to the created PluginException object and include it in the email along with all other relevant information.
  • It would be nice if there was a web page where all errors were shown, with filtering, sorting, etc.
    • Advanced Help Search

Edit

To help you get started, this is what I am currently using to extract all the information from the context of the plugin and convert it to text that is inserted into the exception:

#region GetPluginInfo private Exception GetPluginExecutionInfoForLog(IServiceProvider serviceProvider, Exception ex) { if(ex.GetType() == typeof(InvalidPluginExecutionException)){ return ex; } try { var context = serviceProvider.GetContext(); ex = new InvalidPluginExecutionException( String.Format("Error During Plugin Execution: {0}**** Context Values ****{0}{1}", Environment.NewLine, GetPluginExecutionInfo(context)), ex); } catch (Exception childEx) { OnError(childEx); } return ex; } protected String GetPluginExecutionInfo(IPluginExecutionContext context) { var lines = new List<String>(); var target = GetTarget<Entity>(context); lines.Add("MessageName: " + context.MessageName); lines.Add("PrimaryEntityName: " + context.PrimaryEntityName); lines.Add("PrimaryEntityId: " + context.PrimaryEntityId); lines.Add("BusinessUnitId: " + context.BusinessUnitId); lines.Add("CorrelationId: " + context.CorrelationId); lines.Add("Depth: " + context.Depth); lines.Add("Has Parent Context: " + (context.ParentContext != null)); lines.Add("InitiatingUserId: " + context.InitiatingUserId); AddParameters(lines, context.InputParameters, "Input Parameters"); lines.Add("IsInTransaction: " + context.IsInTransaction); lines.Add("IsolationMode: " + context.IsolationMode); lines.Add("Mode: " + context.Mode); lines.Add("OperationCreatedOn: " + context.OperationCreatedOn); lines.Add("OperationId: " + context.OperationId); lines.Add("Organization: " + context.OrganizationName + "(" + context.OrganizationId + ")"); AddParameters(lines, context.OutputParameters, "Output Parameters"); AddEntityReference(lines, context.OwningExtension, "OwningExtension"); AddEntityImages(lines, context.PostEntityImages, "Post Entity Images"); AddEntityImages(lines, context.PreEntityImages, "Pre Entity Images"); lines.Add("SecondaryEntityName: " + context.SecondaryEntityName); AddParameters(lines, context.SharedVariables, "Shared Variables"); lines.Add("Stage: " + context.Stage); lines.Add("UserId: " + context.UserId); if (target == null || target.Attributes.Count == 0) { lines.Add("Target: Empty "); } else { lines.Add("* Target " + target.ToEntityReference().GetNameId() + " *"); foreach (var att in target.Attributes) { lines.Add(" Entity[" + att.Key + "]: " + GetAttributeValue(att.Value)); } } lines.Add("* App Config Values *"); foreach (var key in ConfigurationManager.AppSettings.AllKeys) { lines.Add(" [" + key + "]: " + ConfigurationManager.AppSettings[key]); } return String.Join(Environment.NewLine, lines); } private static string GetAttributeValue(object value) { if(value == null){ return "Null"; } var type = value.GetType(); if (type == typeof(OptionSetValue)) { return ((OptionSetValue)value).Value.ToString(); } else if (type == typeof(EntityReference)) { return ((EntityReference)value).GetNameId(); } else { return value.ToString(); } } private static void AddEntityReference(List<string> nameValuePairs, EntityReference entity, string name) { if (entity != null) { nameValuePairs.Add(name + ": " + entity.GetNameId()); } } private static void AddEntityImages(List<string> nameValuePairs, EntityImageCollection images, string name) { if (images != null && images.Count > 0) { nameValuePairs.Add("** " + name + " **"); foreach (var image in images) { if (image.Value == null || image.Value.Attributes.Count == 0) { nameValuePairs.Add(" Image[" + image.Key + "] " + image.Value.ToEntityReference().GetNameId() + ": Empty"); } else { nameValuePairs.Add("* Image[" + image.Key + "] " + image.Value.ToEntityReference().GetNameId() + " *"); foreach (var att in image.Value.Attributes) { nameValuePairs.Add(" Entity[" + att.Key + "]: " + GetAttributeValue(att.Value)); } } } } else { nameValuePairs.Add(name + ": Empty"); } } private static void AddParameters(List<string> nameValuePairs, ParameterCollection parameters, string name) { if (parameters != null && parameters.Count > 0) { nameValuePairs.Add("* " + name + " *"); foreach (var param in parameters) { nameValuePairs.Add(" Param[" + param.Key + "]: " + param.Value); } } else { nameValuePairs.Add(name + ": Empty"); } } #endregion // GetPluginInfo 
+6
source

I found a very quick way to do this at http://mscrmtech.com/mscrm-2011-useful-itracingservice-addiion-when-creating-plugin-assemblies/

Documented here (only here): http://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.itracingservice.aspx

So what can i do

  public void Execute(IServiceProvider serviceProvider) { ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); if (tracingService == null) throw new InvalidPluginExecutionException("Failed to retrieve the tracing service."); tracingService.Trace("CRMSTClasses.Main_Code.Execute - testing tracing"); throw new InvalidPluginExecutionException("Test exception"); 

And then the log file that I can load from the error dialog includes:

 [CRMSTClasses: CRMSTClasses.Main_Code.Receiver] [cb42fcb0-0717-e311-9097-0050569274a2: CRMSTClasses.Main_Code.Receiver: Create of incident] CRMSTClasses.Main_Code.Execute - testing tracing 
0
source

Source: https://habr.com/ru/post/954768/


All Articles