|
En primer lugar, consideraremos los métodos Web de
Microsoft® ASP.NET síncronos normales. La respuesta para un
método Web síncrono se envía cuando se devuelve desde el
método. Si una solicitud lleva un período de tiempo
relativamente prolongado en completarse, el subproceso que
esté procesando la solicitud se encontrará en uso hasta que
finalice la llamada al método. Desafortunadamente, la mayor
parte de llamadas prolongadas se deben, por ejemplo, a
consultas extensas a la base de datos, o quizás a una llamada
a otro servicio Web. Por ejemplo, si realiza una llamada a la
base de datos, el subproceso actual espera a que se complete
dicha llamada. El subproceso espera simplemente sin hacer nada
hasta que recibe una respuesta de la consulta. Surgen
problemas similares cuando un subproceso espera a que finalice
una llamada a un socket TCP o a un servicio Web del servidor.
Los subprocesos en espera son problemáticos, sobre todo en
situaciones de sobrecarga en servidores. Los subprocesos en
espera no hacen nada productivo, como dar servicio a otras
solicitudes. Lo que necesitamos es una forma de iniciar un
proceso extenso en segundo plano en un servidor, pero devolver
el subproceso actual al grupo de procesos de ASP.NET. A
continuación, cuando finalice el proceso extenso en segundo
plano, deberíamos invocar una función de devolución de llamada
para que podamos finalizar el procesamiento de la solicitud y,
de alguna manera, señalar la finalización de la solicitud a
ASP.NET. Resulta que esta función proviene de ASP.NET con
métodos Web asíncronos.
Funcionamiento de los métodos Web
asíncronos
Cuando se escribe un servicio Web ASP.NET típico utilizando
métodos Web, Microsoft® Visual Studio® .Net simplemente
compila el código para crear el ensamblado que se llamará
cuando se reciban solicitudes para sus métodos Web. El
ensamblado mismo no tiene por qué saber nada acerca de SOAP.
Por lo tanto, cuando se inicie la aplicación por primera vez,
el controlador de ASMX debe reflejarse sobre el ensamblado
para determinar qué métodos Web se exponen. Para solicitudes
síncronas normales, es sólo cuestión de buscar los métodos con
un atributo WebMethod asociado y de establecer la
lógica para llamar al método apropiado basándose en el
encabezado HTTP SOAPAction.
Para solicitudes asíncronas, durante la reflexión el
controlador de ASMX busca los métodos Web con un tipo
determinado de firma que reconoce como asíncronos. En
concreto, busca un par de métodos que cumplan las reglas
siguientes:
- Hay un método Web BeginXXX y
EndXXX donde XXX hace referencia a
cualquier cadena que represente el nombre del método que
desea exponer.
- La función BeginXXX devuelve una interfaz
IAsyncResult y toma como sus dos últimos parámetros
de entrada un parámetro AsyncCallback y un objeto,
respectivamente.
- La función EndXXX toma como único
parámetro una interfaz IAsyncResult.
- Ambas deben estar marcadas con el atributo
WebMethod.
Si el controlador de ASMX encuentra dos métodos que reúnan
todos estos requisitos, expondrá el método XXX en su
WSDL como si fuera un método Web normal. El método aceptará
como entrada los parámetros definidos antes del parámetro
AsyncCallback en la firma para BeginXXX y
devolverá lo que devuelva la función EndXXX.
Así, si tuviéramos un método Web cuya declaración síncrona
fuera similar a: [WebMethod]
public string LengthyProcedure(int milliseconds) {...}
Entonces, una declaración asíncrona sería similar a: [WebMethod]
public IAsyncResult BeginLengthyProcedure(
int milliseconds,
AsyncCallback cb,
object s) {...}
[WebMethod]
public string EndLengthyProcedure(IAsyncResult call) {...}
El WSDL para cada una sería el mismo.
Una vez que el controlador de ASMX se refleje en un
ensamblado y detecte un método Web asíncrono, deberá
administrar solicitudes para dicho método de forma diferente
que para las solicitudes síncronas. En vez de llamar a un
método simple, llama al método BeginXXX.
Deserializa la solicitud entrante en los parámetros para que
pase a la función (como lo hace con las solicitudes
síncronas), pero también pasa el puntero a una función de
devolución de llamada interna como parámetro
AsyncCallback extra en el método
BeginXXX.
Este enfoque es de forma intencionada muy similar al
paradigma de programación de .NET Framework para aplicaciones
cliente del servicio Web. En el caso de la compatibilidad del
lado del cliente para llamadas asíncronas de servicios Web, se
liberan subprocesos bloqueados para el equipo cliente,
mientras que en el lado del servidor se liberan subprocesos
bloqueados en el equipo servidor. Sin embargo, existen dos
diferencias fundamentales. En primer lugar, en vez de que el
código de servidor llame a las funciones BeginXXX
y EndXXX, lo hará el controlador de ASMX. En
segundo lugar, escribirá el código para las funciones
BeginXXX y EndXXX en vez de utilizar el
código generado por WSDL.EXE o el Asistente "Agregar
referencia Web" en Visual Studio .NET. Sin embargo, el
resultado es el mismo: liberar subprocesos para que puedan
realizar otros procesamientos.
Una vez que el controlador de ASMX llama a la función
BeginXXX del servidor, devolverá el subproceso
al grupo de subprocesos del proceso para que pueda administrar
cualquier otra solicitud que se reciba. El HttpContext para la
solicitud aún no se liberará. El controlador de ASMX esperará
hasta que se llame a la función de devolución de llamada que
pasó a la función BeginXXX para finalizar el
procesamiento de la solicitud.
Una vez llamada la función de devolución de llamada, el
controlador de ASMX llamará a la función EndXXX
para que el método Web pueda finalizar cualquier
procesamiento que necesite realizar y se puedan proporcionar
los datos de retorno que se serializarán en la respuesta de
SOAP. Sólo cuando se envíe la respuesta después de que vuelva
la función EndXXX se liberará el HttpContext
para la solicitud.
Un método Web asíncrono sencillo
Para ilustrar los métodos Web asíncronos, comenzaré con un
sencillo método Web síncrono denominado
LengthyProcedure, cuyo código aparece a continuación.
Posteriormente, veremos cómo hacer lo mismo de forma
asíncrona. LengthyProcedure simplemente bloquea el
número determinado de milisegundos. [WebService]
public class SyncWebService : System.Web.Services.WebService
{
[WebMethod]
public string LengthyProcedure(int milliseconds)
{
System.Threading.Thread.Sleep(milliseconds);
return "Correcto";
}
}
Ahora convertiremos LengthyProcedure en un método
Web asíncrono. Debemos crear una función
BeginLengthyProcedure y una función
EndLengthyProcedure, como se ha descrito anteriormente.
Recuerde que nuestra llamada BeginLengthyProcedure
deberá devolver una interfaz IAsyncResult. En este
caso, voy a hacer que nuestra llamada
BeginLengthyProcedure realice una invocación al método
asíncrono utilizando un delegado y el método
BeginInvoke en dicho delegado. La función de devolución
de llamada pasada a BeginLengthyProcedure se
transferirá al método BeginInvoke en nuestro delegado y
la interfaz IAsyncResult devuelta de BeginInvoke
será devuelta por el método BeginLengthyProcedure.
Se llamará al método EndLengthyProcedure cuando haya
finalizado nuestro delegado. Llamaremos al método
EndInvoke en el delegado que pasa a la interfaz
IAsyncResult que recibimos como entrada en la llamada
EndLengthyProcedure. La cadena devuelta será la que
devuelva nuestro método Web. Este es el código: [WebService]
public class AsyncWebService : System.Web.Services.WebService
{
public delegate string LengthyProcedureAsyncStub(
int milliseconds);
public string LengthyProcedure(int milliseconds)
{
System.Threading.Thread.Sleep(milliseconds);
return "Correcto";
}
public class MyState
{
public object previousState;
public LengthyProcedureAsyncStub asyncStub;
}
[ System.Web.Services.WebMethod ]
public IAsyncResult BeginLengthyProcedure(int milliseconds,
AsyncCallback cb, object s)
{
LengthyProcedureAsyncStub stub
= new LengthyProcedureAsyncStub(LengthyProcedure);
MyState ms = new MyState();
ms.previousState = s;
ms.asyncStub = stub;
return stub.BeginInvoke(milliseconds, cb, ms);
}
[ System.Web.Services.WebMethod ]
public string EndLengthyProcedure(IAsyncResult call)
{
MyState ms = (MyState)call.AsyncState;
return ms.asyncStub.EndInvoke(call);
}
}
Cuándo resultan más adecuados los métodos Web
asíncronos
Deben tenerse en cuenta varias cuestiones a la hora de
determinar si los métodos Web asíncronos son adecuados para la
aplicación. En primer lugar, la función BeginXXX
para la llamada debe devolver una interfaz
IAsyncResult. Las interfaces IAsyncResult se
devuelven a partir de ciertas operaciones asíncronas de E/S
para obtener acceso a secuencias, realizar llamadas de
Microsoft® Windows® Sockets, realizar E/S de archivos,
interactuar con otros dispositivos de hardware, llamar a
métodos asíncronos y, por supuesto, llamar a otros servicios
Web. Probablemente deseará obtener la interfaz
IAsyncResult a partir de uno de estos tipos de
operaciones asíncronas, de modo que pueda devolverla desde la
función BeginXXX. La otra opción es crear su
propia clase que implemente la interfaz IAsyncResult,
pero, de todos modos, probablemente tendrá que empaquetar una
de las implementaciones de E/S anteriormente mencionadas.
Para casi todas las operaciones asíncronas que hemos
mencionado, resulta muy adecuado utilizar métodos Web
asíncronos para empaquetar la llamada asíncrona del servidor
al tiempo que da como resultado un código del servicio Web más
eficaz. La excepción es cuando se realizan llamadas de método
asíncrono con delegados. Éstos harán que las llamadas de
método asíncrono se ejecuten en un subproceso del grupo de
subprocesos del proceso. Desafortunadamente, estos son los
mismos subprocesos que utiliza el controlador de ASMX para dar
servicio a las solicitudes entrantes. De modo que, al
contrario que las llamadas que realizan operaciones de E/S
reales con recursos de hardware o de red, una llamada de
método asíncrono que utilice delegados bloqueará uno de los
subprocesos del proceso durante la ejecución. También podría
bloquear el subproceso original y ejecutar el método Web de
forma síncrona.
El siguiente ejemplo muestra un método Web asíncrono que
llama al servicio Web del servidor. Ha marcado los métodos
BeginGetAge y EndGetAge con el atributo
WebMethod para que se ejecute de forma asíncrona. El
código de este método Web asíncrono llama a un método Web del
servidor denominado UserInfoQuery para obtener la
información que necesita devolver. La llamada a
UserInfoQuery se realiza de forma asíncrona y se pasa a
la función AsyncCallback que se transfirió al método
BeginGetAge. Esto provocará que se llame a la función
de devolución interna cuando finalice la solicitud del
servidor. La función de devolución de llamada llamará a
nuestro método EndGetAge para finalizar la solicitud.
En este caso, el código es mucho más simple que el del ejemplo
anterior y tiene la ventaja adicional de que no inicia el
procesamiento del servidor en el mismo grupo de subprocesos
que da servicio a nuestras solicitudes de método Web de nivel
medio. [WebService]
public class GetMyInfo : System.Web.Services.WebService
{
[WebMethod]
public IAsyncResult BeginGetAge(AsyncCallback cb, Object state)
{
// Invocar a una llamada asíncrona de servicios Web.
localhost.UserInfoQuery proxy
= new localhost.UserInfoQuery();
return proxy.BeginGetUserInfo("Nombre del usuario",
cb,
proxy);
}
[WebMethod]
public int EndGetAge(IAsyncResult res)
{
localhost.UserInfoQuery proxy
= (localhost.UserInfoQuery)res.AsyncState;
int age = proxy.EndGetUserInfo(res).age;
// Realizar aquí cualquier procesamiento adicional en
// los resultados desde la llamada de servicios Web.
return age;
}
}
Uno de los tipos de operaciones de E/S más comunes que se
producen en un método Web es un llamada a una base de datos
SQL. Desafortunadamente, Microsoft® ADO.NET por el momento no
tiene definido un buen mecanismo de llamadas asíncronas y el
simple empaquetado de una llamada SQL en una llamada de
delegado asincrónica no ayuda en absoluto al departamento de
eficacia. El almacenamiento de los datos en caché a veces es
una solución, pero también se debe considerar el uso de Microsoft
SQL Server 2000 Web Services Toolkit (en inglés) para
exponer las bases de datos como servicio Web. Entonces, podrá
utilizar la compatibilidad de .NET Framework para llamar a
servicios Web de forma asíncrona para consultar o actualizar
la base de datos.
Los conocimientos adquiridos para tener acceso a SQL
mediante una llamada de servicios Web deben tomarse muy en
serio por muchos de los recursos del servidor. Si ha estado
utilizando sockets TCP para comunicarse con un equipo Unix o
tiene acceso a algunas de las otras plataformas SQL
disponibles mediante controladores de bases de datos de
propietario (o incluso si tiene un recurso al que ha tenido
acceso utilizando DCOM), podría utilizar los numerosos kits de
herramientas de servicios Web disponibles en la actualidad
para exponer los recursos como servicios Web.
Una de las ventajas de este enfoque es que se pueden
aprovechar los avances en infraestructura de servicios Web del
lado del cliente, como las llamadas asíncronas de servicios
Web con .NET Framework. Así podrá obtener las funciones de
llamadas asíncronas de forma gratuita y resultará que el
mecanismo de acceso a clientes funcionará de forma eficaz con
métodos Web asíncronos.
Agregar datos con un método Web asíncrono
En la actualidad, muchos servicios Web tienen acceso a
varios recursos del servidor y agregan la información para el
servicio Web cliente. Aunque la llamada a varios recursos del
servidor agrega complejidad al modelo del método Web
asíncrono, se gana mucho en términos de eficacia.
Por ejemplo, el método Web llama a dos servicios Web del
servidor, Servicio A y Servicio B. Desde la función
BeginXXX, puede llamar tanto al Servicio A como
al Servicio B de forma asíncrona. Debería pasar a cada una de
estas llamadas asíncrona su propia función de devolución de
llamada. Para poder desencadenar la finalización del método
Web después de recibir los resultados del Servicio A y B, la
función de devolución de llamada proporcionada comprobará que
ambas solicitudes han finalizado, realizará el procesamiento
en los datos devueltos y, por último, llamará a la función de
devolución de llamada pasada a la función
BeginXXX. Esto desencadenará la llamada a la
función EndXXX, que a su retorno hará que
finalice el método Web asíncrono.
Conclusión
Los métodos Web asíncronos proporcionan un mecanismo eficaz
en los servicios Web de ASP.NET Web para invocar a llamadas a
servicios de servidor sin que se bloqueen los valiosos
subprocesos del grupo de subprocesos del proceso mientras no
realizan ninguna acción. En combinación con solicitudes
asíncronas a recursos del servidor, un servidor puede
maximizar el número de solicitudes simultáneas que puede
administrar con sus métodos Web. Deberá tener en cuenta este
enfoque al desarrollar aplicaciones de servicios Web de alto
rendimiento.
A su servicio
| Ultima
actualización: Lunes, 13 de Enero de 2003
| |