简体   繁体   中英

How can I force unhandled exceptions in a WCF thread to crash the process?

So here's the scenario:

I have a WCF service that has a bunch of FaultContracts defined per operation. I would like to arrange it such that if an unhandled exception is thrown in a WCF service thread that does not match a valid FaultContract, it takes down the entire process rather than just the thread. (The reason being that I would like a crash dump that contains the information on the exception, since it didn't match the contract.)

Is there any way to do this cleanly? The main problem I have is that WCF wants to translate all my exceptions into a client-side fault in order to keep the service running; I actually want to take the entire process down, which essentially means circumventing WCF's normal behavior.

Environment.FailFast() will create a crash dump; it will not run any pending try-finally blocks nor will it run any finalizers.

You need to use IErrorHandler to customize WCF's error handling behavior. You "apply the behavior" before you call (ServiceHost).Open().

For example (look for the line that says "serviceHost.Description.Behaviors.Add(new FailBehavior());" in Main()):

class FailBehavior : IServiceBehavior
{
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
        return;
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        Console.WriteLine("The FailFast behavior has been applied.");
        var f = new FailOnError();
        foreach(ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
        {
            chanDisp.ErrorHandlers.Add(f);      
        }
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        return;
    }
}

class FailOnError : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        // this is called for every exception -- even ungraceful disconnects
        if( !(error is CommunicationException) )
            throw new TargetInvocationException( "WCF operation failed.", error );
        else
            throw new CommunicationException( "Unexpected communication problem. (see inner exception)", error );

        // Unreachable
        //return false; // other handlers should be called
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        // Can't throw from here (it will be swallowed), and using Environment.FailFast
        // will result in all crashes going to the same WER bucket. We could create
        // another thread and throw on that, but instead I think throwing from HandleError
        // should work.

        //Console.WriteLine( "Unhandled exception: {0}", error );
        //Environment.FailFast("Unhandled exception thrown -- killing server");            
    }
}

class Program
{
    static void Main( string[] args )
    {
        Console.WriteLine( "Greetings from the server." );

        Uri uri = new Uri( "net.tcp://localhost:5678/ServerThatShouldCrash" );
        using( ServiceHost serviceHost = new ServiceHost( typeof( Server ), uri ) )
        {
            Binding binding = _CreateBinding();

            serviceHost.AddServiceEndpoint( typeof( IServer ),
                                            binding,
                                            uri );
            serviceHost.Description.Behaviors.Add(new FailBehavior());
            serviceHost.Open();

            // The service can now be accessed.
            Console.WriteLine( "The service is ready." );
            Console.WriteLine( "\nPress <ENTER> to terminate service.\n" );
            Console.ReadLine();
        }
    }

    private static Binding _CreateBinding()
    {
        NetTcpBinding netTcp = new NetTcpBinding( SecurityMode.None );
        netTcp.ReceiveTimeout = TimeSpan.MaxValue;
        netTcp.ReliableSession.InactivityTimeout = TimeSpan.MaxValue;
        return netTcp;
    } // end _CreateBinding()
}
Application.Exit();

这可能会做到,但用户将失去他们当时正在做的任何事情。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM