【问题标题】:How can I determine the type of exception thrown by a asp.net web service?如何确定 asp.net Web 服务引发的异常类型?
【发布时间】:2012-02-12 16:11:59
【问题描述】:

我有一个抛出异常的 asp.NET Web 服务(不是 WCF,而是带有 WebMethods 的经典 .asmx 服务)。异常都派生自两个基本异常类之一(两者都派生自 Exception):

public class InputException : Exception
{
   ....
}

public class FatalException : Exception
{
    ....
}

public class NoFilesFound: FatalException
{
   ....
}

....

Web 服务现在根据需要抛出异常。在我的客户端代码中,我可以捕获异常并看到如下消息:

Server was unable to process request. ---> There were no files found

但是异常是 FaultException 类型(当我对捕获的异常执行 .GetType() 时可以看到)。调用客户端需要能够区分 InputException 和 FatalException(并以最佳方式区分各个派生的,但这并不重要)。现在唯一的方法是解析消息,去掉“--->”之前的文本并打开文本。这显然不是最优的。

我知道我可以使用自定义代码抛出 SoapExceptions,但我想尽可能避免这种情况。此外,它似乎是为那些处理 XML 的人设计的,但我们所有的 web 服务代码都没有触及 XML,因为它已经为我们反序列化了。

简而言之,有没有办法让我从 web 服务中抛出自定义异常,并让调用客户端能够区分这些异常?

【问题讨论】:

    标签: c# asp.net web-services exception soap


    【解决方案1】:

    处理此问题的正确方法是使用SoapException。因此,您基本上将捕获服务上所有可能的异常,然后将它们转换为 SoapException(我链接到的文档包含一个示例),然后抛出这个 SoapException 并包含您感兴趣的信息,而不是抛出您的一些自定义异常故障的详细 XML 节点。

    然后在客户端调用服务时,您将能够捕获此 SoapException 并分析 Detail XML 节点以收集有关服务器上发生故障的确切原因的更多详细信息。

    在 WCF 中,所有这些手动生成的故障节点都变得非常容易,您只需使用数据合约并捕获 FaultException<SomeFaultContract>

    让我们举个例子。假设您有以下服务方法,它会引发 SoapException 并在 Details 节点中提供有关错误的详细信息:

    [WebMethod]
    public string HelloWorld()
    {
        var doc = new XmlDocument();
        var node = doc.CreateNode(
            XmlNodeType.Element, 
            SoapException.DetailElementName.Name, 
            SoapException.DetailElementName.Namespace
        );
        // you could actually use any sub nodes here
        // and pass even complex objects
        node.InnerText = "no files found";
    
        throw new SoapException(
            "Fault occurred", 
            SoapException.ClientFaultCode, 
            Context.Request.Url.AbsoluteUri, 
            node
        );
    }
    

    使用它时,您可以在客户端捕获此 SoapException:

    using (var client = new WebService1())
    {
        try
        {
            var result = client.HelloWorld();
        }
        catch (SoapException ex)
        {
            var detail = ex.Detail;
            // detail.InnerText will contain the detail message
            // as detail is an XmlNode if on the server you have
            // provided a complex XML you would be able to fetch it here
        }
    }
    

    就您的InputExceptionFatalExceptionNoFilesFound 异常而言,它们很好,但它们应该保留在服务器上。在您的 Web 方法中捕获它们并构建适当的 SoapException,以便客户端在使用服务时能够理解。

    【讨论】:

    • 谢谢!我想知道是否可以让我的自定义类从 SoapException 派生,然后使用构造函数来构建 XmlNodes...
    • @user1079591,是的,你可以,这实际上是一个非常好的方法。
    • 所以我按照你的建议做了,但在客户端代码中它没有将其作为 SoapException 而是作为 System.ServiceModel.FaultException 捕获。在我的代码中,我有两个 catch 块:一个用于 SoapException,一个用于常规 Exception,它总是转到常规异常,当我对通用异常执行 .GetType() 时,它说它是 System.ServiceModel.FaultException 类型。
    • @user1079591,那是因为您在客户端上使用 WCF。您已经在 VS 中使用 svcutil.exeAdd Service Reference 生成了客户端代理。如果您想将其用作 asmx Web 服务,您可以使用 wsdl.exeAdd Web Reference(仅当您面向 .NET 2.0 或更早版本时可用)。
    • 啊,我明白了。事实上,我确实使用了“添加服务参考”。感谢您的捕获,我会修复它。
    猜你喜欢
    • 1970-01-01
    • 2011-03-21
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    相关资源
    最近更新 更多