如何通过WCF将自定义异常的字段从服务传播到客户端?

时间:2012-07-18 12:56:41

标签: wcf

这是我观察的内容

我需要从服务向客户端抛出自定义Exception子类型。 (在特定操作中列为FaultContract)。我在CustomException上有一些字段,应该由客户端接收。

[Serializable]
class MyCustomException : Exception
{
    public string From { get; private set; }

    public MyCustomException(string where)
    {
        From = where;
    }

}

}

我发现即使在FaultException实例中存在异常,该字段也不会被反序列化。我尝试通过重写GetObjectData和序列化ctor来实现ISerializable,但没有骰子。 我能解决的唯一方法是将MyCustomException更改为DataContract,而不是从Exception派生。

[DataContract]
class MyCustomException
{
    [DataMember]
    public string From { get; private set; }

    public MyCustomException(string where)
    {
        From = where;
    }
}

这很有效。但是它不能再从Exception派生..因为Exception用Serializable属性标记,并且你不能在类型上同时使用Serializable和DataContract。 (已确认:抛出运行时异常)

所以我的问题是:在WCF中传播自定义异常子类型字段的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

  

...您不能在类型上同时拥有Seri​​alizable和DataContract。   (已确认:抛出运行时异常)

首先,您可以将DataContractSerializable放在一起。事实上,没有这个,我现在正在处理的网站将无法工作,因为我的WCF服务是通过$.ajax在网上消费的。 This SO主题将为您提供正式的详细信息。

接下来,我强​​烈建议您不要从Exception继承自定义错误。原因是您已经有FaultException<TDetail>内置类,其中TDetail是您的自定义错误。您可以阅读this MSDN文章了解实施细节 - 请记住在部署时关闭客户端的“异常详细信息”。

catch (FaultException<MyFault> e)
{
    //e is the full exception (with StackTrace et al.) when 'exception details' is on
    //e.Detail is your custom fault which is always available
}

答案 1 :(得分:1)

以下是我如何使用它...不确定它是否正确。 我找不到任何明确的指导原则,说明你不应该在FaultException<TDetail>中使用Exception子类型作为TDetail参数。

我尝试抛出一个FaultException<FileNotFoundException>,发现文件名字段实际上是正确传播的。

那么FileNotFoundException和MyCustomException之间的差异是什么?

由于基本异常实现了ISerializable,我不得不覆盖服务器端的方法

    protected MyCustomException(SerializationInfo info, StreamingContext context) :
        base(info, context)
    {
        this.From = info.GetString("From");
    }
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue("From", this.From);
    }

然后我使用svcutil生成客户端代理类。我发现没有生成FileNotFoundException(因为它是内置类型)但MyCustomException是。但它没有任何字段,只有一个空的反序列化ctor。

我之前没有深入研究ISerializable,因为当我在代理类ctor中设置断点时,它没有被击中。我错误地中止了那条调查线(无法在类上看到DebuggerStepThrough属性和GeneratedCode属性;由svcutil添加)。

然后我手动编辑自动生成的类以添加字段并将其设置在ctor中,如此...

[System.SerializableAttribute()]
    public partial class MyCustomException : System.Exception
    {
        public string From { get; private set; } // manual edit

        public MyCustomException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) :
            base(info, context)
        {
             this.From = info.GetString("From");  // manual edit
        }
    }

现在它按预期工作;现场数据完好无损。

这提出了另一个问题:为什么代理生成步骤不会自动执行此操作?