WCF 故障合约因 NamedPipe 失败

发布于 2024-10-15 21:30:00 字数 1860 浏览 2 评论 0原文

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

如果我使用以下代码,我可以捕获FaultException;在客户端上并查看异常详细信息:

Contract:

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

Implement:

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

Client:

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 类位于客户端和服务器均可使用的共享库中。

这个问题与

I have a simple IPC mechanism that uses WCF and named pipes. My goal is to propagate exception details (including the stacktrace) to the client for logging purposes (the rest of the application logging is located on the client).

If I use the following code I am able to catch FaultException<Exception> on the client and see exception details:

Contract:

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

Implementation:

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

Client:

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

This works fine and I see the message printed on the console. However, if I want to use my own derived exception instead of the base Exception class, it fails.

Custom 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) { }
}

Change the FaultContract on IService.DoSomething to

typeof(MyException).

Change the throw clause in Service to

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

Change the catch clause in the client to

catch (FaultException<MyException> e)

When I execute this, a CommunicationException is caught on the client with the error:
System.ServiceModel.CommunicationException: There was an error reading from the pipe: The pipe has been ended. (109, 0x6d).

The MyException class is in a shared library available to both the client and server.

This question is very similar to this question, but that did not help me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空‖城人不在 2024-10-22 21:30:00

我通过编写自己的错误 DataContract 解决了这个问题,其中包含 StackFrame 的序列化列表。

显然这篇 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; }
}

I resolved this by writing my own fault DataContract which contained a serialized list of StackFrames.

Apparently this MSDN article is not exactly accurate?

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; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文