为什么 IIS 会在循环构造函数上给出广泛的“502.3 - Bad Gateway”错误

Why does IIS give a broad "502.3 - Bad Gateway" error on circular constructors

我明白为什么代码 不能工作 。我不明白是什么技术原因造成的,所以我们没有收到更明确的错误消息。

在开发 netcore2 应用程序时,我最终使用构造函数进行了循环引用。我的意思是 class A 的构造函数实例化了另一个 B 类型的对象,该对象本身将实例化 A 类型的对象,依此类推。

这是一个简单的代码片段,用于重现循环实例化,它在 online compiler 上抛出一个 WhosebugException 我在上面做了那个例子。

public class A
{
    public A()
    {
        var b = new B();
    }
}

public class B
{
    public B()
    {
        var b = new B();
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var a = new A();
    }
}

令人惊讶的是,IIS 在应用程序崩溃之前给我的不是 Whosebug 异常而是 502.3 - Bad Gateway 错误,它没有提供有关潜在问题的太多信息。我希望像这样的循环调用是一种足够容易检测到的模式,不仅可以被编译器捕获,甚至可以被 VisualStudio 2017 或 Resharper ultimate 指出,但没有任何警告我。

this article as well as this one 似乎表明问题可能是超时,但似乎不太可能,因为应用程序会在不到两秒的时间内崩溃。

我只是不明白为什么没有 CircularConstructionException - 这听起来很容易实现,更糟糕的是,为什么 IIS 不像在线编译器那样抛出常规 WhosebugException

我认为正确答案是它是 C# 的设计决定。在您的案例中,其他异常被捕获并包装在异常页面中,WhosebugException 导致进程终止,这是报告 502.3 响应(报告连接失败)的原因。


来自 WhosebugExceptions 上的 MSDN 页面:

In prior versions of the .NET Framework, your application could catch a WhosebugException object (for example, to recover from unbounded recursion). However, that practice is currently discouraged because significant additional code is required to reliably catch a stack overflow exception and continue program execution.

Starting with the .NET Framework version 2.0, a WhosebugException object cannot be caught by a try-catch block and the corresponding process is terminated by default. Consequently, users are advised to write their code to detect and prevent a stack overflow. For example, if your application depends on recursion, use a counter or a state condition to terminate the recursive loop. Note that an application that hosts the common language runtime (CLR) can specify that the CLR unload the application domain where the stack overflow exception occurs and let the corresponding process continue. For more information, see ICLRPolicyManager Interface and Hosting the Common Language Runtime.

这个class调用自己无限时间导致堆栈溢出

public class B
{
    public B()
    {
        var b = new B();
    }
}

I simply don't understand why there is no CircularConstructionException - this sounds easy enough to implement

在 运行 时间,关于一个对象实例化另一个对象(即使是相同类型的对象)没有任何违法行为。问题是你没有正确控制堆栈,所以 WhosebugException 实际上是合适的。在这种情况下,编译器可以检测到问题,但这仍然不是 运行时间异常。

and even worse, why isn't IIS throwing a regular WhosebugException like the online compiler ?

IIS大概不知道为什么死了。它为 运行 您的应用程序创建一个工作进程;该进程由于堆栈溢出而死亡。然后 IIS 主机进程返回一个错误,表明工作进程失败。也许 "Bad Gateway" 不是最清楚的,但 IIS 主机对堆栈溢出一无所知。它只知道它的工作进程没有响应或死了。