这是我观察的内容
我需要从服务向客户端抛出自定义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中传播自定义异常子类型字段的正确方法是什么?
答案 0 :(得分:2)
...您不能在类型上同时拥有Serializable和DataContract。 (已确认:抛出运行时异常)
首先,您可以将DataContract
和Serializable
放在一起。事实上,没有这个,我现在正在处理的网站将无法工作,因为我的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
}
}
现在它按预期工作;现场数据完好无损。
这提出了另一个问题:为什么代理生成步骤不会自动执行此操作?