如何通过WCF将自定义异常的字段从服务分配给客户端



以下是我观察到的

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

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

}

我发现即使FaultException实例中存在异常,字段也没有被反序列化。我尝试通过重写GetObjectData和序列化构造函数来实现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中提出自定义异常子类型的字段的正确方法是什么?

不能在一个类型上同时具有Serializable和DataContract。(已确认:引发运行时异常)

首先,您可以将DataContractSerializable放在一起。事实上,如果没有这一点,我现在工作的网站将无法工作,因为我的WCF服务是通过$.ajax在网络上使用的。此SO线程将为您提供正式的详细信息。

接下来,我强烈建议不要从Exception继承您的自定义错误。原因是您已经有FaultException<TDetail>内置类,其中TDetail是您的自定义错误。您可以阅读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
}

以下是我如何使其工作的。。不确定这是否是正确的方式。我找不到任何明确的指导原则,说明您不应该在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。但是它没有任何字段,只有一个空的反序列化构造函数。

我之前没有深入研究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
        }
    }

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

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

最新更新