【问题标题】:Throwing FaultException using Custom Exception Handler EL WCF使用自定义异常处理程序 EL WCF 引发 FaultException
【发布时间】:2012-01-06 01:44:29
【问题描述】:

所以我尝试在我的 WCF 服务中使用企业库来为我做一些与异常相关的工作。

我的想法是为说“NullReferenceException”设置一个“自定义异常处理程序”,并在“自定义异常处理程序”中创建 FaultException 异常。

我的理解是,这个“新”异常将通过网络传递,我将在客户端捕获它。

一些代码以便更好地理解:

WCF 服务:

[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");
        }
}

自定义异常处理程序:(企业库)

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);
            }
}

将 NullReferenceException 映射到“自定义异常处理程序”的应用程序配置文件:

<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>

最后是期望捕获此 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
            }

但是我得到了一个 ProtocolException,说明需要回复操作:

收到操作“方法”的回复消息,操作为“”。 但是,您的客户端代码需要操作 'http://tempuri.org/MyService/MethodResponse'。

我做错了什么?是否可以在“自定义异常处理程序”中返回(不显式抛出)带有自定义 FaultContract 的 FaultException?

感谢任何建议。

更新: 如您所见,“自定义异常处理程序”中的后处理操作设置为“ThrowNewException”。 如果我将其更改为“NotifyRethrow”,我将不再使用“ProtocolException”! 相反,客户端会捕获常规的“FaultException”(不是自定义类型的)。​​

现在的问题是为什么原始的自定义类型的 FaultException 没有成功。

更新 2 我忘记提及的一件事是我的 WCF 服务在 ServiceHost 中运行,而不是在 IIS 下运行。所以基本上我有一个 Windows 服务,它创建一个 ServiceHost 并通过这个 ServiceHost 公开 Service1 接口。

我认为这可能与此问题有关的原因是 Enterprise Library 声称它处理整个应用程序中的异常,而不仅仅是在服务边界内。也许这会导致异常被抛出为时已晚?还是不在正确的级别?

更新 3
谢谢你的帖子! 你是对的,我搞乱自定义处理程序的唯一原因是因为我想设置 MyFaultCode 值。 我尝试了您的建议 - 配置了 2 个处理程序。

First 是一个自定义处理程序并捕获 NullReference 异常。它会引发一个新异常 - MyApplicationException,带有 MyFaultContract 字段。

然后我配置了第二个处理程序 - 内置的“Fault Contract Exception Handler”,它捕获 MyApplicationException,创建新的 FaultException 并自动将 MyFaultcontract 从 MyApplicationException 映射到新创建的 FaultException。

WCF 客户端仍然捕获通用的 FaultException,而不是自定义合同。

【问题讨论】:

    标签: wcf enterprise-library faultexception protocolexception


    【解决方案1】:

    我会考虑使用自定义 WCF IErrorHandler 实现。它提供了一个集中处理服务方法中发生的所有未处理异常的地方。

    在我看来,它最终比使用 Ent Lib 更干净,减少了 1 个依赖项,并且您不需要在配置中进行错误映射,因此减少了 XML。

    例子:

    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);
        }
    }
    

    当然,如果您有其他原因想要使用 Ent Lib,那就继续吧。您可能可以以某种方式将它们绑在一起。

    这个链接也有一些关于错误处理的好读物,包括添加自定义 IErrorHandler 行为:http://www.codeproject.com/KB/WCF/WCFErrorHandling.aspx

    【讨论】:

    • 感谢您指出此解决方案。我试过了,它似乎做了我现在需要的。真的感觉……虽然水平很低。我的意思是你正在捕捉异常试图通过网络实现它并执行一些逻辑的时刻。对于其他团队成员可能并不完全透明,但肯定能满足我的需要。再次感谢!
    【解决方案2】:

    我本来打算发表评论的,但是太长了。

    您是否考虑过将异常处理块异常屏蔽与故障合同异常处理程序一起使用?我认为它可以满足您的大部分需求。 http://msdn.microsoft.com/en-us/library/ff953192(v=PandP.50).aspx

    方法是创建您自己的处理程序以将所有属性映射到您的自定义异常类型。然后配置 FaultContractExceptionHandler 将异常中的属性映射到故障契约中的属性。

    如果您不需要为 MyFaultCode 设置值,则可以避免一起编写自定义处理程序。

    【讨论】:

    • 你说得对,我搞乱自定义处理程序的唯一原因是因为我想设置 MyFaultCode 值。所以这是我的 2 个 hadnlers:首先是一个自定义处理程序,它捕获 NullReference 异常。它会抛出一个带有 MyFaultContract 字段的新异常 MyApplicationException。第二个处理程序 - 内置的“Fault Contract Exception Handler”捕获 MyApplicationException,创建新的 FaultException 并自动将 MyFaultcontract 从 MyApplicationException 映射到新创建的 FaultException。 WCF 客户端仍然捕获通用的 FaultException,而不是自定义合同。
    • @iEddie:内置的故障契约异常处理程序是否如您所愿? IE。是抛出 FaultException 而不是 FaultException
    • 好吧,如果我只使用内置的故障契约异常处理程序 - 是的。所以,比如说,我明确地抛出了 MyApplicationException,并且在 EL 中我配置了 Fault Contract Exception Handler 来捕获 MyApplicationException 并将其转换为 FaultException。在这种情况下 - 是的,一切正常。但我希望我的自定义 FaultException 填充 FaultCode 字段,并且标准映射(EL GUI 映射接口)似乎没有办法在新异常中设置固定值,只能将值从一个异常对象传输到另一个异常对象。
    猜你喜欢
    • 2011-08-08
    • 1970-01-01
    • 2013-06-08
    • 2013-05-28
    • 2011-07-13
    • 2015-10-18
    • 2023-03-04
    • 2014-06-06
    相关资源
    最近更新 更多