【问题标题】:How to use FaultException with details without specifying FaultContractAttribute如何在不指定 FaultContractAttribute 的情况下使用带有详细信息的 FaultException
【发布时间】:2020-11-05 04:35:00
【问题描述】:

我很清楚如何使用 FaultException 和细节。我知道我可以声明详细信息合同,然后我需要用 [FaultContract(type(DetailsContractType))] 装饰预计会引发此类异常的方法,然后在该方法中抛出 FaultException。所有这些都被理解和工作。我需要的是能够从我的 WCF 主机中所有合同的所有方法中抛出 FaultException。在每个操作合同的每个方法中添加 [FaultContract(type(DetailsContractType))] 对我来说似乎很重要。有没有另一种方法来允许这种异常而不用该属性装饰方法?如果我只是删除该属性,那么一切都会停止工作,并且异常在客户端就变成了 FaultException。我在考虑 DataContractResolver 但看起来它不涉及 DetailsContractType 解析。有什么想法、提示、解决方案吗?

【问题讨论】:

    标签: wcf faultexception


    【解决方案1】:

    可以实现IErrorHandler接口统一处理WCF中的错误,这里有一个Demo:

      [ServiceContract]
        public interface IDemo {
            [OperationContract]
            void DeleteData(int dataId);
        }
    
    class DemoService : IDemo
    {
        public void DeleteData(int dataId)
        {
            if (dataId<0) {
                throw new ArgumentException("error");
            }
        }
    }
    

    以上代码是WCF服务的接口和实现类。

     class MyCustErrorHandler : IErrorHandler
        {
            public bool HandleError(Exception error)
            {
                return true;
            }
            public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {
                FaultException faultException = new FaultException(error.Message);
                MessageFault messageFault = faultException.CreateMessageFault();
                fault = Message.CreateMessage(version,messageFault,"my-test-error");
            }
        }
    

    以上代码是IErrorHandler接口的实现类。

    class MyEndpointBehavior : IEndpointBehavior
        {
            public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
            {
                return;
            }
    
            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
            {
                return;
            }
    
            public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
            {
                MyCustErrorHandler handler = new MyCustErrorHandler();
                endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(handler);
            }
    
            public void Validate(ServiceEndpoint endpoint)
            {
                return;
            }
        }
    

    我们通过扩展端点的 Behavior 方法来添加一个自定义的错误处理类。

      ServiceEndpoint ep = selfHost.AddServiceEndpoint(typeof(IDemo), new BasicHttpBinding(), "CalculatorService");
      MyEndpointBehavior myEndpointBehavior = new MyEndpointBehavior();
      ep.EndpointBehaviors.Add(myEndpointBehavior);
    

    客户端执行以下代码会在控制台打印“error”:

            try { 
                demoClient.DeleteData(-3);
                }
            catch (FaultException fault) {
                string err = fault.Reason.GetMatchingTranslation().Text;
                Console.WriteLine(err);
            }    
    

    有关IErrorhandler的更多信息,请参考以下链接:

    https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.dispatcher.ierrorhandler?view=netframework-4.8

    更新

    如果不想使用IErrorhandler,也可以使用FaultReason:

    public string SayHello(string name) {
                if (name.Length<2) {
                    FaultReasonText faultReasonText = new FaultReasonText("name length cannot be less than 2");
                    FaultReason reason = new FaultReason(faultReasonText);
                    throw new FaultException(reason);
                }
                return "hello";
            }
    

    客户端调用时需要捕获异常:

            try {
                    string res = channnel.Sayhello("B");
    
                }
                catch (FaultException fex) {
    
                    if (fex.Reason != null) {
                        FaultReason reason = fex.Reason;
                        //Get error information
                        FaultReasonText txt = reason.GetMatchingTranslation();
                        Console.WriteLine(txt.Text);
                    
                    }
                }
    

    【讨论】:

      【解决方案2】:

      使用 IErrorHandler 并不能免除您使用我试图避免的 FaultContractAttribute 装饰合约操作的麻烦。甚至在您提到的示例中也有说明,那里有评论

      // This behavior requires that the contract have a SOAP fault with a detail type of 
      GreetingFault.
      

          throw new InvalidOperationException(String.Format(
            "EnforceGreetingFaultBehavior requires a "
            + "FaultContractAttribute(typeof(GreetingFault)) in each operation contract.  "
            + "The \"{0}\" operation contains no FaultContractAttribute.",
            opDesc.Name)
          );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-19
        • 1970-01-01
        • 2012-06-18
        • 1970-01-01
        相关资源
        最近更新 更多