24 June, 2008

WCF and Custom Exception Handling (custom exceptions), part 1

As this seems a rather popular topic, I’ve decided to rewrite this post in a more “reader friendly” format. Here goes…


I was really under the impression that WCF allowed "any" type to be used as FaultContract<T>, as long as the type was marked with the [Serializable]-attribute. Surprise-surprise - that is not the case!


If you do not want to declare a completely custom type using the [DataContract] attribute on your own class, but instead provide an Exception-derived type (which is quite common in .NET-.NET scenarios where no interoperability is required), you need to take into account a couple of things. In addition - the "exception based" programming model is more in sync with the general .NET paradigm and thereby easier to handle by a programmer.


First of all - the type to be used as <T> in the FaultContract<T>, is to inherit from CommunicationException (not System.Exception); or so the documentation says. In reality System.Exception will actually do, but better to stay current with the documentation. Next is the really important part - Provide a protected constructor allowing for the serialization process taking SerializationInfo and StreamingContext as arguments:

[Serializable]
public class MyCustomException : CommunicationException
{
public MyCustomException()
{ }

public MyCustomException(string msg) : base(msg)
{}

protected MyCustomException(SerializationInfo info, StreamingContext ctxt) : base(info, ctxt)
{}
}
SERVICE: When declaring a type like the above, it will be (re)thrown at the Client-side (by the proxy) correctly when declared in the ServiceContract like this using the FaultContract(type) as seen below:
/// <summary>
///
My service contract
/// </summary>
[ServiceContract(Namespace="UniqueString")]
public interface IMyService
{
/// <summary>
///
Prints the string.
/// </summary>
/// <param name="msg">
The MSG.</param>
[OperationContract]
[FaultContract(typeof(MyCustomException))]
void PrintString(string msg);
}

The service implementation throwing the exception (MyCustomException) looks like this:

public class MyService : IMyService
{
#region IMyService Members

public void PrintString(string msg)
{
if (string.IsNullOrEmpty(msg))
throw new FaultException<MyCustomException>(new MyCustomException("Input was null"));

//to stuff with input, otherwise...
}

#endregion
}

CLIENT: Throwing this exception-derived type in the service implementation will propagate to the Client just fine and can be caught like this in the client:

    void CallService()
{
try
{
proxy.PrintString(null);
}
catch (FaultException<MyCustomException>)
{
Console.WriteLine("The proper exception caught");
}
catch (CommunicationException)
{
Console.WriteLine("The INCORRECT exception caught");
}
}
}
2011.03.16: Update: To be able to convey your own custom data as well, see this post:
http://blog.clauskonrad.net/2011/03/how-to-wcf-and-custom-exception.html
Technorati Tags:

6 comments:

Anonymous said...

Thank you for the post, Claus; it helps.

Anonymous said...

Thank you so much for this very helpful and understandable post.

Anonymous said...

Thanks a lot man. It helped me.

Anonymous said...

thank you for the post, it helps a lot!
btw, if you inherit from Exception, it doesn't work. I have to say that i didn't implemented the protected constructor, but it didn't worked until the custom exception inherits from communicationException.

Anonymous said...

Perfect, thank you. Saved me a lot of time!

Blanes said...

Great post..I still have a problem. MyCustomException have a property named IDUser..after this exception is thrown in client, this property is reinitialized(with 0). How can I bring more info to the client(more than an Exception have)?