【问题标题】:WCF Error Handling and accessing class objectsWCF 错误处理和访问类对象
【发布时间】:2012-03-09 01:49:26
【问题描述】:

我已经使用 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

我现在有错误的堆栈跟踪。但是我怎样才能访问用户和电话号码?虽然堆栈跟踪很有帮助,但对导致错误的基础数据的引用在错误报告系统中至关重要。

【问题讨论】:

    标签: .net wcf error-handling


    【解决方案1】:

    除非您希望错误处理程序了解每个操作中使用的每种类型,否则您应该依靠操作本身的异常处理来存储可能与故障排除相关的任何信息。特别是,该操作可能知道特定的嵌套类结构需要在向下钻取之前检查属性是否为 null,但我不想编写一个知道这一点的错误处理程序。

    在您要为其提供额外详细信息的每个操作周围放置一个 try/catch 块,然后引发自定义异常,包括详细信息,并将原始异常作为 InnerException 包含在内。

    【讨论】:

      【解决方案2】:

      我做了类似的事情,但我没有在IErrorHandler 扩展点中记录方法调用参数。相反,我最终实现了一个自定义 IOperationInvoker 并在那里处理参数日志记录。这是一个可能有用的代码 sn-p:

      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 实现来记录未处理的异常,我只是不从那里记录参数,而是从上面的代码中记录参数。

      希望这会有所帮助!

      【讨论】:

        【解决方案3】:

        您可以使用 AOP 工具来帮助记录错误,这将有助于减少在方法出错时必须编写以记录输入参数的样板代码。 Postsharp 运行良好,免费版可以满足您的需求。

        【讨论】:

        • 哇,这很容易!我刚刚添加了一个属性包装器,然后能够将 args.Instance 转换为我的底层数据类型。
        • 另外,当您创建 AOP 属性时,您可能需要考虑将 System.Diagnostics.DebuggerStepThrough 属性添加到类定义中。特别是如果您使用 AOP 记录方法的进入和退出。如果每次在 Visual Studio 中调试时都单步执行注入的 AOP 代码,那可能会很痛苦。
        【解决方案4】:

        你不能,除非你在方法中捕捉到异常,并用你想要记录的额外信息重新抛出一个自定义异常

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-09
          • 1970-01-01
          • 2012-02-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多