Managing Exceptions in Service Host Applications


In Chapter 2, you saw how to create a host application for a WCF service and use this application to control the lifecycle of the service. A service host application uses a ServiceHost object to instantiate and manage a WCF service. The ServiceHost class implements a finite-state machine. A ServiceHost object can be in one of a small number of states, and there are well-defined rules that determine how the WCF runtime transitions a ServiceHost object from one state to another. Some of these transitions occur as the result of specific method calls, while others are caused by exceptions in the service, in the communications infrastructure, or in the objects implementing the channel stack. A service host application should be prepared to handle these transitions and attempt recovery to ensure that the service is available whenever possible.

ServiceHost States and Transitions

When you instantiate a ServiceHost object, it starts in the Created state. In this state, you can configure the object; you can use the AddServiceEndpoint method to cause the ServiceHost object to listen for requests on a particular endpoint for example. A ServiceHost object in this state is not ready to accept requests from client applications.

You start a ServiceHost object listening for requests by using the Open method (or the BeginOpen method if you are using the asynchronous programming model). The ServiceHost object moves to the Opening state while it creates the channel stacks specified by the bindings for each endpoint and starts the service. If an exception occurs at this point, the object transitions to the Faulted state. If the ServiceHost object successfully opens the communication channels for the service, it moves to the Opened state. Only in this state can the object accept requests from client applications and direct them to the service.

You stop a ServiceHost object listening for client requests by using the Close (or BeginClose) method. The ServiceHost object enters the Closing state. Currently running requests are allowed to complete, but clients can no longer send new requests to the service. When all outstanding requests have finished, the ServiceHost object moves to the Closed state. You can also stop a service by using the Abort method. This method closes the service immediately without waiting for the service to finish processing client requests. Stopping or aborting the service disposes the service object hosted by the ServiceHost object and reclaims any resources it was using. To start the service, you must recreate the ServiceHost object with a new instance of the service and then execute the Open method to reconstruct the channel stacks and start listening for requests again.

A ServiceHost object enters the Faulted state either when it fails to open correctly or if it detects an unrecoverable error in a channel used by the ServiceHost object to communicate with clients (for example, if some sort of protocol error occurs).When a ServiceHost object is in the Faulted state, you can examine the properties of the object to try and ascertain the cause of the failure, but you cannot send requests to the service. To recover the service, you should use the Abort method to close the service, recreate the ServiceHost object, and then execute the Open method again. Figure 3-1 summarizes the state transitions for a ServiceHost object, and the methods and conditions that cause the object to move between states.

image from book
Figure 3-1: State transition diagram for a ServiceHost object.

Tip 

You can determine the current state of a ServiceHost object by examining the value of its State property.

Handling Faults in a Host Application

When a ServiceHost object moves from one state to another, it can trigger an event. These events were described in Table 2-2 in Chapter 2. From an error-handling perspective, the most important of these is the Faulted event, which occurs when a ServiceHost object enters the Faulted state. You should subscribe to this event, and provide a method that attempts to determine the cause, and then abort and restart the service, like this:

 // ServiceHost object for hosting a WCF service ServiceHost productsServiceHost; productsServiceHost = new ServiceHost(…); … // Subscribe to the Faulted event of the productsServiceHost object productsServiceHost.Faulted += new EventHandler(faultHandler); … // FaultHandler method // Runs when productsServiceHost enters the Faulted state void faultHandler(object sender, EventArgs e) {     // Examine the properties of the productsServiceHost object     // and log the reasons for the fault          // Abort the service     productsServiceHost.Abort();     // Recreate the ServiceHost object     productsServiceHost = new ServiceHost();     // Start the service     productsServiceHost.Open(); }

Note 

You can use the Close method rather than Abort in the fault handler, but a service in the Faulted state will not be able to continue processing requests. Using the Abort method to close the service can reduce the time required in the FaultHandler method to restart the service.

Handling Unexpected Messages in a Host Application

