2011-02-03 67 views
1

我有一個簡單的IPC機制,使用WCF和命名管道。我的目標是將異常詳細信息(包括堆棧跟蹤)傳播到客戶端以進行日誌記錄(其餘應用程序日誌記錄位於客戶端上)。WCF FaultContract失敗NamedPipe

如果我使用下面的代碼,我能趕上在客戶端上的FaultException <異常>,看到異常的詳細信息:

合同:

[ServiceContract] 
public interface IService 
{ 
    [OperationContract] 
    [FaultContract(typeof(Exception))] 
    void DoSomething(); 
} 

實現:

public class Service : IService 
{ 
    public void DoSomething() 
    { 
     try 
     { 
      ThisWillThrowAnException(); 
     } 
     catch (Exception e) 
     { 
      throw new FaultException<Exception>(e); 
     } 
    } 
} 

客戶端:

public void CallServer() 
{ 
    try 
    { 
     proxy.DoSomething(); 
    } 
    catch (FaultException<Exception> e) 
    { 
     Console.WriteLine("Caught fault exception!"); 
    } 
} 

這工作正常,我看到消息打印在控制檯上。但是,如果我想使用自己的派生異常而不是基類Exception類,它將失敗。

自定義異常:

[Serializable] 
public class MyException : Exception 
{ 
    public MyException() { } 
    public MyException (string message) : base(message) { } 
    public MyException (string message, Exception inner) : base(message, inner) { } 
    protected MyException (
     SerializationInfo info, 
     StreamingContext context) 
     : base(info, context) { } 
} 

更改FaultContract上IService.DoSomething到

typeof(MyException). 

變化服務扔子句

new FaultException<MyException>(new MyException(e.Message, e); 

更改客戶端的catch子句到

catch (FaultException<MyException> e) 

當我執行此操作時,在客戶端上發生CommunicationException並出現以下錯誤: System.ServiceModel.CommunicationException:從管道讀取時發生錯誤:管道已結束。 (109,0x6d)。

MyException類位於共享庫中,可供客戶端和服務器使用。

這個問題與this question非常相似,但這並沒有幫助我。

回答

1

我通過編寫自己的錯誤DataContract包含一個序列化的StackFrames列表來解決這個問題。

顯然這個MSDN文章不完全準確?

http://msdn.microsoft.com/en-us/library/ff649840.aspx

[DataContract] 
public class MyFault 
{ 
    [DataMember] 
    public string Message { get; set; } 

    [DataMember] 
    public IList<SerializableMiniStackFrame> StackTrace { get; set; } 


    public static MyFault CreateFault(Exception e) 
    { 
     MyFault fault = new MyFault(); 
     fault.Message = e.Message; 
     fault.InitTrace(e); 
     return fault; 
    } 

    /// <summary> 
    /// Initializes the stack trace based on when the inner exception was thrown. 
    /// </summary> 
    /// <param name="inner">The inner exception.</param> 
    private void InitTrace(Exception inner) 
    { 
     StackTrace trace = new StackTrace(inner, true); 
     InitTrace(trace); 
    } 

    /// <summary> 
    /// Initializes the internal serializable stack frames based on the given 
    /// stack trace. 
    /// </summary> 
    /// <param name="stackTrace">The stack trace.</param> 
    private void InitTrace(StackTrace stackTrace) 
    { 
     // Create a new list of serializable frames. 
     this.StackTrace = new List<SerializableMiniStackFrame>(); 
     // Iterate over each frame in the stack trace. 
     foreach (StackFrame frame in stackTrace.GetFrames()) 
     { 
      string type = ""; 
      Type declaringType = frame.GetMethod().DeclaringType; 
      if (null != declaringType) 
      { 
       type = declaringType.FullName; 
      } 

      MethodBase method = frame.GetMethod(); 
      string methodName = method.Name; 
      string parameters = string.Empty; 
      string delimiter = string.Empty; 
      foreach (ParameterInfo parameter in method.GetParameters()) 
      { 
       parameters += string.Format("{0}{1} {2}", delimiter, parameter.ParameterType.Name, parameter.Name); 
       delimiter = ", "; 
      } 
      string file = Path.GetFileName(frame.GetFileName()); 
      int line = frame.GetFileLineNumber(); 

      // Create a serializable frame and add it to the list. 
      SerializableMiniStackFrame miniFrame = new SerializableMiniStackFrame(type, methodName, parameters, file, line); 
      this.StackTrace.Add(miniFrame); 
     } 
    } 
} 

/// <summary> 
/// This class encapsulates basic stack frame information into a serializable 
/// object. 
/// </summary> 
[DataContract] 
public class SerializableMiniStackFrame 
{ 
    public SerializableMiniStackFrame() { } 
    public SerializableMiniStackFrame(string type, string method, string parameters, string file, int line) 
    { 
     this.Type = type; 
     this.Method = method; 
     this.Parameters = parameters; 
     this.File = file; 
     this.Line = line; 
    } 

    [DataMember] 
    public string Type { get; set; } 
    [DataMember] 
    public string Method { get; set; } 
    [DataMember] 
    public string Parameters { get; set; } 
    [DataMember] 
    public string File { get; set; } 
    [DataMember] 
    public int Line { get; set; } 
}