Example 6-1. The FaultException<T> class

using System;
using System.Runtime;
using System.Runtime.Serialization;
using System.Security;
using System.ServiceModel.Channels;

namespace System.ServiceModel
{
    [Serializable] //More attributes
    public class FaultException : CommunicationException
    {
        public FaultException( );
        public FaultException(string reason);
        public FaultException(FaultReason reason);
        public virtual MessageFault CreateMessageFault( );
        //More members
    }

    [Serializable]
    public class FaultException<T> : FaultException
    {
        public FaultException(T detail);
        public FaultException(T detail,string reason);
        public FaultException(T detail,FaultReason reason);
        //More members
    }   
}        
View Code

Example 6-2. Throwing a FaultException<T>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace WCFServiceProgramming.Library
{
    [ServiceContract]
    interface ICalculator
    {
        [OperationContract]
        double Divide(double number1, double number2);

        //More methods
    }
    
    class Calculator : ICalculator
    {
        public double Divide(double number1, double number2)
        {
            if (number2 == 0)
            {
                DivideByZeroException exception = new DivideByZeroException();
                throw new FaultException<DivideByZeroException>(exception);
            }

            return number1 / number2;
        }

        //Rest of the implementation
    }
}
View Code

Example 6-3. Defining a fault contract

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace WCFServiceProgramming.Library
{
    [ServiceContract]
    interface ICalculator
    {
        [OperationContract]
        double Add(double number1, double number2);

        [OperationContract]
        [FaultContract(typeof(DivideByZeroException))]
        double Divide(double number1, double number2);

        //More methods
    }
}
View Code

Example 6-4. Including the service exception in the fault message

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace WCFServiceProgramming.Library
{
    [ServiceContract]
    public interface IMyContract
    {
        [OperationContract]
        void MethodWithError();
    }

    class MyService : IMyContract
    {
        public void MethodWithError()
        {
            InvalidOperationException exception = new InvalidOperationException("Some error");
            ExceptionDetail detail = new ExceptionDetail(exception);

            throw new FaultException<ExceptionDetail>(detail, exception.Message);
        }
    }
}
View Code

Example 6-5. Processing the included exception

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.Runtime.Serialization;
using WCFServiceProgramming.Library;
using System.Diagnostics;

namespace WCFServiceProgramming.Client
{
    class MyContractClient : ClientBase<IMyContract>, IMyContract
    {
        public void MethodWithError()
        {
            Channel.MethodWithError();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyContractClient proxy = new MyContractClient();

            try
            {
                proxy.MethodWithError();
            }
            catch (FaultException<ExceptionDetail> exception)
            {
                Debug.Assert(exception.Detail.Type == typeof(InvalidOperationException).ToString());
                Debug.Assert(exception.Message == "Some error");
            }
        }
    }
}
View Code

Example 6-6. SettingIncludeExceptionDetailInFaults to true in debug only

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace WCFServiceProgramming.Library
{
    [ServiceContract]
    public interface IMyContract
    {
        [OperationContract]
        void MethodWithError();
    }

    public static class DebugHelper
    {
        public const bool IncludeExceptionDetailInFaults = 
    #if DEBUG
            true;
    #else
            false;
    #endif
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = DebugHelper.IncludeExceptionDetailInFaults)]
    class MyService : IMyContract
    {
        public void MethodWithError()
        {
            InvalidOperationException exception = new InvalidOperationException("Some error");
            ExceptionDetail detail = new ExceptionDetail(exception);

            throw new FaultException<ExceptionDetail>(detail, exception.Message);
        }
    }
}
View Code

Example 6-7. ServiceHost<T> and returning unknown exceptions

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Diagnostics;
using System.ServiceModel.Channels;

namespace WCFServiceProgramming.Host
{
    public class ServiceHost<T> : ServiceHost
    {
        public bool IncludeExceptionDetailInFaults
        {
            set
            {
                if (State == CommunicationState.Opened)
                {
                    throw new InvalidOperationException("Host is already opened");
                }

                ServiceBehaviorAttribute debuggingBehavior =
                    Description.Behaviors.Find<ServiceBehaviorAttribute>();

                debuggingBehavior.IncludeExceptionDetailInFaults = value;
            }
            get
            {
                ServiceBehaviorAttribute debuggingBehavior =
                    Description.Behaviors.Find<ServiceBehaviorAttribute>();

                return debuggingBehavior.IncludeExceptionDetailInFaults;
            }
        }
    }
}
View Code

Example 6-8. Administratively including exceptions in the fault message

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="MyService" behaviorConfiguration="Debugging">
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Debugging">
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>
View Code

