Quantcast
Channel: .Net
Viewing all articles
Browse latest Browse all 10

Exception across App Domains

$
0
0

Recently I had a very strange exception and took me some time to figure out what was the problem. So lets imagine that I want to execute a piece of code in a different app domain, lets call it “NewDomain”, and that NewDomain throws a custom exception “MyException”.

The code of MyException is this:

[Serializable]public class MyException : ApplicationException{public MyException()
        : base()
    {
    }public MyException(string message)
        : base(message)
    {
        myCustomMessage = "Dear user you got an exception: " + message;
    }public MyException(string message, Exception innerException)
        :base(message, innerException)
    {
        myCustomMessage = "Dear user you got an exception: " + message;
    }public override string Message
    {get{return myCustomMessage;
        }
    }private string myCustomMessage;
}

 

If this exception is thrown across app domains you will get this nice exception:

The constructor to deserialize an object of type 'MyException’ was not found.

Server stack trace:

   at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)

   at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)

   at System.Runtime.Serialization.ObjectManager.DoFixups()

   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)

   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)

   at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeObject(MemoryStream stm)

   at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeMessageParts(MemoryStream stm)

   at System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage.FixupForNewAppDomain()

   at System.Runtime.Remoting.Channels.CrossAppDomainSink.SyncProcessMessage(IMessage reqMsg)

I didn’t know what the problem was at the beginning, because my class was marked with the attribute Serializable so what was the real problem???

The problem happens because I was transmitting the exception object across a stream. And across streams mark the class as Serializable is not enough.

So the solution is actually simple.

  1. I need to add a protected constructor with the following signature
    1. protected MyException(SerializationInfo info, StreamingContext context)
  2. My MyException class needs to implement ISerializable, the class System.Exception already implements it
  3. I need to implement the method
    1. GetObjectData(SerializationInfo info, StreamingContext context)
  4. Attribute the method with the following attribute
    1. [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]

 

I need all of this because the constructor is called during deserialization to reconstitute the exception object transmitted over a stream, and I need the method GetObjectData because I need to serialize my fields.

 

So, MyException class will lock like this:

[Serializable]public class MyException : ApplicationException{public MyException()
        : base()
    {
    }public MyException(string message)
        : base(message)
    {
        myCustomMessage = "Dear user you got an exception: " + message;
    }public MyException(string message, Exception innerException)
        :base(message, innerException)
    {
        myCustomMessage = "Dear user you got an exception: " + message;
    }protected MyException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        myCustomMessage = info.GetString("myCustomMessage");
    }

    [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("myCustomMessage", myCustomMessage);base.GetObjectData(info, context);
    }public override string Message
    {get{return myCustomMessage;
        }
    }private string myCustomMessage;
}

Like I wrote I just had to implement a constructor  to deserialize my fields  and a method to serialize them.


Viewing all articles
Browse latest Browse all 10

Latest Images

Trending Articles





Latest Images