WCF - asynchronous calls
Often we develop a method to perform some task and after properly coded, invoke the same from any point in the application. Depending on what this method does, it can take some time to run and, if time is considerably high, we can begin to have problems in applying, because as the call is always performed synchronously, while the method does not return, the execution of system that makes use of it will freeze, awaiting the return of the method to follow up on implementation. however, to provide a better user experience and make the performance of the very highest performing application, we choose to perform a certain task so asynchronous. This will enable the firing of a costly process in a thread work part of the application, allowing the application to continue running while the costly process runs in parallel and when it finished, we can recover the result and display the same to user. The purpose of this article is to show how to implement asynchronous processing both client side ( proxy ) and server side (contract) in WCF services. Before proceeding, we need to be familiar with the architecture of asynchronous processing within the NET platform. Basically, we have some methods within the NET Framework itself that there are 3 versions for the same: the first is to use synchronous; since the other two ( BeginXXX andEndXXX ) are for asynchronous call this same process. Was agreed that synchronous methods are named according to their functionality, eg Read , Write ; have the asynchronous versions of these same methods are:BeginRead , EndRead , BeginWrite and EndWrite . ADO.NET version 2.0 now also includes support for asynchronous processing common data access tasks, such as running queries complex for modification of records in the database and also when we need to recover data with some query more complex (more details can be seenin this article ). Support for asynchronous process does not stop there, access to files on disk, access to services and even the delegates bring this support natively. Asynchronous Processing in Client In this scenario, you need nothing be done during the creation and implementation of the contract. This works very similarly to what has happened with Articles ASP.NET Web Services, ie, for each method created in the contract form, it also created an asynchronous version ( BeginXXX and EndXXX ) method when we make reference to the service at the client . Here there is a slight change: the asynchronous methods that provide support are not implicitly created.The image below illustrates the location that we set to mark the creation of methods that support asynchronous process:
![]() |
Figure 1 - When making an Add Service Reference , click the option Advanced to select the option that is highlighted in red. |
By default, this option is not checked. Once you choose to mark it, an asynchronous version will be created for each method that is within the contract. Thereafter the developer who consume the proxy service will need to be alert to make the call to the method asynchronously, which will require the form in which the call is executed.When it is an asynchronous process, we have some care about the shooting of the method: the method that starts the process ( BeginXXX ) usually waits for the required task execution parameters (if any), an instance of adelegate of type AsyncCallback (explored below) and finally an object that represents a "contextual" information.Note: The option "Generate asynchronous operations" is the same as specifying the parameter / async utilitysvcutil.exe . To illustrate, we have a contract called ICliente that has a method called CalcularComissao which, in turn, returns a value which represents the calculated value of the commissions. This task it is a process that, for purposes of example, will be seen as a costly task and it will take some time to run. The code below shows the contract to be used (note that there is nothing special):
using System;
using System.ServiceModel;
[ServiceContract]
public interface ICliente
{
[OperationContract]
CalcularComissao decimal (string code);
}
|
Once added to the reference, we note that there are three methods available to us from the client side:CalcularComissao for synchronous process, BeginCalcularComissao and EndCalcularComissao for asynchronous processing. When generating the proxy method BeginXXX is decorated with the attributeOperationContractAttribute which, in turn, has a property called AsyncPattern and in this case, is set to True . With this configuration, the runtime will not invoke the method BeginCalcularComissao the contract, if only because it does not exist; actually the runtime will use a thread from the ThreadPool to synchronously trigger the method defined by the property Action and, in this case the method is CalcularComissao . 'll assume that the call to the method synchronously is already known and is sedimented. The focus here is to understand the operation of an asynchronous process. The starting point is the method BeginCalcularComissao : he shall initiate the process and, in addition to receiving the callback and the object as a parameter (as stated above), this method also expects the parameters to the method itself requires to perform the task which it was intended to do. Following processing architecture asynchronous NET Framework, the method BeginCalcularComissoes returns an object that implements the IAsyncResult interface ; This object stores a reference to the process that is running in parallel. As we have noted, is not the method BeginXXX that returns the result. This is a task that belongs exclusively to the method EndXXX . The question is when to invoke it. Once you invoke the same, and the process has not yet been finalized, the program crashes running, waiting for the return process. Depending on how much time is remaining to finalize, we fall into the same problem of synchronous processing. The following code snippet illustrates how to consume the method BeginCalcularComissoes :
using (proxy = new ClienteClient ClienteClient ())
{
IAsyncResult ar = proxy.BeginCalcularComissao ("123", null, null);
// Do some work
decimal result = proxy.EndCalcularComissao (air);
Console.WriteLine (result);
}
|
In the above example we can have some benefit, since the method BeginCalcularComissao triggers the asynchronous processing and longer returns the execution control to the program and, therefore, allows us to do some work in parallel while the service calculates commissions. The problem is that at the time of the method callEndCalcularComissao (which returns the result) the process is not yet finished, execution will block execution until the asynchronous process to return. Remember that this technique is sometimes necessary: imagine a time when the program can not continue its execution, it depends on the result of the asynchronous process to continue. Yet another possibility to test the return of the asynchronous process, which is called of pooling . This technique consists in before invoking the method EndCalcularComissao and possibly block the execution, we can test whether or not the process finished. If we look at the example code above, the method BeginCalcularComissaoreturns an object that implements the IAsyncResult interface . This interface provides a method calledIsCompleted that returns a boolean value indicating whether or not the process was finalized. This will ensure that the method call EndCalcularComissao only that the process actually finished. The code below illustrates the use of this property:
using (proxy = new ClienteClient ClienteClient ())
{
IAsyncResult ar = proxy.BeginCalcularComissao ("123", null, null);
// Do some work
if (ar.IsCompleted)
{
decimal result = proxy.EndCalcularComissao (air);
Console.WriteLine (result);
}
else
{
Console.WriteLine ("The process has not finished.");
}
}
|
Finally, the last technique we have to shoot a method is asynchronously with the use of callbacks . With this alternative, instead of continuing to testing whether or not the process finished by invoking the methodBeginCalcularComissao , pass an instance of the class AsyncCallback with reference to a method on the client side that must be shot with the asynchronous process is finalized. A time specified the method that will be used as acallback , is no longer required that you store the object that stores a reference to the asynchronous process (IAsyncResult ), as this is automatically provided to the callback ; Furthermore, it is also important to say that the method callback runs under the thread of work before it is returned to the ThreadPool . As already mentioned above, we report the method to be fired from an instance of the AsyncCallback delegate , as shown in the code below:
private static ClienteClient _Proxy;
private static void TestandoProcessoAssincronoComCallback ()
{
_Proxy ClienteClient = new ();
_proxy.BeginCalcularComissao ("123", new AsyncCallback (Callback), null);
Console.ReadLine ();
}
private static void Callback (IAsyncResult ar)
{
decimal result = _proxy.EndCalcularComissao (air);
Console.WriteLine (result);
}
|
Note: We can resort to using anonymous methods or even expressions of lambda to avoid creating a method share to be triggered when the callback . happen Besides the traditional model of asynchronous calls (APM), we have the possibility of asynchronous call based events. The idea here is, before invoking the operation, you can subscribe to an event that will be triggered only when the asynchronous process is complete. This will avoid having a manual job to analyze whether the process ended or not ( poll , waiting , etc.). Internally during the generation of the proxy , the code that is auto-generated already includes the necessary for the event-based model implementation. Basically it created another version of the method, now with the suffix XXXAsync that internally makes a call to the methods BeginXXX / EndXXX that, as we already know, fired the operation asynchronously. Additionally, a delegate of type EventHandler <T> will also be created to represent the callbackthat, when triggered, will invoke the event side of who is consuming the service. Below an example of how to make event-based asynchronous call:
using (proxy = new ClienteClient ClienteClient ())
{
proxy.CalcularComissaoCompleted + =
new EventHandler <CalcularComissaoCompletedEventArgs> (proxy_CalcularComissaoCompleted);
proxy.CalcularComissaoAsync ("2");
Console.ReadLine ();
}
private static void proxy_CalcularComissaoCompleted (object sender,
And CalcularComissaoCompletedEventArgs)
{
Console.WriteLine ("End.");
}
|
If we notice the internal implementation of the proxy , we see that the method XXXAsync makes use of the method InvokeAsync , class ClientBase <T> . This method is available only from the NET Framework 3.5. Thus, some details while generating the proxy must be analyzed:
- Via "Add Service Reference": If you are making reference to a project that is using the NET Framework 3.5 and you opt for the generation of methods that support asynchronous processing, it will also create the types needed to support the event model .
- Svcutil.exe Via: in this case you need to specify through the parameter / async , and furthermore, specify the version of NET Framework through the parameter / targetClientVersion , pointing Version30 or if you want to use the event-based model, using the option Version35 .
Asynchronous Processing in Server
Everything we saw above is to allow the client that consumes the service run method asynchronously, avoiding the application is not blocked while the method is executing. From now on we will examine how to implement asynchronous processing on the server. This will consist of a considerable change in the contract of service and that we will see below. purpose of the asynchronous process on the server side is to increase the scalability and performance without affecting clients that consume the service. Importantly, asynchronous processes client-side and server-side work independently, seeking totally different benefits. The idea of asynchronous processing on the server side is mainly aimed at performing tasks that have a high cost for implementation and some common cases, consultations are to some information in the database, reading / writing files to disk, etc. This will allow the release of the thread that is running the service is released while the costly process happens in parallel, allowing you to perform some task in parallel while the process takes place or not even have threads being blocked while waiting for this processing. Again, you can combine this feature asynchronous processing techniques that already exist within the NET Framework, such as the ADO.NET 2.0 classes IO namespace , etc. For example, we simulate a costly process in the database. As already said above, the contract of the service change. We will need to design it to fit the pattern of asynchronous processing NET Framework which, as we know, for each method, we have actually a pair where the first corresponds to the beginning of the execution ( BeginXXX ) and the second corresponds to end processing ( EndXXX ). The code below illustrates how to proceed to define these methods:
Everything we saw above is to allow the client that consumes the service run method asynchronously, avoiding the application is not blocked while the method is executing. From now on we will examine how to implement asynchronous processing on the server. This will consist of a considerable change in the contract of service and that we will see below. purpose of the asynchronous process on the server side is to increase the scalability and performance without affecting clients that consume the service. Importantly, asynchronous processes client-side and server-side work independently, seeking totally different benefits. The idea of asynchronous processing on the server side is mainly aimed at performing tasks that have a high cost for implementation and some common cases, consultations are to some information in the database, reading / writing files to disk, etc. This will allow the release of the thread that is running the service is released while the costly process happens in parallel, allowing you to perform some task in parallel while the process takes place or not even have threads being blocked while waiting for this processing. Again, you can combine this feature asynchronous processing techniques that already exist within the NET Framework, such as the ADO.NET 2.0 classes IO namespace , etc. For example, we simulate a costly process in the database. As already said above, the contract of the service change. We will need to design it to fit the pattern of asynchronous processing NET Framework which, as we know, for each method, we have actually a pair where the first corresponds to the beginning of the execution ( BeginXXX ) and the second corresponds to end processing ( EndXXX ). The code below illustrates how to proceed to define these methods:
using System;
using System.ServiceModel;
[ServiceContract]
public interface ICliente
{
[OperationContract (AsyncPattern = true)]
IAsyncResult BeginRecuperar (AsyncCallback callback, object state);
Customer [] EndRecuperar (IAsyncResult ar);
}
|
The above code illustrates exactly the steps you must follow to enable asynchronous call by WCF. The methods we want are invoked asynchronously by WCF should, instead of having only a single method to accomplish the task, we must divide them into two parts (methods): BeginXXX and EndXXX . Importantly, only the method BeginXXXwill be decorated with the attribute OperationContractAttribute , setting the property AsyncPattern to True . Still following the standard asynchronous processing .NET Framework, the method Begin should receive as parameter an object of type AsyncCallback (who later point to the method EndXXX ) and an Object , returning an object that implements the IAsyncResult interface . Already method EndXXX should effectively return information that the method is intended to do and, as a parameter, should be an object that implements the IAsyncResult interface .above When the contract is exposed by WCF and a client consume it, just have a single method called Recover .As said earlier, the idea here is to prevent the client know how it is implemented within the service. In this case, it makes sense you have "a synchronous version of the method" and, if so, by default, WCF will always use it. Once the contract is defined, we must implement it in class and consequently expose the same to be consumed.Implementation of Interface ICliente like any other that requires asynchronous processing, requires caution at deployment time compared to traditional format. As we are using ADO.NET 2.0 and it already brings natively support asynchronous execution of queries asynchronously, we can integrate it running:
using System;
using System.Threading;
using System.Data.SqlClient;
using System.Collections.Generic;
public class ServicoDeClientes: ICliente
{
private const string SQL_CONN_STRING = "...; Asynchronous Processing = True";
private SqlConnection _Connection;
private SqlCommand _command;
public IAsyncResult BeginRecuperar (AsyncCallback callback, object state)
{
this._connection = new SqlConnection (SQL_CONN_STRING);
this._command = new SqlCommand ("SELECT Name FROM Customer", this._connection);
this._connection.Open ();
return this._command.BeginExecuteReader (callback, state);
}
public Customer [] EndRecuperar (IAsyncResult ar)
{
List <Customer> result = new List <Customer> ();
using (this._connection)
using (this._command)
using (SqlDataReader dr = this._command.EndExecuteReader (air))
while (dr.Read ())
resultado.Add (new Customer () {Name = dr.GetString (0)});
resultado.ToArray return ();
}
}
|
In the method that starts the process opened the connection to the database, inform the query and finally invoke the method BeginExecuteReader passing the callback and the object that is passed as a parameter to the methodBeginRecuperar . Finally, the method EndRecuperar is invoked through it and collect the result of running the cumbersome process, prepare the same and return. This is the result that will be forwarded to the customer. code client-side changes nothing. Regardless of the implementation that you use server-side, client-side nothing will change, ie, even if you create two methods ( Begin and End ) to compose asynchronous processing, WCF always provide a unique method for the customer. He can invoke it synchronously or asynchronously. Conclusions: In this paper we understand how to integrate asynchronous processing in WCF services. You can perform this technique on both sides (client and server), but it is important to remember that they work independently which, although similar, have completely different purpose and, thus, need to understand the context and apply the implementation ideal.
Comments
Post a Comment