如何处理WCF中的传输与通信级异常?除FaultException/FaultContract外还有其他方法吗?
Great question! When dealing with transport and communication-level exceptions in WCF beyond FaultException and FaultContract, there are several targeted approaches you can use depending on whether you're working on the server or client side. Let's break them down clearly:
Server-Side Approaches
1. Implement the IErrorHandler Interface
This is the go-to extension point for global exception handling on the WCF server. It lets you catch all unhandled exceptions (including transport/communication ones like CommunicationException), log them, and even customize fault messages if needed—no FaultContract required.
Here's a straightforward implementation example:
public class GlobalErrorHandler : IErrorHandler { public bool HandleError(Exception error) { // Log the exception (use your preferred logging framework here) Console.WriteLine($"Server encountered a communication error: {error.Message}"); return true; // Mark the error as handled to prevent further propagation } public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { // Customize the fault message for communication-specific errors if (error is CommunicationException) { fault = Message.CreateMessage(version, "", "A network or communication error occurred on the server."); } } }
To register this handler, you’ll need to wrap it in a service behavior and add it to your service configuration:
public class ErrorHandlerBehavior : BehaviorExtensionElement, IServiceBehavior { public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { var errorHandler = new GlobalErrorHandler(); foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) { dispatcher.ErrorHandlers.Add(errorHandler); } } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } public override Type BehaviorType => typeof(ErrorHandlerBehavior); protected override object CreateBehavior() => new ErrorHandlerBehavior(); }
Then add it to your app.config/web.config:
<system.serviceModel> <extensions> <behaviorExtensions> <add name="errorHandler" type="YourNamespace.ErrorHandlerBehavior, YourAssemblyName"/> </behaviorExtensions> </extensions> <behaviors> <serviceBehaviors> <behavior> <errorHandler/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
2. Use ServiceHost Events
The ServiceHost exposes events that let you catch communication-level issues directly. For example, the Faulted event triggers when a service channel enters an unusable faulted state (common with transport errors):
var serviceHost = new ServiceHost(typeof(YourService)); serviceHost.Faulted += (sender, e) => { Console.WriteLine("Service host faulted due to a communication error."); // Clean up and restart the host if needed serviceHost.Abort(); serviceHost.Open(); }; serviceHost.Open();
Client-Side Approaches
1. Catch Specific Communication Exception Subtypes
On the client, you can directly target subclasses of CommunicationException that correspond to transport/network issues. These include:
EndpointNotFoundException: Thrown when the client can’t locate the service endpointTimeoutException: Thrown when a request exceeds transport-level timeoutsCommunicationObjectFaultedException: Thrown when the client channel is in a faulted stateSocketException: Low-level network errors (wrapped underCommunicationException)
Example client error handling:
using (var serviceClient = new YourServiceClient()) { try { serviceClient.YourServiceMethod(); } catch (EndpointNotFoundException ex) { Console.WriteLine($"Could not reach the service: {ex.Message}"); // Notify user or check endpoint configuration } catch (TimeoutException ex) { Console.WriteLine($"Request timed out: {ex.Message}"); // Implement retry logic if appropriate } catch (CommunicationObjectFaultedException ex) { Console.WriteLine($"Client channel is unusable: {ex.Message}"); // Create a new client instance since the current one is faulted } catch (CommunicationException ex) { // Catch-all for other communication-related errors Console.WriteLine($"General communication error: {ex.Message}"); } }
2. Implement IClientMessageInspector
This client-side extension lets you intercept messages before sending and after receiving, allowing you to detect communication issues during the message exchange. For example:
public class ClientMessageInspector : IClientMessageInspector { public void AfterReceiveReply(ref Message reply, object correlationState) { if (reply.IsFault) { var fault = MessageFault.CreateFault(reply, int.MaxValue); if (fault.HasDetail && fault.Detail is CommunicationException) { Console.WriteLine("Communication error detected in server reply."); } } } public object BeforeSendRequest(ref Message request, IClientChannel channel) { // Check channel health before sending a request if (channel.State != CommunicationState.Opened) { Console.WriteLine("Client channel is not open - resetting..."); channel.Abort(); channel.Open(); } return null; } }
To register this inspector, attach it to your client’s endpoint behavior:
var serviceClient = new YourServiceClient(); serviceClient.Endpoint.Behaviors.Add(new ClientMessageInspectorBehavior()); // Helper behavior class public class ClientMessageInspectorBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new ClientMessageInspector()); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
Quick Reminder
Communication-level exceptions often leave client channels in a faulted state—you’ll need to abort and recreate the channel if you want to make subsequent calls to the service.
内容的提问来源于stack exchange,提问作者Chealsea

