重写System.Exception序列化

时间:2012-01-08 12:02:16

标签: .net exception serialization

我想跳过Exception类的一些属性的序列化,例如StackTraceRemoteStackTrace(在WCF的上下文中需要这个用于自定义错误处理)。我怎样才能做到这一点?我很乐意在null中将其值设置为GetObjectData(),但我不能,因为底层字段是私有的(为什么他们总是将它们设为私有而不是保护?)

1 个答案:

答案 0 :(得分:0)

幸运的是,Message属性是虚拟的,其他我需要公共设置器,所以我只能禁用继承(de)序列化代码:

[Serializable]
public abstract class MyErrorBase : Exception
{
    protected string reason;

    public string TrackingID { get; set; }

    public override string Message
    {
        get { return reason; }
    }

    public MyErrorBase() : this(null) { }

    public MyErrorBase(string reason) : base(reason)
    {
        this.reason = reason;
        // other init logic
    }

    protected MyErrorBase(SerializationInfo info, StreamingContext context)
    {
        HelpLink = info.GetString("HelpLink");
        Source = info.GetString("Source");
        TrackingID = info.GetString("TrackingID");
        reason = info.GetString("Reason");
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Reason", reason);
        info.AddValue("TrackingID", TrackingID);
        info.AddValue("Source", Source);
        info.AddValue("HelpLink", HelpLink);
    }


}

令人惊讶的是,在重新抛出反序列化的实例时,禁用继承的逻辑对于CLR来说看起来非常好。

对于那些有兴趣为什么我需要这个。我的自定义WCF错误处理受到了这个令人敬畏的article的启发。因此,我的错误来自MyErrorBase而不是琐碎的普通错误类,而我的操作合同看起来像这样:

[OperationContract]
[FaultContract(typeof(InvalidState))]   
void Action();

InvalidState继承自MyErrorBase的地方。这样做很好,因为Exception标有[Serializable] - 这对DataContractSerializer来说已经足够了。但是,您不希望通过服务调用公开任何类似堆栈跟踪的详细信息,是吗?

生成的信封(现在)如下所示:

  <s:Fault>
     <faultcode>s:InvalidState</faultcode>
     <faultstring xml:lang="en-US">Cannot be processed in its current state.</faultstring>
     <detail>
        <InvalidState xmlns="http://schemas.datacontract.org/2004/07/MyNS" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema">
           <Reason i:type="x:string" xmlns="">Cannot be processed in its current state.</Reason>
           <TrackingID i:type="x:string" xmlns="">50547779-06d4-470d-ae75-a9feb3e08a99</TrackingID>
           <Source i:type="x:string" xmlns="app1"/>
           <HelpLink i:type="x:string" xmlns="">blabla</HelpLink>
           <State i:type="x:int" xmlns="">2</State>
        </InvalidState>
     </detail>
  </s:Fault>

最大的好处是非.NET消费者仍然很好(完全SOAP兼容性,我们不公开敏感数据),但服务的.NET使用者现在可以将错误提取为.NET异常并重新抛出它客户端(或处理故障通常的方式)。这比处理FaultException<T>要好得多,因为您可以将故障组织为层次结构并享受catch块中的继承。由于类型(in)方差,FaultException<T>在这里失败。