【问题标题】:WCF FaultContract Fails with NamedPipeWCF 故障合同因命名管道而失败
【发布时间】:2011-02-03 16:25:11
【问题描述】:

我有一个使用 WCF 和命名管道的简单 IPC 机制。我的目标是将异常详细信息(包括堆栈跟踪)传播到客户端以进行日志记录(应用程序日志记录的其余部分位于客户端上)。

如果我使用以下代码,我可以在客户端捕获 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) { }
}

将 IService.DoSomething 上的 FaultContract 更改为

typeof(MyException).

将Service中的throw子句改为

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

将客户端中的catch子句改为

catch (FaultException<MyException> e)

当我执行此操作时,客户端会捕获一个 CommunicationException 并出现错误: System.ServiceModel.CommunicationException:从管道读取错误:管道已结束。 (109, 0x6d)。

MyException 类位于客户端和服务器均可使用的共享库中。

这个问题与this question 非常相似,但这对我没有帮助。

【问题讨论】:

    标签: wcf stack-trace named-pipes faultexception


    【解决方案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; }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-08-05
      • 2020-09-17
      • 1970-01-01
      • 2010-11-30
      • 2011-10-14
      • 2021-07-04
      • 1970-01-01
      • 1970-01-01
      • 2023-01-19
      相关资源
      最近更新 更多