Example 6-9. Callback contract with fault contract

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace WCFServiceProgramming.Library
{
    [ServiceContract(CallbackContract = typeof(IMyContractCallback))]
    public interface IMyContract
    {
        [OperationContract]
        void DoSomething();
    }

    interface IMyContractCallback
    {
        [OperationContract]
        [FaultContract(typeof(InvalidOperationException))]
        void OnCallback();
    }
}
View Code

Example 6-10. Fault handling in out-of-band invocation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;

namespace WCFServiceProgramming.Library
{
    [ServiceContract(CallbackContract = typeof(IMyContractCallback))]
    public interface IMyContract
    {
        [OperationContract]
        void DoSomething();
    }

    interface IMyContractCallback
    {
        [OperationContract]
        [FaultContract(typeof(InvalidOperationException))]
        void OnCallback();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    class MyService : IMyContract
    {
        static List<IMyContractCallback> m_Callbacks =
            new List<IMyContractCallback>();

        public void DoSomething()
        {
            IMyContractCallback callback =
                OperationContext.Current.GetCallbackChannel<IMyContractCallback>();

            if (m_Callbacks.Contains(callback) == false)
            {
                m_Callbacks.Add(callback);
            }
        }

        public static void CallClients()
        {
            Action<IMyContractCallback> invoke = delegate(IMyContractCallback callback)
            {
                try
                {
                    callback.OnCallback();
                }
                catch (FaultException<InvalidOperationException> exception)
                { }
                catch (FaultException exception)
                { }
                catch (CommunicationException exception)
                { }
            };

            m_Callbacks.ForEach(invoke);
        }
    }
}
View Code

Example 6-11. Creating an alternative fault

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel;

namespace WCFServiceProgramming
{
    class MyErrorHandler : IErrorHandler
    {
        #region IErrorHandler Members

        public bool HandleError(Exception error)
        {
            //...
            return true;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            FaultException<int> faultException = new FaultException<int>(3);
            MessageFault messageFault = faultException.CreateMessageFault();

            fault = Message.CreateMessage(version, messageFault, faultException.Action);
        }

        #endregion
    }
}
View Code

Example 6-12. Exception promotion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel;

namespace WCFServiceProgramming
{
    class MyErrorHandler : IErrorHandler
    {
        #region IErrorHandler Members

        public bool HandleError(Exception error)
        {
            //...
            return true;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            FaultException<InvalidOperationException> faultException =
                new FaultException<InvalidOperationException>(new InvalidOperationException(error.Message));
            MessageFault messageFault = faultException.CreateMessageFault();

            fault = Message.CreateMessage(version, messageFault, faultException.Action);
        }

        #endregion
    }
}
View Code

Example 6-13. Logging the error log to a logbook service

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel;
using WCFServiceProgramming.Library;

namespace WCFServiceProgramming
{
    class MyContractClient : ClientBase<IMyContract>, IMyContract
    {
        public void DoSomething()
        {
            Channel.DoSomething();
        }
    }

    class MyErrorHandler : IErrorHandler
    {
        #region IErrorHandler Members

        public bool HandleError(Exception error)
        {
            try
            {
                MyContractClient proxy = new MyContractClient();

                proxy.DoSomething();
                proxy.Close();
            }
            catch
            { }
            
            return false;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
        }

        #endregion
    }
}
View Code

Example 6-14. Adding an error extension object

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;

namespace WCFServiceProgramming.Library
{
    class MyErrorHandler : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            return false;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
        }
    }

    public interface IMyContract
    {
        [OperationContract]
        void DoSomething();
    }

    class MyService : IMyContract, IServiceBehavior
    {
        #region IMyContract Members

        public void DoSomething()
        {
            
        }

        #endregion

        #region IServiceBehavior Members

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, 
            Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase host)
        {
            IErrorHandler handler = new MyErrorHandler();
            foreach (ChannelDispatcher dispatcher in host.ChannelDispatchers)
            {
                dispatcher.ErrorHandlers.Add(handler);
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            
        }

        #endregion
    }
}
View Code

Example 6-15. Supporting IErrorHandler by the service class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;

namespace WCFServiceProgramming.Library
{
    class MyErrorHandler : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            return false;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
        }
    }

    public interface IMyContract
    {
        [OperationContract]
        void DoSomething();
    }

    class MyService : IMyContract, IServiceBehavior, IErrorHandler
    {
        #region IMyContract Members

        public void DoSomething()
        {
            
        }

        #endregion

        #region IServiceBehavior Members

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, 
            Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase host)
        {
            foreach (ChannelDispatcher dispatcher in host.ChannelDispatchers)
            {
                dispatcher.ErrorHandlers.Add(this);
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            
        }

        #endregion

        #region IErrorHandler Members

        public bool HandleError(Exception error)
        {
            return false;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            
        }

        #endregion
    }
}
View Code

