未处理的异常会导致WCF服务崩溃吗?

7
我想知道未处理的异常是否会导致WCF服务崩溃。我编写了以下程序,该程序显示由WCF服务启动的线程中的未处理的异常将使整个WCF服务崩溃。
我的问题是,我想确认在WCF服务启动的线程中的未处理异常是否会使WCF崩溃? 我感到困惑的是,我认为WCF应该是一个稳定的服务,不应因未处理的异常而崩溃。
我正在使用VSTS 2008 + C# + .Net 3.5开发基于自托管Windows服务的WCF服务。
以下是相关代码部分:
namespace Foo
{
    // NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in Web.config.
    [ServiceContract]
    public interface IFoo
    {
        [OperationContract]
        string Submit(string request);
    }
}

namespace Foo
{
    // NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in Web.config and in the associated .svc file.
    public class FooImpl : IFoo
    {
        public string Submit(string request)
        {
            return String.Empty;
        }
    }
}

namespace Foo
{
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
            InitializeComponent();
        }

        ServiceHost host = new ServiceHost(typeof(FooImpl));

        protected override void OnStart(string[] args)
        {
            host.Open();
            // start a thread which will throw unhandled exception
            Thread t = new Thread(Workerjob);
            t.Start();
        }

        protected override void OnStop()
        {
            host.Close();
        }

        public static void Workerjob()
        {
            Thread.Sleep(5000);
            throw new Exception("unhandled");
        }
    }
}

2
你的示例并没有显示“由WCF服务启动的线程中未处理的异常”,而是显示“由Windows服务启动的线程中未处理的异常”。这与WCF无关。 - Darin Dimitrov
我在Windows服务中启动WCF自托管(host.Open()),这意味着WCF服务中会出现未处理的异常。对于混淆的术语,我很抱歉,请问有什么评论或者回答我的问题吗? - George2
6个回答

18

服务端发生未处理的异常会导致通道(客户端和服务器之间的连接)“故障” - 即被中断。

从那时起,您将无法再使用相同的代理客户端对象实例从客户端调用 - 您必须重新创建代理客户端。

最好的方法是尽可能在服务器端处理所有错误。查看IErrorHandler接口,您应该在服务实现类上实现它,将所有未处理的.NET异常转换为SOAP故障(这不会导致通道故障),或者完全报告/吞下它们。

Marc


嗨,马克,我仔细阅读了你推荐的有关IErrorHandler的MSDN链接。有一个疑惑,我的问题中未处理的异常来自我显式启动的线程,而不是WCF操作线程。我认为IErrorHandler捕获WCF操作线程(即执行OperationContract操作的线程)中的未处理异常,由于我的线程不是WCF操作线程,所以与我的问题无关,对吗?有任何意见吗? - George2
1
你是从WCF服务器代码启动了那个线程吗?问题实际上是:如果线程崩溃会影响到你的服务器代码吗?如果导致服务器代码出现异常,那么实现IErrorHandler接口将有所帮助。 - marc_s
谢谢Marc,1. 我对“从你的WCF服务器代码启动该线程”的含义感到困惑,你能否请澄清一下?从开发者的角度来看,WCF只是一组契约,我不确定你所说的WCF服务器是什么意思。 :-) 2. 你的意思是非WCF线程中的未处理异常也会被IErrorHandler捕获吗? - George2
是的,你有契约 - 但你也必须在服务器端拥有一个实际实现该服务契约的类。这就是我所说的。你的线程是否是从服务契约的服务器端实现中创建和运行的? - marc_s

11

是的,在线程中未处理的异常会导致进程崩溃。

这个进程将会崩溃:

static void Main(string[] args)
{
    Thread t = new Thread(() =>
    {
        throw new NullReferenceException();
    });
    t.Start();
    Console.ReadKey();
}

这个不会起作用:
static void Main(string[] args)
{
    Thread t = new Thread(() =>
    {
        try
        {
            throw new NullReferenceException();
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
    });
    t.Start();
    Console.ReadKey();
}

8
WCF运行时的默认行为是吞噬所有但少数类型的异常。因此,如果您的代码将异常抛出到WCF运行时(例如,如果您从WCF操作中抛出异常),它不会使应用程序崩溃(除非它被认为是“致命”异常,例如OOM、SEHException等)。如果异常不是操作故障契约的一部分,则通道将被故障,否则不会。
如果WCF运行时不在堆栈上下文中,则异常将导致进程崩溃。
这类似于ASP.NET运行时。
如果您想以一般方式筛选WCF操作中的异常,我建议使用IOperationInvoker接口。您也可以使用IErrorHandler,但是您的IErrorHandler实现将收到其他异常的通知,而不仅仅是从“用户代码”(WCF操作)中抛出的异常,例如WCF内部I/O线程上的SocketAbortedExceptions,这些异常可能对您不感兴趣。

3

如果您不处理异常,它将传递给操作系统,并通过终止引起异常的任何应用程序来响应。

为什么不添加一个try/catch来处理异常,以便您的服务不会被终止?


只有当异常出现在主线程以外的线程中时,才会发生上述情况。请参阅Fredrik Mörk上面的示例。 - user141682
在Fredrik的示例中,有一个try/catch块来阻止异常导致进程崩溃,这正是我上面所说的。 - jussij

1
如果您没有适当的错误处理,程序将会崩溃。最好的做法是放置一个


try{//do something
}
catch{ //handle errors
}
finally{//final clean up
}

在您的代码中加入块以确保如果它抛出异常,能够优雅地处理它。示例请参见http://msdn.microsoft.com/en-us/library/fk6t46tz(VS.71).aspx

1

您可以利用FaultException将错误信息传递给客户端,并将逻辑保留在服务中。

请查看示例,希望对您有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接