【问题标题】:WCF FaultExceptionWCF 故障异常
【发布时间】:2023-09-13 01:59:01
【问题描述】:

在构建 WCF 服务时,如果我在服务中不包含我的 FaultException 合同,我可以在客户端上创建包含所有成员的 WCF 服务引用在 Reference.cs 文件中。

如果我包含我的 FaultException 合同,会发生两件事。

  1. 在 WCF 测试客户端中,我在合同名称(CreateFaultMessage)旁边有一个红色的“X”

  2. 当我创建 WCF 服务引用时,并非所有成员都是 包含在 Reference.cs 文件中。

由于我不是 WCF 专家,因此我希望有人能够告知我在创建 FaultException 合同时我做错了什么。

下面是我的合约在界面中的代码声明。

[OperationContract]
        [FaultContractAttribute(typeof(LogEventArgs), ProtectionLevel = ProtectionLevel.None)]
        Exception CreateFaultMessage(Exception ex, string method);

下面是类中实现接口的方法。 注意 PostTransmissionRecord 方法的 catch 块中对 CreateFaultMessage 方法的调用。

public bool PostTransmissionRecord(TransmissionRecord transmissionRecord)
{
    bool blnUpdated = false;

    try
    {
        blnUpdated = TransmissionRecordGateway.InsertData(transmissionRecord);
        LogMessage.WriteEventLog("Transmission records updated successfully", "Ryder.ShopProcessService.SOA", 3, null);

        return blnUpdated;
    }
    catch (Exception ex)
    {
        LogMessage.WriteEventLog("Class: ShopProcessService" + CrLf + "Method: PostTransmissionRecord" + CrLf + "Error: " + ex.Message + CrLf + "InnerException: " + ex.InnerException + CrLf + "Source: " + ex.Source + CrLf + "StackTrace: " + ex.StackTrace, "Ryder.ShopProcessService.SOA", 1, null);
        IssueRemedyTicket("Class: ShopProcessService" + CrLf + "Method: PostTransmissionRecord" + CrLf + "Error: " + ex.Message + CrLf + "InnerException: " + ex.InnerException + CrLf + "Source: " + ex.Source + CrLf + "StackTrace: " + ex.StackTrace);
        CreateFaultMessage(ex, "UpdateSearchInventory");
        return blnUpdated;
    }
}

public Exception CreateFaultMessage(Exception ex, string method)
{
    LogEventArgs detail = new LogEventArgs();

    detail.ApplicationID = "ShopProcessService";
    detail.ExceptionMessage = ex.Message;
    detail.LogEventType = LogEventTypeEnum.Error;
    detail.Method = method;
    detail.Source = ex.Source;
    detail.StackTrace = ex.StackTrace;
    if (ex.InnerException != null)
        detail.InnerExceptionMessage = ex.InnerException.ToString();
    else
        detail.InnerExceptionMessage = null;

    throw new FaultException<LogEventArgs>(detail);
}

更新代码

DataContract 类

namespace Ryder.Enterprise.DataTransferObjects
{
    [Serializable, DataContract(Name = "LogEventArgs", Namespace = "http://www.Ryder.com/SOA/DataContracts/2014/02/17")]
    public class LogEventArgs
    {
        private string applicationID;
        private string method;
        private LogEventTypeEnum logEventType;
        private string exceptionMessage;
        private string innerExceptionMessage;
        private string stackTrace;
        private string source;

        [DataMember(Name = "ApplicationID")]
        public string ApplicationID
        {
            get
            {
                return applicationID;
            }
            set
            {
                applicationID = value;
            }
        }
.
.
.

服务方法抛出FAULTEXCEPTION

public bool UpdateSpotCheckInventory(SpotCheck transferObject)
        {
            bool blnUpdated = false;

            try
            {
                blnUpdated = SpotCheckCollectionGateway.UpdateData(transferObject);
                LogMessage.WriteEventLog("SpotCheck records updated successfully", "Ryder.ShopProcessService.SOA", 3, null);

                return blnUpdated;
            }
            catch (Exception ex)
            {
                //throw fault exception here on service
                return blnUpdated;
            }
        }

捕获错误提示的客户端代码

catch (FaultException<LogEventArgs> ex)
            {                   ex.Detail.ApplicationID = "ShopProcessService";
                ex.Detail.LogEventType = LogEventTypeEnum.Error;
                serviceClient.Abort();
            } 

【问题讨论】:

