WCF FaultContract与NamedPipe失败 [英] WCF FaultContract Fails with NamedPipe

查看:107
本文介绍了WCF FaultContract与NamedPipe失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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).

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

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

合同:

[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类,则它将失败.

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.

自定义例外:

[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更改为

Change the FaultContract on IService.DoSomething to

typeof(MyException).

将Service中的throw子句更改为

Change the throw clause in Service to

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

将客户端中的catch子句更改为

Change the catch clause in the client to

catch (FaultException<MyException> e)

执行此操作时,在客户端上捕获到CommunicationException,并显示错误: System.ServiceModel.CommunicationException:从管道读取错误:管道已结束. (109,0x6d).

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).

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

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.

推荐答案

我通过编写自己的故障DataContract来解决此问题,该故障包含一个StackFrames序列化列表.

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

此MSDN文章显然不完全正确吗?

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; }
}

这篇关于WCF FaultContract与NamedPipe失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