Accessing Services Using a Client
Client applications must create, configure, and use WCF client or channel objects to communicate with services. The WCF Client Overview topic provides an overview of the objects and steps involved in creating basic client and channel objects and using them.
This topic provides in-depth information about some of the issues with client applications and client and channel objects that may be useful depending upon your scenario.
This topic describes behavior and issues relating to:
Channel and session lifetimes.
Understanding blocking issues.
Initializing channels interactively.
Channel and Session Lifetimes
Windows Communication Foundation (WCF) applications includes two categories of channels, datagram and sessionful.
A datagram channel is a channel in which all messages are uncorrelated. With a datagram channel, if an input or output operation fails, the next operation is typically unaffected, and the same channel can be reused. Because of this, datagram channels typically do not fault.
Sessionful channels, however, are channels with a connection to the other endpoint. Messages in a session on one side are always correlated with the same session on the other side. In addition, both participants in a session must agree that the requirements of their conversation were met for that session to be considered successful. If they cannot agree, the sessionful channel may fault.
Open clients explicitly or implicitly by calling the first operation.
|Trying to explicitly detect faulted sessionful channels is not typically useful, because when you are notified depends upon the session implementation. For example, because the System.ServiceModel.NetTcpBinding (with the reliable session disabled) surfaces the session of the TCP connection, if you listen to the System.ServiceModel.ICommunicationObject.Faulted event on the service or the client you are likely to be notified quickly in the event of a network failure. But reliable sessions (established by bindings in which the System.ServiceModel.Channels.ReliableSessionBindingElement is enabled) are designed to insulate services from small network failures. If the session can be reestablished within a reasonable period of time, the same binding—configured for reliable sessions—might not fault until the interruption continued for a longer period of time.|
Most of the system-provided bindings (which expose channels to the application layer) use sessions by default, but the System.ServiceModel.BasicHttpBinding does not. For more information, see Using Sessions.
The Proper Use of Sessions
Sessions provide a way to know if the entire message exchange is complete, and if both sides considered it successful. It is recommended that a calling application open the channel, use it, and close the channel inside one try block. If a session channel is open, and the System.ServiceModel.ICommunicationObject.Close method is called once, and that call returns successfully, then the session was successful. Successful in this case means that all delivery guarantees the binding specified were met, and the other side did not call System.ServiceModel.ICommunicationObject.Abort on the channel before calling Close.
The following section provides an example of this client approach.
Handling exceptions in client applications is straightforward. If a channel is opened, used, and closed inside a try block, then the conversation has succeeded, unless an exception is thrown. Typically, if an exception is thrown the conversation is aborted.
|Use of the using statement (Using in Visual Basic) is not recommended. This is because the end of the using statement can cause exceptions that can mask other exceptions you may need to know about. For more information, see Avoiding Problems with the Using Statement.|
The following code example shows the recommended client pattern using a try/catch block and not the using statement.
Imports System Imports System.ServiceModel Imports System.ServiceModel.Channels Imports Microsoft.WCF.Documentation Public Class Client Public Shared Sub Main() ' Picks up configuration from the config file. Dim wcfClient As New SampleServiceClient() Try ' Making calls. Console.WriteLine("Enter the greeting to send: ") Dim greeting As String = Console.ReadLine() Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting)) Console.WriteLine("Press ENTER to exit:") Console.ReadLine() ' Done with service. wcfClient.Close() Console.WriteLine("Done!") Catch timeProblem As TimeoutException Console.WriteLine("The service operation timed out. " & timeProblem.Message) Console.ReadLine() wcfClient.Abort() Catch greetingFault As FaultException(Of GreetingFault) Console.WriteLine(greetingFault.Detail.Message) Console.ReadLine() wcfClient.Abort() Catch unknownFault As FaultException Console.WriteLine("An unknown exception was received. " & unknownFault.Message) Console.ReadLine() wcfClient.Abort() Catch commProblem As CommunicationException Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace) Console.ReadLine() wcfClient.Abort() End Try End Sub End Class
|Checking the value of the System.ServiceModel.ICommunicationObject.State property is a race condition and is not recommended to determine whether to reuse or close a channel.|
Datagram channels never fault even if exceptions occur when they are closed. In addition, non-duplex clients that fail to authenticate using a secure conversation typically throw a System.ServiceModel.Security.MessageSecurityException. However if the duplex client using a secure conversation fails to authenticate, the client receives a System.TimeoutException instead.
For more complete information about working with error information at the application level, see Specifying and Handling Faults in Contracts and Services. Expected Exceptions describes expected exceptions and shows how to handle them. For more information about how to handle errors when developing channels, see Handling Exceptions and Faults.
Client Blocking and Performance
When an application synchronously calls a request-reply operation, the client blocks until a return value is received or an exception (such as a System.TimeoutException) is thrown. This behavior is similar to local behavior. When an application synchronously invokes an operation on a WCF client object or channel, the client does not return until the channel layer can write the data to the network or until an exception is thrown. And while the one-way message exchange pattern (specified by marking an operation with System.ServiceModel.OperationContractAttribute.IsOneWay set to true) can make some clients more responsive, one-way operations can also block, depending upon the binding and what messages have already been sent. One-way operations are only about the message exchange, no more and no less. For more information, see One-Way Services.
Large data chunks can slow client processing no matter what the message exchange pattern. To understand how to handle these issues, see Large Data and Streaming.
If your application must do more work while an operation completes, you should create an asynchronous method pair on the service contract interface that your WCF client implements. The easiest way to do this is to use the /async switch on the ServiceModel Metadata Utility Tool (Svcutil.exe). For an example, see How to: Call WCF Service Operations Asynchronously.
For more information about increasing client performance, see Middle-Tier Client Applications.
Enabling the User to Select Credentials Dynamically
The IInteractiveChannelInitializer interface enables applications to display a user interface that enables the user to choose credentials with which a channel is created before the timeout timers start.
Application developers can make use of an inserted IInteractiveChannelInitializer in two ways. The client application can call either System.ServiceModel.ClientBase.DisplayInitializationUI or System.ServiceModel.IClientChannel.DisplayInitializationUI (or an asynchronous version) prior to opening the channel (the explicit approach) or call the first operation (the implicit approach).
If using the explicit approach, the application must perform the following steps in order:
Call either System.ServiceModel.ClientBase.DisplayInitializationUI or System.ServiceModel.IClientChannel.DisplayInitializationUI (or an asynchronous version).
When the initializers have returned, call either the Open method on the IClientChannel object or on the IClientChannel object returned from the System.ServiceModel.ClientBase.InnerChannel property.
It is recommended that production-quality applications control the user-interface process by adopting the explicit approach.
Applications that use the implicit approach invoke the user-interface initializers, but if the user of the application fails to respond within the send timeout period of the binding, an exception is thrown when the user interface returns.
TasksHow to: Access WCF Services with One-Way and Request-Reply Contracts
How to: Access Services with a Duplex Contract
How to: Access a WSE 3.0 Service with a WCF Client
How to: Use the ChannelFactory
How to: Call WCF Service Operations Asynchronously
Middle-Tier Client Applications