One other exceptional circumstance that can arise in a host application is an unexpected message from a client. Client applications built using the WCF library typically communicate with the service by using a proxy object, generated by using the svcutil utility. The proxy object provides a strongly typed interface to the service that specifies the operations the client can request (and therefore the messages that the client sends). It is unlikely that a WCF client using correctly generated proxy object will send an unexpected message. However, remember that a WCF service is simply a service that accepts SOAP messages, and developers building client applications can use whatever means they see fit for sending these messages. Developers building Java client applications will typically use Java-specific tools and libraries for constructing and sending SOAP messages. WCF also provides a low-level mechanism that enables developers to open a channel to a service, create SOAP messages, and then send them to the service, as shown in this fragment of code:

 // Create a binding and endpoint to communicate with the ProductsService BasicHttpBinding binding = new BasicHttpBinding(); EndpointAddress address = new EndpointAddress(     "http://localhost:8000/ProductsService/ProductsService.svc"); ChannelFactory<IRequestChannel> factory = new     ChannelFactory<IRequestChannel>(binding, address); // Connect to the ProductsService service IRequestChannel channel = factory.CreateChannel(); channel.Open(); // Send a ListProducts request to the service Message request = Message.CreateMessage(MessageVersion.Soap11,     "http://tempuri.org/IProductsService/ListProducts"); Message reply = channel.Request(request); // Process the reply // (should be a SOAP message with a list of product numbers)  // Release resources and close the connection reply.Close(); channel.Close(); factory.Close();

Don’t worry too much about the details of this block of code–you will learn more about using Message and Channel objects in Chapter 10, “Programmatically Controlling the Configuration and Communications.” The key statement is the line that creates the message sent to the ProductsService service:

 Message request = Message.CreateMessage(MessageVersion.Soap11,     "http://tempuri.org/IProductsService/ListProducts");

The second parameter to the CreateMessage method specifies the action that identifies the message sent to the service. If you recall the earlier discussion in this chapter describing the use of the svcutil utility to generate the client proxy, one of the files generated contained the WSDL description of the service. The WSDL description includes the definitions of each of the operations exposed by the service, and the messages that an application sends to invoke these operations. Here is part of the WSDL describing the ListProducts operation:

 <wsdl:operation name="ListProducts">       <wsdl:input wsaw:Action="http://tempuri.org/IProductsService/ ListProducts" message="tns:IProductsService_ListProducts_InputMessage" />       … </wsdl:operation>

When the service receives a message identified by the action http://tempuri.org/IProductsService/ListProducts, it performs the ListProducts operation. If a client application sends a message specifying an action that the service does not recognize, the service host application raises the UnknownMessageReceived event. The host application can catch this event and record the unrecognized message, like this:

 // ServiceHost object for hosting a WCF service ServiceHost productsServiceHost; productsServiceHost = new ServiceHost(…); … // Subscribe to the UnknownMessageReceived event of the // productsServiceHost object productsServiceHost.UnknownMessageReceived += new     EventHandler<UnknownMessageReceivedEventArgs>(unknownMessage); … // UnknownMessageReceived event handler void  unknownMessage(object sender, UnknownMessageReceivedEventArgs e) {     // Log the unknown message     …     // Display a message to the administrator     MessageBox.Show("A client attempted to send the message " +     e.Message.Headers.Action; }

There could be a perfectly innocent explanation for a client sending a message such as this, or it could be part of a more concerted attack by a malicious user trying to probe a service and gather information about the operations it supports; remember that by default, WCF Web services do not publish their metadata, so an attacker might not have access to the WSDL description of a service.

One other possibility is that a WCF client application is using an out-of-date proxy object for sending messages to the service. If a developer modifies the service contract for a WCF service, she might change the messages that the service sends and receives. If any client applications that use the service are not updated, they might send messages that the service no longer understands. Therefore, if you update a service, you should ensure that you retain backwards compatibility with existing clients. The same issues can arise with data contracts. You will learn more about how to update data contracts for a WCF service safely in Chapter 6, “Maintaining Data Contracts and Service Contracts.”




Microsoft Windows Communication Foundation Step by Step
Microsoft Windows Communication Foundation Step by Step (Step By Step Developer Series)
ISBN: 0735623368
EAN: 2147483647
Year: 2007
Pages: 105
Authors: John Sharp

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net