    标签: c# .net wcf faultexception


    【解决方案1】:

    为了简化从服务中抛出 FaultException 并在客户端捕获和处理它的方法,请遵循以下代码:

    服务:

    public bool UpdateSpotCheckInventory(SpotCheck transferObject)
    {
        bool blnUpdated = false;
        try
        {
            blnUpdated = SpotCheckCollectionGateway.UpdateData(transferObject);
            LogMessage.WriteEventLog("SpotCheck records updated successfully", "Ryder.ShopProcessService.SOA", 3, null);
            return blnUpdated;
        }
        catch (Exception ex)
        {
            //throw fault exception here on service
            throw new FaultException("A fatal exception occurred while processing your request", new FaultCode("1000"))
        }
    }
    

    客户:

    catch (FaultException ex)
    {
        ex.Detail.ApplicationID = "ShopProcessService";
        ex.Detail.LogEventType = LogEventTypeEnum.Error;
        serviceClient.Abort();
    
        // You can also access the custom message and error code sent from the service...
        String customErrorCode = ex.Code.Name;
        String customErrorMessage = ex.Reason;
    }
    

    我相信这会解决您的问题。 :-)

    【讨论】:

    • 海霞,感谢更新。我明白。最后一个问题...如果我在 LogEventArgs 类中包含属性,我是否需要在中止客户端之前放置以下代码? ex.Detail.ApplicationID = "ShopProcessService"; ex.Detail.LogEventType = LogEventTypeEnum.Error; ex.Detail.FaultCode = ex.Code; ex.Detail.Reason = ex.Reason; ex.Detail.ExceptionMessage = ex.Message;或者 ExceptionMessage 等会是多余的吗?
    【解决方案2】:

    请尝试将CustomFault(本例中为MathFault)定义为数据合约而不是操作合约,例如:

    [DataContract]
    public class MathFault
    {    
        //...
    }
    

    在客户端:

    static void Main(string[] args)
    {
        ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
        try
        {
            int value1 = 22;
            int value2 = 0;
            int result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
            client.Close();
        }
        catch (FaultException<MathFault> e)
        {
            Console.WriteLine("FaultException<MathFault>: Math fault while doing " + e.Detail.Operation + ". Problem: " + e.Detail.ProblemType);
            client.Abort();
            Console.ReadLine();
        }
    }
    

    查看更多:Fault Contract

    【讨论】:

    • 参考更新后的代码。这个问题是针对 DataContract 类的: Haixia,非常感谢您的帮助 :) 我修改了代码,但不确定如何抛出 FaultException。我现在在我的服务上设置了以下内容:我正在引用一个包含 DataContract 的类,如下所示。我想我只需要 applicationID 和 logeventType 因为 FaultException 似乎会继承我列出的其他属性。如果这是真的,请告诉我。
    • 这个问题是针对抛出FAULT异常的Service方法。这是我要抛出 FaultException 的方法。从语法上看,这看起来如何?不知道如何将它放在 Catch 块中,或者甚至 Catch 块是否正确。
    • 这个问题与 CLIENT CODE CATCHING THE FAUTEXCEPTION 有关。这就是我现在在我的客户身上所拥有的。当 FaultException 被命中时,它会被传输回调用服务,他们会收到带有适当属性的异常消息,包括 ex.Message、stacktrace、方法等?
    • 最后,最后一个问题:在从服务中获取 FaultException 的接收端,Catch 块会是什么样子?
    • 检查我的新答案,其中我展示了如何在服务中使用自定义消息和错误代码引发 FaultException 以及如何在客户端中处理它。