2
votes

I have written a custom exception object. The reason for this is I want to track additional information when an error occurs. My CLR object is defined as follows:

public class MyException : Exception
{
  public override string StackTrace
  {
    get { return base.StackTrace; }
  }
  private readonly string stackTrace;

  public override string Message
  {
    get { return base.Message; }
  }
  private readonly string message;

  public string Element
  {
    get { return element; }
  }
  private readonly string element;

  public string ErrorType
  {
    get { return errorType; }
  }
  private readonly string errorType;

  public string Misc
  {
    get { return misc; }
  }
  private readonly string misc;

  #endregion Properties

  #region Constructors

  public MyException() 
  {}

  public MyException(string message) : base(message)
  { }

  public MyException(string message, Exception inner) : base(message, inner)
  { }

  public MyException(string message, string stackTrace) : base()
  {
    this.message = message;
    this.stackTrace = stackTrace;
  }

  public MyException(string message, string stackTrace, string element, string errorType, string misc) : base()
  {
    this.message = message;
    this.stackTrace = stackTrace;
    this.element = element;
    this.errorType = errorType;
    this.misc = misc;
  }   

  protected MyException(SerializationInfo info, StreamingContext context) : base(info, context)
  {
    element = info.GetString("element");
    errorType = info.GetString("errorType");
    misc = info.GetString("misc");
  }

  public override void GetObjectData(SerializationInfo info, StreamingContext context)
  {
    base.GetObjectData(info, context);
    info.AddValue("element", element);
    info.AddValue("errorType", errorType);
    info.AddValue("misc", misc);
  }
}

I have created a copy of this custom xception in a WP7 application. The only difference is, I do not have the GetObjectData method defined or the constructor with SerializationInfo defined. If I run the application as is, I receive an error that says:

Type 'My.MyException' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute.

If I add the DataContract / DataMember attributes to the class and its appropriate members on the server-side, I receive an error that says: Type cannot be ISerializable and have DataContractAttribute attribute.

How do I serialize MyException so that I can pass an instance of it to my WCF service. Please note, I want to use my service from an Android app. Because of this, I don't want to do anything too Microsoft centric. That was my fear with DataContract / DataMember stuff.

Thank you so much for your help!

2

2 Answers

2
votes

You need to add [Serializable] to your custom class. This is what your first error is most likely telling you, that this thing needs to be serializable, although it's telling you to use the preferred WCF (use a DataContract) way.

You can't mix serialization interfaces (DataContract AND ISerializable), which is what the second error is telling you. Exception already implements ISerializable, and WCF will support that. It looks like from your code you've already added some of the methods for that as well (the ones with SerializationInfo).

Like Marc said, there is nothing too .NET centric about using DataContract stuff, it's just as platform independent when it comes to client side consumption.

0
votes

There isn't anythig terrible about DataMember etc; they translate nicely to standard SOAP concepts. But exceptions: less so. For pure WCF, you should consider faults rather than raw exceptions, but in the general case I would instead return (as my result from the operation) an object that optionally includes information about expected failures. Unexpected failures should be left at the server, and a generic "oops" result returned.

For example, you could simply have something like:

[DataContract]
public class FooResult {
    [DataMember]
    public string Error {get;set;}
    [DataMember]
    public SomeType Result {get;set;}
}

where the caller should expect an Error XOR a Result. Also note that without DataContract / DataMember attributes there is a chance that the serializer is acting as a field serializer, which is something you really don't want.