我已经使用IErrorHandler实现了一些基本的WCF错误处理,我可以在其中获取堆栈跟踪并记录它,但是我也想从类中记录导致异常的一些其他信息。
例如说我服务中有以下课程:
Class Foo
Public User As String
Public PhoneNumber As String
Public Function Bar() As Boolean
Dim c As Collection 'intentionally not set to an object to cause an error below
c.Add(PhoneNumber)
Return True
End Function
End Class
我抓错了:
Public Function HandleError(ByVal [error] As System.Exception) As Boolean Implements ystem.ServiceModel.Dispatcher.IErrorHandler.HandleError
'Log ex.tostring to event log
'How can I access User and PhoneNumber?
Return False
End Function
我现在有了错误的堆栈跟踪。但是如何才能访问User和PhoneNumber?虽然堆栈跟踪很有用,但在错误报告系统中引用导致错误的基础数据是最重要的。
答案 0 :(得分:4)
我做了类似的事情,但是我没有在IErrorHandler
扩展点中记录方法调用参数。相反,我最终实现了自定义IOperationInvoker
并在那里处理参数日志记录。这是一个可能有用的代码片段:
public class MyOperationBehavior : IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
// intentionally empty.
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
// intentionally empty.
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
// create a name for this operation for logging purposes.
string operationName;
if (operationDescription.SyncMethod != null)
operationName = operationDescription.SyncMethod.DeclaringType.FullName + "." + operationDescription.Name;
else if (operationDescription.BeginMethod != null)
operationName = operationDescription.BeginMethod.DeclaringType.FullName + "." + operationDescription.Name;
else operationName = operationDescription.Name;
dispatchOperation.Invoker = new MyOperationInvoker(operationName, dispatchOperation.Invoker);
}
public void Validate(OperationDescription operationDescription)
{
// intentionally empty.
}
}
public class MyOperationInvoker : IOperationInvoker
{
private readonly IOperationInvoker defaultInvoker;
private readonly string operationName;
public MyOperationInvoker(string operationName, IOperationInvoker defaultInvoker)
{
if(defaultInvoker == null)
throw new ArgumentException("DefaultInvoker can not be null.");
this.defaultInvoker = defaultInvoker;
this.operationName = operationName;
}
public object[] AllocateInputs()
{
return defaultInvoker.AllocateInputs();
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
Exception error = null;
DoMySuperAwesomePreProcessing(operationName, inputs);
try
{
return defaultInvoker.Invoke(instance, inputs, out outputs);
}
catch (Exception ex)
{
error = ex;
throw;
}
finally
{
DoMySuperAwesomePostProcessing(operationName, inputs, error);
}
}
public bool IsSynchronous
{
get { return defaultInvoker.IsSynchronous; }
}
所以基本上它通过defaultInvoker
调用它通常会发生的任何事情,但是在调用之前和之后,它有机会与实例,输入,输出和异常进行交互(如果抛出一个)。
在该后处理点,如果我发现错误,我最终会使用方法名称和所有输入参数以及所有记录的异常方法对其进行记录,因此我们可以尝试重现该问题使用相同的输入。
我做还有一个用于记录未处理异常的自定义IErrorHandler
实现,我只是不从那里记录参数,而是从上面的代码中记录参数。< / p>
希望这有帮助!
答案 1 :(得分:2)
您可以使用AOP工具来帮助记录错误,这有助于减少在方法出错时必须写入日志输入参数的样板代码。 Postsharp效果很好,免费版本可以满足您的需求。
答案 2 :(得分:1)
除非您在方法中捕获异常并使用要记录的额外信息重新抛出自定义异常,否则不能
答案 3 :(得分:0)
除非您希望错误处理程序理解每个操作中使用的每个类型,否则您应该依赖操作本身的异常处理来存储可能与故障排除相关的任何信息。特别是,操作可能知道特定的嵌套类结构需要在向下钻取之前检查null的属性,但我不想写一个知道这个的错误处理程序。
在每个要提供额外详细信息的操作周围放置一个try / catch块,然后抛出一个自定义异常,包括详细信息,并将原始异常包括为InnerException。