C# 在 Web 服务中抛出异常时隐藏堆栈跟踪?

C# hide stacktrace when throwing exception in web service?

提问人:AngryOtter 提问时间:2/23/2023 更新时间:5/16/2023 访问量:744

问:

我有一个旧的网络服务,在某些情况下会抛出异常。但是,目前,异常将包括 stacktrace(path、method name 等)。我创建了一个自定义异常并覆盖了 StackTrace 属性以试图隐藏它。

简化示例:

    [WebMethod]
    public List<Object> GetISShipments(string userToken)
    {
        User user = GetUserFromToken(userToken);
        try
        {
            if (!user.CountryList.Contains("IS"))
            {
                throw new ServiceException($"Access denied for country");
            }
        }catch(Exception ex)
        {
            throw;
        }

        return new List<Object>();
    }

我试图像这样覆盖异常

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

[Serializable]
public class ServiceException : Exception
{
    public ServiceException() { }
    public ServiceException(string message) : base(message) { } 
    public ServiceException(string message, Exception innerException) : base(message, innerException) { }
    public ServiceException(SerializationInfo info, StreamingContext context) : base(info, context) { }

    public override string StackTrace
    {
        get { return String.Empty; }
    }
}

我有的问题

使用浏览器直接在 Visual Studio 中调用 Web 服务时,异常处于隐藏状态。但是,当我尝试使用SoapUI调用它时,我仍然收到stacktrace的异常。

HTTP/1.1 500 Internal Server Error
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcR0RJVCBUZW1wXERlc2t0b3BcTmV3RUZUU1xFRlRTXEVmdHNXZWJTZXJ2aWNlc1xDb250aW5nZW5jeVNoaXBtZW50cy5hc214?=
X-Powered-By: ASP.NET
Date: Wed, 22 Feb 2023 18:21:41 GMT
Content-Length: 688

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>System.Web.Services.Protocols.SoapException: Server was unable to process request. ---&gt; ServiceException: Access denied for country
   at myNameSpace.MyClass.GetISShipments(String userToken) in C:\Users\myUser\Desktop\NewProject\Project\MyWebServices\App_Code\ContingencyShipments.cs:line 66
   --- End of inner exception stack trace ---</faultstring><detail /></soap:Fault></soap:Body></soap:Envelope>

其他资讯

.Net 版本:4

我知道将响应包装到带有错误消息的响应对象中比返回类对象本身要好。但是,这是一个非常旧的 Web 服务,我的客户使用了很多旧进程。因此,我试图找到一种方法来实现这一目标,而无需我的客户改变任何事情。

那么有没有办法实现这一目标呢?

C# asp.net .NET Web 服务

评论

1赞 Sebastian S. 2/23/2023
添加一个异常处理程序并返回一个异常对象,其中包含例如错误消息。
0赞 AngryOtter 2/23/2023
@SebastianS。你能详细说明一下吗?我确实解释说,我试图在不更改返回类型的情况下隐藏堆栈跟踪,因此使用此 Web 服务的客户端不需要更改任何内容。请随时发布答案。
0赞 Sebastian S. 2/23/2023
对不起,我已经过度阅读了您无法更改响应类型的事实。

答:

0赞 itsdaniel0 2/23/2023 #1

如果你看一下抛出的错误,它实际上说了以下内容。End of inner exception stack trace

堆栈跟踪来自 ,而不是您的自定义异常。因此,尽管您已经重写了 StackTrace,但您只对顶级异常进行了重写。InnerException

您可以重写该方法以仅显示所需的信息.ToString()

[Serializable]
public class ServiceException : Exception
{
    public ServiceException() { }
    public ServiceException(string message) : base(message) { } 
    public ServiceException(string message, Exception innerException) : base(message, innerException) { }
    public ServiceException(SerializationInfo info, StreamingContext context) : base(info, context) { }

    public override string ToString()
    {
        // Return anything you need here
        return Message;
    }
}

评论

0赞 Volkan 2/23/2023
全局异常中间件可以改变这种行为吗?如果是这样,我会建议: nuget.org/packages/Tore.Service.GlobalExceptionMiddleware 来源@: github.com/IVTore/Tore.Service.GlobalExceptionMiddleware
1赞 itsdaniel0 2/23/2023
该包看起来只是捕获异常并将信息写出到控制台。对于中间件来说,这有点奇怪,因为没有控制台的概念。不过,它可能会根据 OP 用例解决问题
0赞 Volkan 2/23/2023
您可以分配一个静态异步方法,用于接收 httpcontext 和异常以生成响应。Delegate 是公共委托 Task ExceptionResponderDelegate( HttpContext context, Exception exception );变量为:public static ExceptionResponderDelegate ExceptionResponder;预期形式为: public static async Task MyStaticExceptionResponder(HttpContext context, Exception exception) { // 执行 }
0赞 Volkan 2/23/2023
“对于中间件来说,这有点奇怪,因为没有控制台的概念。这很奇怪。它是一种魅力。最好看看解释和来源,每个都很短。我认为它对您来说也可能是一个方便的工具。非常感谢您的友好回答。
0赞 AngryOtter 2/23/2023
即使在覆盖仅返回 Message 的 ToString() 之后,我也收到具有相同内部堆栈跟踪的错误。
0赞 Kevin Birdwell 2/23/2023 #2

您可以改为抛出具有 null 详细信息的 SoapException,然后堆栈跟踪将不会显示。

[WebMethod]
public List<Object> GetISShipments(string userToken)
{
    User user = GetUserFromToken(userToken);
    if (!user.CountryList.Contains("IS"))
    {
        throw new SoapException(message: "Access denied for country", code: SoapException.ServerFaultCode, actor: Context.Request.Url.AbosoluteUri, detail: null);
    }

    return new List<Object>();
}
0赞 AngryOtter 5/16/2023 #3

实际上没有一个好的方法可以做到这一点。我最终使用了 @Sebastian S. 的建议并重写了整个网络服务......

public class ShipmentError
{
    public string DocumentNumber;
    public string ErrorMessage;

    public ShipmentError() { }

    public ShipmentError(string documentNumber, string message)
    {
        this.DocumentNumber = documentNumber;
        this.ErrorMessage = message;
    }
}
public class ShipmentResponse
{
    public int SuccessfulDataCount { get; set; }
    public List<ShipmentError> Errors { get; set; } = new List<ShipmentEventNotificationError>();
    public WebServiceStatus Status { get; set; }
}