Example 6-16. The ErrorHandlerBehavior attribute

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel;
using System.Collections.ObjectModel;
using System.ServiceModel.Channels;

namespace WCFServiceProgramming.Library
{
    public class ErrorHandlerBehaviorAttribute : Attribute, IServiceBehavior, IErrorHandler
    {
        protected Type ServiceType
        {
            get;
            set;
        }

        #region IServiceBehavior Members

        public void AddBindingParameters(ServiceDescription description, ServiceHostBase host, 
            Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            
        }

        public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase host)
        {
            ServiceType = description.ServiceType;

            foreach (ChannelDispatcher dispatcher in host.ChannelDispatchers)
            {
                dispatcher.ErrorHandlers.Add(this);
            }
        }

        public void Validate(ServiceDescription description, ServiceHostBase host)
        {
            
        }

        #endregion

        #region IErrorHandler Members

        public bool HandleError(Exception error)
        {
            return false;
        }

        public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
        {
            
        }

        #endregion
    }
}
View Code

Example 6-17. Implementing AddErrorHandler( )

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Diagnostics;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Collections.ObjectModel;
using WCFServiceProgramming.Library;

namespace WCFServiceProgramming.Host
{
    public class ServiceHost<T> : ServiceHost
    {
        class ErrorHandlerBehavior : IServiceBehavior, IErrorHandler
        {
            IErrorHandler m_ErrorHandler;

            public ErrorHandlerBehavior(IErrorHandler errorHandler)
            {
                m_ErrorHandler = errorHandler;
            }

            #region IErrorHandler Members

            public bool HandleError(Exception error)
            {
                return false;
            }

            public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {  
            }

            #endregion

            #region IServiceBehavior Members

            public void AddBindingParameters(ServiceDescription description, ServiceHostBase host, 
                Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
            {
            }

            public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase host)
            {
                foreach (ChannelDispatcher dispatcher in host.ChannelDispatchers)
                {
                    dispatcher.ErrorHandlers.Add(this);
                }
            }

            public void Validate(ServiceDescription description, ServiceHostBase host)
            {
            }

            #endregion
        }

        List<IServiceBehavior> m_ErrorHandlers = new List<IServiceBehavior>();

        public void AddErrorHandler(IErrorHandler errorHandler)
        {
            if (State == CommunicationState.Opened)
            {
                throw new InvalidOperationException("Host is already opened");
            }

            IServiceBehavior errorHandlerBehavior = new ErrorHandlerBehavior(errorHandler);
            m_ErrorHandlers.Add(errorHandlerBehavior);
        }

        public void AddErrorHandler()
        {
            if (State == CommunicationState.Opened)
            {
                throw new InvalidOperationException("Host is already opened");
            }

            IServiceBehavior errorHandlerBehavior = new ErrorHandlerBehaviorAttribute();
            m_ErrorHandlers.Add(errorHandlerBehavior);
        }

        protected override void OnOpening()
        {
            foreach (IServiceBehavior behavior in m_ErrorHandlers)
            {
                Description.Behaviors.Add(behavior);
            }
            base.OnOpening();
        }
        //Rest of the implementation
    }
}
View Code

Example 6-18. Implementing IEndpointBehavior

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCFServiceProgramming.Library;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;

namespace WCFServiceProgramming
{
    class MyClient : IMyContractCallback, IEndpointBehavior
    {
        #region IMyContractCallback Members

        public void OnCallback()
        {
        }

        #endregion

        #region IEndpointBehavior Members

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection parameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime behavior)
        {
            IErrorHandler handler = new MyErrorHandler();

            behavior.CallbackDispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(handler);
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher dispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        #endregion
    }
}
View Code

Example 6-19. Implementing CallbackErrorHandlerBehavior attribute

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

namespace WCFServiceProgramming.Library
{
    public class CallbackErrorHandlerBehaviorAttribute : 
        ErrorHandlerBehaviorAttribute, IEndpointBehavior
    {
        public CallbackErrorHandlerBehaviorAttribute(Type clientType)
        {
            ServiceType = clientType;
        }

        #region IEndpointBehavior Members

        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection parameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime behavior)
        {
            behavior.CallbackDispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(this);
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher dispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        #endregion
    }
}
View Code

 

 

 

posted on 2012-11-22 17:24  逝者如斯(乎)  阅读(191)  评论(0编辑  收藏  举报