|
How to use asynchronous methods
|
|
The regular, synchronous forms of the FTP operations presented through the FTPConnection
interface do not return until the operation that they're performing has been completed. If the
connection to the server is slow or if a large file is being transferred then this can result in
unacceptable performance, particularly for GUI applications and other applications where FTP
operations are performed interactively with a user. This is why ExFTPConnection (and SecureFTPConnection) provide advanced asynchronous (or background) functionality.
Most regular methods present in the FTPConnection
interface have asynchronous
counterparts. For each synchronous method, there is a corresponding pair of method of the
same name, but with Begin and End prefixes.
For example, the Connect() method
corresponds to BeginConnect() and EndConnect(). In the
following code, the Print statement is not executed until after the connection to the server has
been established.
ftpConnection.Connect();
Print("Connected");
It is common for it to take several seconds to establish a connection so, even this simple task
can result in unacceptable GUI performance.
When this is recoded using asynchronous methods, as follows:
ftpConnection.BeginConnect(new AsyncCallback(OnConnect), null);
Print("Connecting");
the BeginConnect() method does not wait for the connection to be established before
returning and allowing processing to continue. Instead, executing immediately returns to the
next instruction and the connection is established concurrently on a worker-thread. It is of
course necessary to know when the connection has been established; this is what the
AsyncCallback delegate is for. In this case, this delegate instructs ExFTPConnection to call
the method OnConnect() once the connection has been established. This method is defined
as follows:
private void OnConnect(IAsyncResult ar)
{
Print("Connected");
}
Since the Connect() operation does not return a value, there is no need to call the EndConnect() method. Some FTP operations do however return values. In such cases the EndX() method returns the value as illustrated in the following example:
ftpConnection.BeginGetSize(fileName, new AsyncCallback(OnGetSize),
ftpConnection);
.
.
.
private void OnGetSize(IAsyncResult ar)
{
SecureFTPConnection c = (SecureFTPConnection)ar.AsyncState;
long size = c.EndGetSize(ar);
Print("size = " + size + " bytes");
}
The asynchronous approach allows the developer to write a highly responsive interface that
responds instantly to user actions and provides feedback on how processing is progressing.
Queuing FTP Operations
Unlike other similar implementations, ExFTPConnection
allows multiple operations to be
queued. In other words, multiple Begin operations may be invoked without delay. They will be
processed in the order in which they're added. They will all be executed on the same thread
and the callback methods will be invoked between each operation.
Preventing Callbacks and Event-Handlers from Hanging
ExFTPConnection has been designed to make asynchronous processing and event-handling
as easy as possible, but occasionally it is necessary to understand how the processing is
performed in order to avoid problems that can be difficult to diagnose.
In a Windows Forms application all calls that update the user-interface should be executed on
one particular thread. When this rule is not adhered to .NET 1.1 will exhibit hanging behavior
and .NET 2.0 will throw InvalidOperationExceptions. Microsoft calls such cases "cross-thread
calls".
When asynchronous methods are used, ExFTPConnection
employs a worker-thread to
process FTP operations. This frees the GUI thread to continue updating the screen and
processing user inputs. However, the decision of which thread the callback should be
executed on is not clear-cut. By default, ExFTPConnection will run asynchronous callbacks
and event-handlers on the GUI thread if one is available. This is generally the most useful
since such event-handlers are often used to provide some sort of user-interface-related
action. This behavior can, however, be changed through the UseGuiThreadIfAvailable
property. If this property is set to false then asynchronous callbacks and event-handlers will
be executed on the worker-thread. This is sometimes desirable for performance reasons
since it doesn't tie up the GUI thread unnecessarily.