为了支持您的愿望清单,我将创建这些实体:
插件日志
- 包含您希望为成功完成的插件调用保留的任何信息
- 与插件异常类有关。这样您就可以查看发生异常之前发生的情况
插件异常
- 包含有关异常的任何特殊信息(用户、上下文、堆栈跟踪)
现在让我们来看看你的愿望清单:
- 在内存中保留最后 n 行日志。
- 不确定是否要记录特定的插件类,或 DLL 中定义的所有插件类,我将假设一个特定的插件类:
- 为插件创建一个静态 ConcurrentQueue
- 向日志中添加一行的单个函数调用。
- 创建一个函数,在内存中创建一个 PluginLog 实体(而不在 CRM 数据库中创建它)并将其添加到队列中。
- 如果它的长度> n,则出队。
- 导致记录错误的单个函数调用。
- 同样,这是您需要创建的东西。基本上我会在 CRM 中创建一个 PLuginException 实体,然后将所有项目从队列中取出,填充插件异常 ID,并将其保存到 CRM
- 当出现错误时,给我发电子邮件说有问题。这包含摘要信息。
- 只要执行插件的应用程序域上下文具有所需的权限(不确定它是否在 CRM Online 中),这应该是微不足道的。
- 该电子邮件包含一个指向网页的链接,该链接向我显示了完整的错误详细信息。堆栈跟踪、错误消息、日期、时间、用户等,最后 n 行日志。
- 您可以创建指向已创建 PluginException 实体的链接,并将其与所有其他相关信息一起包含在电子邮件中。
- 如果某个地方也有一个网页向我显示所有错误,包括过滤、排序等,那就太好了。
编辑
为了帮助您入门,这是我目前用来从插件上下文中检索所有信息,并将其转换为插入到异常中的文本的方法:
#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