用于登录Dynamics CRM插件的生产的策略

cja*_*cja 6 dynamics-crm dynamics-crm-2011

CRM 2011在前提下.

我有一个用C#编写的插件.它可能会抛出异常或在生产中表现不佳.

当发生这种情况时,我想捕获有关状态和最近代码执行的信息,以帮助我分析问题.

理想情况下,我想要以下内容:

  1. 如果代码决定我应该知道一个问题,那么我希望它能够告诉我尽快出现问题,而我没有看到问题是否已经发生.

  2. 我希望能够轻松获取有关该问题的信息.我不想让RDP到另一台机器并搜索文件.

  3. 我不希望日志记录对性能产生太大影响.

我想我正在寻找这样的东西:

  • 在内存中保留最后n行日志.
  • 单个函数调用以向日志添加一行.
  • 单个函数调用导致记录错误.
  • 如果出现错误,请发邮件给我说有问题.这包含摘要信息.
  • 该电子邮件包含指向网页的链接,向我显示完整的错误详细信息.堆栈跟踪,错误消息,日期,时间,用户等,最后n行日志.
  • 如果还有一个网页显示我所有错误,过滤,排序等等,那就太好了.

我对CRM很新,但我以前开发过这样的系统.由于CRM已经存在多年,我希望它可以用于它.

Dar*_*ryl 6

为了支持您的愿望清单,我将创建这些实体:

PluginLog

  • 包含您希望为成功完成的插件调用保留的信息
  • 与插件异常类有关.这样您就可以查看异常发生之前发生的事情

PluginException

  • 包含有关异常的任何特殊信息(用户,上下文,堆栈跟踪)

现在让我们看看你的愿望清单:

  • 在内存中保留最后n行日志.
    • 不确定是否要记录特定的插件类,或者DLL中定义的所有插件类,我将假设一个特定的插件类:
    • 为插件创建一个静态ConcurrentQueue
  • 单个函数调用以向日志添加一行.
    • 创建一个在内存中创建PluginLog实体的函数(不在CRM数据库中创建它)并将其添加到队列中.
    • 如果它的长度> n,则出列队列.
  • 单个函数调用导致记录错误.
    • 同样,这是你需要创建的东西.基本上我会在CRM中创建一个PLuginException实体,然后将所有项目从队列中取出,填充插件异常ID,并将其保存到CRM
  • 如果出现错误,请发邮件给我说有问题.这包含摘要信息.
    • 只要执行插件的App Domain上下文具有所需的权限(不确定它是否在CRM Online中),这应该是微不足道的.
  • 该电子邮件包含指向网页的链接,向我显示完整的错误详细信息.堆栈跟踪,错误消息,日期,时间,用户等,最后n行日志.
    • 您可以创建指向已创建的PluginException实体的链接,并将其与所有其他相关信息一起包含在电子邮件中.
  • 如果还有一个网页显示我所有错误,过滤,排序等等,那就太好了.
    • 高级查找救援

编辑

为了帮助您入门,我正在使用这个来从插件上下文中检索所有信息,并将其转换为插入到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
Run Code Online (Sandbox Code Playgroud)