Navigation

Search

Categories

 
 

On this page

Managing exceptions in WCF

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 21
This Year: 0
This Month: 0
This Week: 0
Comments: 29

Sign In
Pick a theme:

 Monday, April 30, 2007
Monday, April 30, 2007 12:33:08 PM (GMT Standard Time, UTC+00:00) ( WCF )

WCF uses SOAP fault objects to transmit exceptions from a service to a client and, in the duplex case, from a client to a service in an interoperable way. Inside this scope, there are two types of SOAP faults that can be sent, declared and undeclared SOAP faults.  Declared SOAP faults are those in which an operation has a System.ServiceModel.FaultContractAttribute that specifies a custom SOAP fault type.  Undeclared SOAP faults are those that are not specified in the contract for an operation.

This post shows the implementation of declared SOAP fault objects using both scenarios: one-way and duplex.

One-way scenario

This example shows a simple code that use a WCF service to publish a post.  To do it, one interface called IBlogs defines a CreatePost(string post) method and, to support declared SOAP faults, this method specifies the FaultContractAttribute to transmit BlogsFault exceptions.

[ServiceContract(Namespace="http://wcf.devdeo.com/excepciones")]
interface IBlogs
{
    [OperationContract]
    [FaultContract(typeof(BlogsFault))]
    void CrearPost(string post);
}

[DataContract(Namespace="http://schemas.devdeo.com/excepciones")]
class BlogsFault
{
    [DataMember]
    public string CustomError;

    public BlogsFault(string error)
    {
        CustomError = error;
    }
}

class BlogsService : IBlogs
{
    public void CreatePost(string post)
    {
        if (post == null || post.Length == 0)
        {
            Console.WriteLine("Error trying to read the post");
            throw new FaultException<BlogsFault>(new BlogsFault("The post was incorrect"));
        }
        Console.WriteLine(string.Format("The post: \"{0}\" was published", post));
    }
}

 

The client invokes the WCF service two times; the first time the client try to publish the post "First post", and the WCF service doesn't generate any error.  The second time the client try to publish an empty post, but at this time the WCF service generates an error and sent it as a SOAP fault object represented by the BlogsFault class.  At this time, the client capture the error using a try..catch... block with the FaultException<> class.

class Program
{
    static void Main(string[] args)
    {
        BlogsClient client = new BlogsClient();
        client.CreatePost("First post");

        try
        {
            client.CreatePost("");
        }
        catch (FaultException<BlogsFault> e)
        {
            Console.WriteLine(string.Format("Error: {0}", e.Detail.CustomError));
        }
    }
}

Duplex scenario

Now, to simulate a duplex scenario, the WCF service will need a confirmation from client before to publish the post.  In this case, a new interface called IBlogsCallback is implemented and specifyed as a CallbackContract property in the service.

If the client doesn't confirm the post, a BlogsFault exception is generated and sent to service as a SOAP fault object.

[ServiceContract(Namespace="http://wcf.devdeo.com/excepciones",CallbackContract=typeof(IBlogsCallback))]
interface IBlogs
{
    [OperationContract]
    [FaultContract(typeof(BlogsFault))]
    void CreatePost(string post);
}

interface IBlogsCallback
{
    [OperationContract]
    [FaultContract(typeof(BlogsFault))]
    void ConfirmPost(string post);
}

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]
class BlogsService : IBlogs
{
    public void CreatePost(string post)
    {        
        if (post == null || post.Length == 0)
        {
            Console.WriteLine("Error trying to read the post");
            throw new FaultException<BlogsFault>(new BlogsFault("The post was incorrect"));
        }

        try
        {
            Callback.ConfirmarPost(post);
        }
        catch(FaultException<BlogsFault> e)
        {
            Console.WriteLine(string.Format("The post: \"{0}\" cannot be published", e.Detail.CustomError));
            return;
        }

        Console.WriteLine(string.Format("The post: \"{0}\" was published", post));
    }

    public IBlogsCallback Callback
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel<IBlogsCallback>();
        }
    }
}

[DataContract(Namespace="http://schemas.devdeo.com/excepciones")]
class BlogsFault
{
    [DataMember]
    public string CustomError;

    public BlogsFault(string error)
    {
        CustomError = error;
    }
}

At last, the client must implement the ConfirmPost(string post) method to confirm the post.

public class Blogs : IBlogsCallback
{
    public void ConfirmPost(string post)
    {
        Console.WriteLine(string.Format("Do you really want publish the post: \"{0}\" ? Y/N", post));
        string result = Console.ReadLine();

        if (result == "N")
        {
            BlogsFault fault = new BlogsFault();
            fault.CustomError = "The user doesn't publish the post";
            throw new FaultException<BlogsFault>(fault);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Blogs confirm = new Blogs();
        InstanceContext ctx = new InstanceContext(confirm);
        BlogsClient client = new BlogsClient(ctx);
        client.CreatePost("First post");

        try
        {
            cliente.CreatePost("");
        }
        catch (FaultException<BlogsFault> e)
        {
            Console.WriteLine(string.Format("Error: {0}", e.Detail.CustomError));
        }
    }
}

 

NOTE: you can read the spanish version of this post at Manejando excepciones en WCF