Переопределение System.Exception сериализации - PullRequest
0 голосов
/ 08 января 2012

Я бы хотел пропустить сериализацию некоторых свойств класса Exception, таких как StackTrace и RemoteStackTrace (это необходимо для пользовательской обработки ошибок в контексте WCF). Как я могу это сделать? Я был бы рад установить их значения на null в GetObjectData(), но я не могу, потому что нижележащие поля являются личными (почему, черт возьми, они всегда делают их личными, а не защищенными?)

1 Ответ

0 голосов
/ 08 января 2012

К счастью, свойство Message является виртуальным, а другие, которые мне нужны, имеют общедоступные сеттеры, поэтому я могу просто отключить унаследованный (де) код сериализации:

[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 вдохновлена ​​этой замечательной статьей .Таким образом, вместо тривиальных классов простых ошибок мои ошибки получены из 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>, потому что вы можете организовать свои ошибки в виде иерархии и наслаждаться наследованием в перехватывающих блоках.FaultException<T> терпит неудачу здесь из-за дисперсии типа (in).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...