Throwing FaultException using Custom Exception Handler EL WCF

做~自己de王妃 提交于 2019-12-13 13:25:13

问题


So I'm trying to use Enterprise Library in my WCF service to do some of the exception-related work for me.

My idea is to set up a "Custom Exception Handler" for say "NullReferenceException" and in the "Custom Exception Handler" create FaultException exception.

My understanding is that this "new" exception will then make it across the wire and I will catch it at the client.

Some code for better understanding:

WCF service:

[ServiceContract(Name="MyService", ConfigurationName="MyNamespace.MyService")]
    [ExceptionShielding("PolicyName")]
    public interface IMyService
    {
        [OperationContract]
        [FaultContract(typeof(MyFaultContract))]
        string Method(String Param);
}

public class MyService : IMyService
    {
        public string Method(String Param)
        {
          throw new  NullReferenceException("code-created null message here");
        }
}

Custom Exception Handler: (Enterprise library)

public class MyExceptionHandler : IExceptionHandler
    {
        public MyExceptionHandler(NameValueCollection collection) { }

        public MyExceptionHandler() { }

        public System.Exception HandleException(System.Exception exception, 
                              Guid handlingInstanceId)
        {
                MyFaultContract details = new MyFaultContract();
                if (exception is NullReferenceException)
                {
                    details.ErrorCode = MyFaultCode.NullReferenceException;
                    details.OriginalMessage = exception.Message;
                    details.MyMessage = "Null Reference exception here!";
                }
                return new FaultException<MyFaultContract>(details);
            }
}

App Config File that maps NullReferenceException to "Custom Exception Handler":

<exceptionPolicies>
      <add name="PolicyName">
        <exceptionTypes>
          <add name="NullReferenceException" type="System.NullReferenceException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="ThrowNewException">
            <exceptionHandlers>
              <add type="MyExceptionHandler, MyApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
                name="MyExceptionHandler" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>

And finally Client code that expects to catch this FaultException:

MyService.MyServiceClient client = new MyService.MyServiceClient();
            client.Open();
            try
            {
                string result = client.Method(string parameter);
            }

            catch (System.ServiceModel.FaultException<MyService.MyFaultContract> ex)
            {
                // where I think exception should end up
            }
            catch (System.ServiceModel.FaultException ex)
            {
                // general FaultException
            }

But instead I get a ProtocolException, stating that reply action is required:

A reply message was received for operation 'Method' with action ''. However, your client code requires action 'http://tempuri.org/MyService/MethodResponse'.

What am I doing wrong? Is it possible to return (not explicitly throw) an FaultException with custom FaultContract in the "Custom Exception Handler"?

Any advice is appreciated.

Update: As you can see, post-handling action in the "Custom Exception Handler" is set to "ThrowNewException". If I change it to "NotifyRethrow" I don't het "ProtocolException" any more! Instead, client catches a regular "FaultException" (not custom-typed).

Now the question is why original custom-typed FaultException doesn't make it across the wire.

Update 2 One thing I forgot to mention is the fact that my WCF service is running within the ServiceHost, not under IIS. So basically I have a Windows service that creates a ServiceHost and exposes Service1 interface through this ServiceHost.

The reason why I think this may have something to do with this problem is that Enterprise Library claims it deals with exceptions throughout entire application, not only within service boundaries. Maybe this cause the exception to be thrown too late? Or not at the correct level?

Update 3
Thanks for the post! You're right, the only reason why I'm messing with custom handler is because I want to set MyFaultCode value. I tried your advice - having 2 handlers configured.

First is a custom handler and catches NullReference exception. It than throws a new exception - MyApplicationException, with MyFaultContract field.

Then I configured second handler - built-in "Fault Contract Exception Handler" that catches MyApplicationException, creates new FaultException and automatically maps MyFaultcontract from MyApplicationException to the newly created FaultException.

WCF client still catches generic FaultException, not the custom-contract one.


回答1:


I would consider using a custom WCF IErrorHandler implementation. It provides a place to centrally handle all unhandled exceptions that occur within your service methods.

In my opinion it ends up cleaner than using Ent Lib, is 1 less dependency, and you wont need that error mapping in your config, so less XML.

Example:

public class MyServiceErrorHandler : IErrorHandler
{
    /// <summary>
    /// Central error handling for WCF services.
    /// Whenever a service encounteres an unhandled exception, it will end up here.
    /// This method will log the error and continue with normal error processing.
    /// </summary>
    /// <param name="error">The unhandled exception thrown from a service method.</param>
    /// <returns>true if the exceptions has been handled, false if normal error processing should continue. This implementation will always return false.</returns>
    public virtual bool HandleError(Exception error)
    {
        return false; // returning false so that WCF will still process the exception as usual.
    }

    /// <summary>
    /// Create a custom Fault message to return to the client.
    /// </summary>
    /// <param name="error">The Exception object thrown in the course of the service operation.</param>
    /// <param name="version">The SOAP version of the message.</param>
    /// <param name="fault">The Message object that is returned to the client, or service, in the duplex case.</param>
    public virtual void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        //If it's a FaultException already, then we have nothing to do
        if (error is FaultException)
            return;

        // pack the exception info into the Fault Contract
        MyFaultContract details = new MyFaultContract();
        if (exception is NullReferenceException)
        {
            details.ErrorCode = MyFaultCode.NullReferenceException;
            details.OriginalMessage = error.Message;
            details.MyMessage = "Null Reference exception here!";
        }
        var faultException = new FaultException<MyFaultContract>(details);

        // turn the fault contract into the response WCF Message.
        var messageFault = faultException.CreateMessageFault();
        fault = Message.CreateMessage(version, messageFault, faultException.Action);
    }
}

Of course if you have other reasons to want to use Ent Lib, then go ahead. You can probably tie them both together somehow.

This link also has some good reading on error handling, including adding the custom IErrorHandler behavior: http://www.codeproject.com/KB/WCF/WCFErrorHandling.aspx




回答2:


I was going to make this a comment but it got too long.

Did you look at using Exception Handling Block Exception Shielding with The Fault Contract Exception Handler? I think it does most of what you want. http://msdn.microsoft.com/en-us/library/ff953192(v=PandP.50).aspx

The approach would be to create your own handler to map all of the properties to your custom exception type. Then configure the FaultContractExceptionHandler to map the properties in your exception to the properties in the fault contract.

If you didn't need to set a value for MyFaultCode you could probably avoid writing a custom handler all together.



来源:https://stackoverflow.com/questions/8752436/throwing-faultexception-using-custom-exception-handler-el-wcf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!