Navigation

Search

Categories

 
 

On this page

How to change the IncludeExceptionDetailInFaults property value
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:

 Friday, May 04, 2007
Friday, May 04, 2007 3:20:34 PM (GMT Standard Time, UTC+00:00) ( WCF )

In WCF service, one service can send managed exception information in the detail SOAP faults from service to client using the IncludeExceptionDetailInFaults property.  By default its value is false, but you can chage it; in this post I'll show the possible ways to change this value using different techniques.

Using config file

This is the most common way, to do it you must specify in the config file of the WCF service the includeExceptionDetailFaults attribute to true.  With this action every endpoint associated to WCF service will send managed exception information. 

<system.serviceModel>
    <services>
        <service name="devdeo.WCF.DebugService"
                         behaviorConfiguration="DebugServiceConfiguration">
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="DebugServiceConfiguration">
                <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

Using code

One way is setting the IncludeExceptionDatailInFaults property to true using the ServiceBehaviorAttribute. 

[ServiceContract(Namespace="http://wcf.devdeo.com/debug/")]
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class DebugService
{ }

Also, you can get the behaviors associated to WCF service using the Behaviors property and search the behavior that is related with the ServiceDebugBehavior object and set its property to true.

[ServiceContract(Namespace=http://wcf.devdeo.com/debug/)] 
public class DebugService { } using (ServiceHost host = new ServiceHost(typeof(DebugService))) { ServiceDescription svcDesc = host.Description.Behaviors; ServiceDebugBehavior svcDebug = svcDesc.Behaviors.Find<ServiceDebugBehavior>(); svcDebug.IncludeExceptionDetailInFaults = true; host.Open(); }

Enable the property partially

Supose that you have a WCF service with two endpoint: debubep1 and debugep2  (see below the config file that represent the configuration), now you need that only the endpoint called debugep1 sends managed exception information. 

<system.serviceModel>
    <services>
        <service name="devdeo.WCF.DebugService"
            behaviorConfiguration="DebugServiceConfiguration"> 
            <endpoint address="net.tcp://localhost:8009/wcf/debugep1"
                binding="netTcpBinding"
                bindingName="debugep1"
                bindingNamespace="http://wcf.devdeo.com/binding/"
                contract="devdeo.WCF.DebugService" />
            <endpoint address="net.tcp://localhost:8009/wcf/debugep2"
                binding="netTcpBinding"
                bindingName="debugep2"
                bindingNamespace="http://wcf.devdeo.com/binding/"
                contract="devdeo.WCF.DebugService" />
        </service>
        <behaviors>
            <serviceBehaviors>
                <behavior name="DebugServiceConfiguration">
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
        </behaviors> 
    </services>
</system.serviceModel>

To implement this, you must create a custom service class that derives from Attribute class and IServiceBehavior interface.  After it, override the ApplyDispatcherBehavior method to evaluate each endpoint reprensted by the ChannelDispatcher class and change the IncludeExceptionDetailInFaults to true.

The ApplyDispatcherBehavior method allows to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects. 

[ServiceContract(Namespace = "http://wcf.devdeo.com/debug/")]
[CustomDebugBehavior]
public class DebugService
{ }

public class CustomDebugBehaviorAttribute : Attribute, IServiceBehavior
{
    #region IServiceBehavior Members
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, 
        System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, 
        System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
        // to-do...
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
            if (cd.BindingName.Equals("http://wcf.devdeo.com/binding/:debugep1"))
                cd.IncludeExceptionDetailInFaults = true;
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        // to-do...
    }
    #endregion
}

At the end, start the WCF service normally. 

using (ServiceHost host = new ServiceHost(typeof(DebugService))) {
    host.Open();
    ...
}

 

Remember that returning managed exception information to services can be a security risk.  This is because exception details expose information about the internal client implementation that could be used by unauthorized services.

NOTE: you can read the spanish version of this post at Propiedad IncludeExceptionDetailInFaults en WCF

 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