Honestly, I'm sick and tired of having to debug weird SerializationExceptions because an instance of a poorly written exception class crossed an AppDomain boundary. I could understand it if it was an exception class that really was impossible to serialize, but the reality is this is caused mainly by lazyness on the developer's part.
Tip #1: Exceptions are not serializable by default. If you create a custom exception class, it is your responsability to ensure it is serializable.
Tip #2: Marking an exception class with [Serializable] is not enough. System.Exception implements ISerializable, so it forces you to do so as well.
Here's what you should keep in mind when writing an exception class:
- Mark the exception type with the [Serializable] attribute.
- Add an empty protected serialization constructor that simply delegates to the base class:
protected MyException(SerializationInfo info, StreamingContext ctxt) : base(info, ctxt)
For most exception classes, this will be enough, since most don't actually add new properties and simply rely on the message.
However, if your custom exception class has custom properties, then it MUST override ISerializable.GetObjectData() (and don't forget to call the base one), and you MUST unpack those properties in your serialization constructor.
It's not just about remoting!
What many people seem to forget is that serialization happens in a lot of places without them knowing it. The underlying remoting and serialization mechanisms in .NET (and I don't mean remote object invokation) are the basis for all cross AppDomain calls, even when they are inside the same process boundary.
More and more we see applications and environments where multiple AppDomains are the norm, rather than the exception: VSTO, MMC 3.0, BizTalk, ASP.NET and averything in between (including anything with COM interop in it). And this will grow in the future because using multiple AppDomains is the preffered way of hosting plugins safely and even applications will support extensibility in this fashion in the future.
In each of those cases there's the possibility that your exception might cross an AppDomain boundary, so please make sure it does so gracefully. If you're a library writer (open source or commercial), be aware that the chance that a user might use your library in one of those contexts is always there, so make sure it is a good citizen.