C# CRM插件:沙盒中的自定义异常
我有一个Dynamics CRM 2013插件正在沙箱中执行 此代码具有以下自定义异常类:C# CRM插件:沙盒中的自定义异常,c#,.net-4.0,dynamics-crm,.net-4.5,dynamics-crm-2013,C#,.net 4.0,Dynamics Crm,.net 4.5,Dynamics Crm 2013,我有一个Dynamics CRM 2013插件正在沙箱中执行 此代码具有以下自定义异常类: [Serializable] public class PluginValidationException : Exception { public PluginValidationException() { } protected PluginValidationException(SerializationInf
[Serializable]
public class PluginValidationException : Exception
{
public PluginValidationException()
{
}
protected PluginValidationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
public PluginValidationException(string message)
: base(message)
{
}
public PluginValidationException(string message, Exception inner)
: base(message, inner)
{
}
}
在插件中引发此异常时,将导致一个通用错误窗口,日志文件中没有详细信息:
未处理的异常:System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault,Microsoft.Xrm.Sdk,Version=6.0.0.0,Culture=neutral,PublicKeyToken=31bf3856ad364e35]:System.Runtime.Serialization.SerializationException:Microsoft Dynamics CRM遇到错误。管理员或支持人员的参考编号:#1355B4E4详细信息:
-2147220970
呼叫栈
在Microsoft.Crm.Application.Platform.ServiceCommands.PlatformCommand.XrmExecuteInternal()中
在Microsoft.Crm.Application.Platform.ServiceCommands.CreateCommand.Execute()中
在Microsoft.Crm.Application.Platform.EntityProxy.Create(布尔performDuplicateCheck,Guid auditingTransactionId)
在Microsoft.Crm.Application.Platform.EntityProxy.Create中(布尔performDuplicateCheck)
在Microsoft.Crm.Application.Platform.EntityProxy.CreateAndRetrieve(字符串[]列集,布尔performDuplicateCheck)中
位于Microsoft.Crm.Application.WebServices.InlineEdit.CommandBase.UpdateEntity(实体,布尔检索)
在Microsoft.Crm.Application.WebServices.InlineEdit.SaveCommand.ExecuteCommand(字符串命令XML)中
位于Microsoft.Crm.Application.WebServices.InlineEdit.CommandBase.Execute(字符串commandXml)
System.Runtime.Serialization.SerializationException:Microsoft Dynamics CRM遇到错误。管理员或支持的参考号:#1355B4E4
2014-04-06T02:04:30.0972001Z
[Demo.DemoPlugin:Demo.DemoPlugin.BasicCrmPlugin]
[d86b89ab-f1bc-e311-9408-000c29254b18:Demo.DemoPlugin.BasicCrmPlugin:Create of contact]
查看CRM跟踪日志可显示以下内容:
System.Runtime.Serialization.SerializationException:程序集“Demo.DemoPlugin,版本=1.0.0.0,区域性=中性,PublicKeyToken=FBB51BA1BA1E588D276”中的类型“Demo.Helpers.PlugInvalizationException”未标记为可序列化。
在Microsoft.Crm.Sandbox.SandboxAppDomainHelper.Execute(IServiceEndpointNotificationService serviceBusService、IOOrganizationServiceFactory organizationServiceFactory、String pluginTypeName、String pluginConfiguration、String PluginSecureConfiguration、IPluginExecutionContext requestContext)
在Microsoft.Crm.Sandbox.SandboxWorker.Execute(SandboxCallInfo callInfo、SandboxPluginExecutionContext requestContext、Guid pluginAssemblyId、Int32 sourceHash、String assemblyName、Guid pluginTypeId、String pluginTypeName、String pluginConfiguration、String PlugInsureConfig、SandboxRequestCounter和workerCounter)
根据一些阅读资料,我不认为这是一个bug,而是因为自定义异常类在.NET4(我使用的是.NET4.5)中不受信任
有人知道如何创建一个自定义的异常类来处理CRM沙箱吗。我正在使用自定义异常类,因为我捕获错误,需要区分InvalidPluginExecutionException
和由于插件注册不正确而导致的异常
于2014年4月8日更新
以下是捕获异常的插件中的代码,对于将其放在Stackoverflow上进行了显著简化:
try
{
//TODO: Prevalidation Logic
ValidatePluginExecution(crmContext, logging, out keyName);
//TODO: Postvalidation Logic
}
catch (PluginValidationException ex)
{
//TODO: Specific logging for Plugin Validation Exception
throw new InvalidPluginExecutionException("Did Not Validate");
}
catch (InvalidPluginExecutionException ex)
{
logging.Write("InvalidPluginExectionException at Plugin Validation");
throw;
}
catch (Exception ex)
{
logging.Write("Unhandled Exeception During Plugin Validation Operation");
logging.Write(ex);
throw new InvalidPluginExecutionException("Error. Download Log and submit to the Help Desk.", ex);
}
我不认为你想要什么是可能的,如果你想要在错误对话框中显示消息,你必须抛出InvalidPluginExecutionException
对于同步插件,可以选择显示自定义错误
在web应用程序的错误对话框中通过
插件引发InvalidPlugineExecutionException异常,异常为
自定义消息字符串作为异常消息属性值
建议插件只通过
InvalidPlugineExecutionException返回平台
作为一方,我不会费心检查插件本身的注册情况,这种情况在2013年没有多大意义。回到CRM 4,插件必须手动注册,这有一定的道理。现在我们有了解决方案,正确的注册是一项开发和测试任务,而不是运行时检查。经过一些额外的测试后,我能够确定:
显然,只有显式地访问堆栈跟踪才能访问异常。当从沙盒插件抛出异常时,只要该异常是CRM平台“知道”的异常(不确定它在做什么,但我猜它正在查看异常的类型,并以不同的方式处理不同的类型),则不会显示异常的堆栈跟踪。如果类型未知,则会导致CRM尝试序列化异常,这在中是不允许的,因为它使用反射(为什么必须序列化,不确定)
下面是一个示例插件,其中有些示例有效,有些则无效:
public class TestPlugin: IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
try
{
OtherMethod();
}
catch (Exception ex)
{
var trace = (ITracingService)serviceProvider.GetService(typeof (ITracingService));
trace.Trace("Throwing Plugin");
// Doesn't work
throw new InvalidPluginExecutionException("Error ", ex);
}
}
// Works:
//public void Execute(IServiceProvider serviceProvider)
//{
//try
//{
//OtherMethod();
//}
//catch (Exception ex)
//{
//var trace = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
//trace.Trace("Throwing Plugin");
//throw new InvalidPluginExecutionException("Error " + ex);
//}
//}
// Doesn't Work:
//public void Execute(IServiceProvider serviceProvider)
//{
// try
// {
// OtherMethod();
// }
// catch (Exception ex)
// {
// throw;
// }
//}
// Doesn't Work:
//public void Execute(IServiceProvider serviceProvider)
//{
// try
// {
// OtherMethod();
// }
// catch (Exception ex)
// {
// throw new InvalidPluginExecutionException("Error", ex);
// }
//}
public void OtherMethod()
{
throw new MyException();
}
}
public class MyException : Exception
{
}
为了回答您的问题:我编写了一个异常处理程序,以便能够遍历内部异常并确定抛出的异常是否有效:
/// <summary>
/// Exception Handler For Exceptions when executing in Sandbox Isolation Mode
/// </summary>
public class ExceptionHandler
{
/// <summary>
/// Determines whether the given exception can be thrown in sandbox mode.
/// Throws a Safe if it can't
/// </summary>
/// <param name="ex">The ex.</param>
/// <returns></returns>
/// <exception cref="InvalidPluginExecutionException"></exception>
/// <exception cref="Exception"></exception>
public static bool CanThrow(Exception ex)
{
var exceptionRootTypeIsValid = IsValidToBeThrown(ex);
var canThrow = exceptionRootTypeIsValid;
var innerException = ex.InnerException;
// While the Exception Types are still valid to be thrown, loop through all inner exceptions, checking for validity
while (canThrow && innerException != null)
{
if (IsValidToBeThrown(ex))
{
innerException = innerException.InnerException;
}
else
{
canThrow = false;
}
}
if (canThrow)
{
return true;
}
var exceptionMessage = ex.Message +
(ex.InnerException == null
? string.Empty
: " Inner Exception: " + ex.InnerException.ToStringWithCallStack());
// ReSharper disable once InvertIf - I like it better this way
if (exceptionRootTypeIsValid)
{
// Attempt to throw the exact Exception Type, with the
var ctor = ex.GetType().GetConstructor(new[] { typeof(string) });
if (ctor != null)
{
throw (Exception) ctor.Invoke(new object[] { exceptionMessage });
}
}
throw new Exception(exceptionMessage);
}
/// <summary>
/// Determines whether the specified ex is valid to be thrown.
/// Current best guess is that it is not
/// </summary>
/// <param name="ex">The ex.</param>
/// <returns></returns>
private static bool IsValidToBeThrown(Exception ex)
{
var assembly = ex.GetType().Assembly.FullName.ToLower();
return assembly.StartsWith("mscorlib,") || assembly.StartsWith("microsoft.xrm.sdk,");
}
}
我相信这是一个实际的错误,我已经打开了与微软的支持票,我们将看看他们是否同意
更新强>
我和微软一起创建了一张罚单:(不确定这些数字是什么意思,但它们都在主题中,希望将来对某人有益:REG:115122213520585 SRXCAP:1318824373ID)。他们确认CRM中不支持沙盒插件的自定义异常
请向上投票,让Microsoft修复此问题,或者至少更好地处理它 我不希望在错误对话框中显示消息,我希望自定义异常,这样我可以捕获它并处理它-如果它返回到平台,代码将抛出InvalidPlugineExecutionException
catch (InvalidPluginExecutionException ex)
{
context.LogException(ex);
// This error is already being thrown from the plugin, just throw
if (context.PluginExecutionContext.IsolationMode == (int) IsolationMode.Sandbox)
{
if (Sandbox.ExceptionHandler.CanThrow(ex))
{
throw;
}
}
else
{
throw;
}
}
catch (Exception ex)
{
// Unexpected Exception occurred, log exception then wrap and throw new exception
context.LogException(ex);
ex = new InvalidPluginExecutionException(ex.Message, ex);
if (context.PluginExecutionContext.IsolationMode == (int)IsolationMode.Sandbox)
{
if (Sandbox.ExceptionHandler.CanThrow(ex))
{
// ReSharper disable once PossibleIntendedRethrow - Wrap the exception in an InvalidPluginExecutionException
throw ex;
}
}
else
{
// ReSharper disable once PossibleIntendedRethrow - Wrap the exception in an InvalidPluginExecutionException
throw ex;
}
}