Servicios web con ASP.NET
Rob Howard
Microsoft Corporation
22 de febrero de 2001
Los servicios web son el fundamento de la estrategia de .NET de Microsoft. Los conceptos y las innovaciones de esta iniciativa han alcanzado un acorde con la creación de la próxima generación de aplicaciones de Internet.
En la columna de este mes, echaremos un vistazo a las características de ASP.NET para habilitar los servicios web. Antes de profundizar en los detalles técnicos, comencemos con una visión general de los servicios web.
Introducción a los servicios web
Un servicio web es una lógica de aplicación programable accesible a través de protocolos web estándar. Uno de estos protocolos web es el Protocolo simple de acceso a objetos (SOAP). SOAP es una nota enviada por W3C (a partir de mayo de 2000) que usa tecnologías basadas en estándares (XML para la descripción de datos y HTTP para el transporte) para codificar y transmitir datos de aplicación.
Los consumidores de un servicio web no necesitan saber nada sobre la plataforma, el modelo de objetos ni el lenguaje de programación utilizados para implementar el servicio; solo necesitan comprender cómo enviar y recibir mensajes SOAP (HTTP y XML).
Mensaje soap
Un mensaje SOAP consta de varios elementos, especialmente un sobre. El sobre encapsula los datos transmitidos dentro del mensaje SOAP. A continuación se muestra un mensaje SOAP simple completado con encabezados HTTP:
POST /demo/MSDN/PerfCounter.asmx HTTP/1.1
Connection: Keep-Alive
Content-Length: 150
Content-Type: text/xml
Host: localhost
User-Agent: MS Web Services Client Protocol 1.0.2204.19
SOAPAction: "http://tempuri.org/PerfCounters"
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/"
xmlns:soapenc="https://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<soap:Body>
<PerfCounters xmlns="http://tempuri.org/"/>
</soap:Body>
</soap:Envelope>
En el ejemplo anterior, vemos los encabezados HTTP de la solicitud, incluido el encabezado HTTP SOAPAction, que opcionalmente usa el servidor para enrutar el mensaje SOAP. Siguiendo los encabezados HTTP, encontramos el cuerpo del mensaje HTTP. El cuerpo del mensaje HTTP es la solicitud SOAP para un servicio web PerfCounters, que vamos a compilar.
Desafortunadamente, no tenemos espacio suficiente en esta columna para analizar SOAP en profundidad. Para obtener más información sobre SOAP, consulte la página Recursos para desarrolladores de SOAP. Aquí puede encontrar la especificación pública de SOAP 1.1, así como artículos y otros recursos relevantes.
servicios web de ASP.NET
Los servicios web son sencillos y fáciles de entender. De hecho, es posible crear una aplicación sencilla que muestre datos como XML conforme a la especificación SOAP. También sería relativamente sencillo compilar una aplicación capaz de recibir mensajes SOAP a través de HTTP y derivar un valor significativo de ella. Para aquellos familiarizados con PERL, esto podría ser simplemente una cuestión de usar RegEx para analizar el valor del resultado XML; es sólo otra cadena.
Sin embargo, al igual que usamos marcos como ASP y ASP.NET para compilar aplicaciones web, mucho más bien usaríamos un marco para compilar servicios web. El razonamiento es bastante lógico. No es necesario reinventar la fontanería, es decir, en un nivel alto, la capacidad de serializar nuestros datos como XML, transportar los datos mediante HTTP y volver a serializar el XML a datos significativos. En su lugar, queremos un marco que facilite la creación de servicios web, lo que nos permite centrarnos en la lógica de la aplicación no en la fontanería. ASP.NET proporciona este marco para nosotros.
Desde el punto de vista de un desarrollador, si alguna vez ha escrito lógica de aplicación, tiene las aptitudes necesarias para crear ASP.NET servicios web. Lo más importante es que, si está familiarizado con ASP o ASP.NET servicios de aplicación, (memoria de estado de la aplicación, etc.), también puede aprovechar estas aptitudes al compilar ASP.NET servicios web.
Exponer
Por ejemplo, vamos a escribir un servicio web que exponga contadores de rendimiento de aplicaciones web. Los contadores de rendimiento nos proporcionan detalles sobre el comportamiento de nuestra aplicación, como el número de sesiones activas o el número de solicitudes atendidas. No siempre tenemos acceso de servidor local a nuestro servidor web y, si tenemos una granja de servidores, es posible que deseemos exponer los contadores de rendimiento de todos estos servidores y agregarlos en una ubicación central.
A partir de un ejemplo simple
En lugar de ir directamente al ejemplo contadores de rendimiento, comencemos con una lógica de aplicación muy sencilla para que podamos ver lo que necesitamos hacer para exponer nuestra lógica como servicio web. Usaremos un método Add() que acepte dos enteros y devuelva su suma. A continuación se muestra esta lógica sencilla de Visual Basic:
Public Class MyMath
Public Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function
End Class
Podríamos usar esta clase y su método de la siguiente manera:
Dim mymath As new MyMath
Dim result As Integer
result = mymath.Add(10, 20)
Para exponer la clase anterior, MyMath
, como un servicio web ASP.NET, es necesario mover la lógica de la aplicación a un archivo *.asmx. Al igual que usamos la extensión *.aspx para ASP.NET Pages, usamos *.asmx para indicar a ASP.NET que el archivo es un servicio web ASP.NET.
Después de crear el archivo de código fuente *.asmx y agregar la lógica de la aplicación, es necesario realizar algunos cambios más pequeños:
<%@ WebService Language="VB" Class="MyMath" %>
Public Class MyMath
Public Function <WebMethod()>Add(a As Integer, b As Integer) As Integer
Return a + b
End Function
End Class
Cambios en nuestro origen
Los cambios que hemos realizado en el archivo *.asmx incluyen agregar una directiva WebService que asigne un nombre tanto a como Language
a que Class
se exponga como un servicio web. La directiva WebService es necesaria, como se debe indicar ASP.NET la clase que contiene la lógica de la aplicación. A continuación, hemos agregado un <atributo WebMethod()> a la declaración de función Add(). Un atributo es un elemento de código declarativo que nos permite cambiar el comportamiento de la lógica de la aplicación sin necesidad de escribir más código. En el caso del <atributo WebMethod(),> esto indica ASP.NET que el método con este atributo se va a tratar como "Web invocable". Web invocable en el sentido de que ASP.NET realiza el trabajo necesario para que este método admita SOAP.
Ahora que hemos visto lo que hay que hacer para habilitar la lógica de aplicación como web invocable, echemos un vistazo a un ejemplo más relevante.
Servicio web contador de rendimiento
A continuación se muestra la lógica de la aplicación que nos proporciona acceso a los contadores de rendimiento de Windows®, con los cambios de ASP.NET servicios web. El archivo que hemos creado es PerfCounter.asmx:
<%@ WebService language="VB" class="PerfCounters" %>
Imports System.Xml.Serialization
Imports System.Web.Services
Imports System.Diagnostics
Public Class PerfCounters
Inherits WebService
' Returns a Counter class
Public Function <WebMethod()>GetCounters() As Counters
Dim c As new Counters
' Application Name
c.ApplicationName = IISAppName
' System specific
c.WorkerProcessRestarts = Poll(0, "Worker Process Restarts")
c.WorkerProcessRunning = Poll(0, "Worker Process Running")
c.ApplicationsRunning = Poll(0, "Applications Running")
c.RequestsQueued = Poll(0, "Requests Queued")
' Application Specific
c.RequestsTotal = Poll(1, "Requests Total")
c.RequestsFailed = Poll(1, "Requests Failed")
c.RequestsSucceeded = Poll(1, "Requests Succeeded")
c.ActiveSessions = Poll(1, "Sessions Active")
Return c
End Function
Private Function Poll(counterType As Integer, counter As String) As Integer
Dim PerfCounter As PerformanceCounter
If (counterType = 0)
PerfCounter = new PerformanceCounter("ASP Plus System", counter, "")
Else
PerfCounter = new PerformanceCounter("ASP Plus Applications", counter, IISAppName)
End If
Return PerfCounter.NextValue().ToInt32()
End Function
Private Function IISAppName() As String
Dim AppName As String
AppName = Context.Request.ServerVariables("APPL_MD_PATH")
AppName = AppName.Replace("/"C, "_"C)
Return AppName
End Function
End Class
Public Class Counters
Public ApplicationName As String
Public WorkerProcessRestarts As Integer
Public WorkerProcessRunning As Integer
Public ApplicationsRunning As Integer
Public RequestsQueued As Integer
Public RequestsTotal As Integer
Public RequestsFailed As Integer
Public RequestsSucceeded As Integer
Public ActiveSessions As Integer
End Class
De nuevo, vemos que hemos declarado una directiva WebService en la parte superior del archivo que señala tanto el idioma como la clase . La clase que contiene el método al que se puede llamar Web es PerfCounters. En PerfCounters encontramos un único método, GetCounters(), con el <atributo WebMethod().> GetCounters() devuelve una instancia de otra clase, Counters.
Cuando llamamos a GetCounters(), el método crea una nueva instancia de la clase Counter y comienza a establecer sus miembros públicos; Tenga en cuenta que estos miembros públicos deben implementarse como propiedades, pero he elegido ahorrar espacio para el propósito del artículo.
Cuando se establecen los miembros de la clase Counter, los establecemos con el resultado devuelto de una llamada a un método privado Poll(). Poll() es responsable de realizar el trabajo real de sondear los contadores de rendimiento de los sistemas y devolver un resultado.
Por último, el último método, IISAppName(), devuelve el valor de la variable de servidor APPL_MD_PATH y reemplaza los caracteres "/" por "_" caracteres; este valor se usa como nombre de aplicación dentro de los contadores de rendimiento.
Ahora que hemos creado el servicio, echemos un vistazo a cómo lo probamos.
Probar servicios web
Ahora que hemos creado este ASP.NET servicio web, ¿cómo lo probamos? El consumidor de un servicio web es otra aplicación, pero ASP.NET proporciona una interfaz de explorador sencilla a nuestro servicio web que podemos usar con fines de prueba o documentación.
Puesto que nuestro servicio se expone como un recurso disponible desde nuestro servidor web, podemos abrir un explorador y realizar una solicitud para ese recurso. Si lo hace, nos proporciona una página de ayuda de servicio web basada en HTML que permite a los usuarios obtener información sobre lo que proporciona nuestro servicio:
Figura 1. Página de ayuda del servicio web basado en HTML
ASP.NET genera la página anterior para nosotros, y podemos usarla para probar nuestro servicio (tenga en cuenta el botón Invocar HTML dentro de la sección Método web GetCounters) y acceder al lenguaje de contrato XML usado para describir lo que ofrece nuestro servicio; volveremos al lenguaje del contrato XML momentáneamente.
Si presionamos el botón Invocar, se abre una nueva ventana del explorador y se realiza una solicitud a nuestro servicio mediante HTTP-Get; uno de los tres protocolos admitidos que usan los servicios web ASP.NET:
Ilustración 2. Ejemplo de la nueva ventana del explorador que se crea al presionar el botón Invocar.
El XML devuelto es un documento XML válido que describe toda la configuración que hemos identificado en nuestra clase Counters. Sin embargo, no es SOAP. SOAP es el protocolo predeterminado que se usa cuando se realiza la comunicación de aplicación a aplicación.
Aunque no lo analizamos en este artículo, podemos personalizar nuestra página de ayuda de forma bastante extensa. Esto se hace realizando algunos cambios en el sistema de configuración de ASP.NET o modificando DefaultSDLHelpGenerator.aspx. Se recomienda no modificar DefaultSDLHelpGenerator.aspx, ya que se trata de la plantilla que se usa para todos nuestros servicios web. En su lugar, realice una copia de ella y haga referencia a la versión copiada en la configuración de la aplicación que lo usa.
Ahora que hemos analizado la creación y prueba de nuestro servicio web, vamos a usarlo.
Consumir
Tenemos varias opciones para consumir servicios web. Dado que este artículo trata sobre ASP.NET, nos centraremos en las tecnologías de .NET que pueden consumir servicios web. Sin embargo, debo señalar que cualquier plataforma o marco que comprenda SOAP debe ser capaz de comunicarse con nuestro servicio web. La compilación del servicio web con ASP.NET no significa que el servicio solo esté disponible para otras aplicaciones de Microsoft.
Los consumidores de un servicio web deben saber cuál es el aspecto que ofrece el servicio, por ejemplo, el aspecto de su método al que se puede llamar web. Por lo tanto, todos los servicios web comparten opcionalmente otro documento XML común: un contrato (nota, los servicios web creados con ASP.NET siempre tienen un contrato proporcionado automáticamente).
Contrato
En los ejemplos anteriores, cuando analizamos la prueba de un servicio web, no analizamos el vínculo que se encuentra en la página de ayuda del servicio web: contrato SDL. Si tuviéramos que seguir ese vínculo, en lugar de presionar el botón Invocar para el método web GetCounters(), se nos presentaría el siguiente documento XML:
Figura 3. Documento XML presentado al seguir el vínculo que se encuentra en la página de ayuda del servicio web
Este documento XML es un contrato que describe nuestro servicio web. Detalla los protocolos admitidos, así como la semántica para llamar y devolver valores. Además, define un esquema XML para nuestra clase Counters .
Las herramientas pueden usar este esquema XML para crear clases de proxy para nuestro servicio web. Una clase de proxy es una clase que se parece a un objeto local, pero de hecho realiza el trabajo para serializar, enviar, recibir y des serializar la solicitud de método a un punto de conexión SOAP.
Nota Beta 1 de .NET muestra un contrato "SDL— Service Description Language", Beta 2 cambiará para usar el contrato "WSDL- Web Service Description Language" más reciente. Semánticamente son muy diferentes. WSDL es el trabajo colaborativo de Microsoft, IBM y otras empresas para estandarizar mejor el lenguaje de contrato XML.
Tenemos varias opciones para consumir servicios web, sin embargo, me gustaría llamar a tres en particular:
- Visual Studio .NET: Visual Studio .NET realiza el trabajo de crear el proxy desde SDL o WSDL y agrega el código adecuado a nuestro proyecto. Para ello, basta con seleccionar Proyecto | Referencias web y, a continuación, apuntar a un contrato válido. Tenga en cuenta que para la versión beta 1, el contrato debe ser SDL.
- Herramientas de línea de comandos: el SDK de .NET se incluye con una herramienta denominada WebServiceUtil.exe que acepta un contrato SDL y puede generar el código fuente del proxy para Visual Basic .NET, C# o JScript.NET.
- IE 5.5. Comportamiento: : un comportamiento específico del explorador que permite una interacción enriquecida del cliente con los puntos de conexión SOAP. Para aquellos de ustedes familiarizados con Remote Scripting, ¡te encantará esto! Para obtener más información sobre el comportamiento de IE 5.5, consulte Comportamiento de webservice.
Desafortunadamente, no tenemos espacio para analizar estas tres opciones en detalle. Sin embargo, pensé que valdría la pena cubrir brevemente la creación de un proxy con la herramienta de línea de comandos, ya que esto es aplicable a aquellos que han instalado .NET; no solo aquellos que tienen Visual Studio .NET.
Texto de línea de comandos
.NET, ya sea que lo instale como parte de Visual Studio .NET o el SDK de .NET, incluye una herramienta de generación de proxy de línea de comandos denominada WebServiceUtil.exe. La ruta de acceso a esta herramienta de línea de comandos, así como otras herramientas de línea de comandos, se agrega a nuestra ruta de acceso al instalar .NET.
WebServiceUtil.exe nos permite nombrar un SDL, o contrato, como uno de los argumentos de la línea de comandos y la herramienta puede generar el código fuente para un proxy a nuestro servicio web.
Si, por ejemplo, se guardaría el SDL desde el ejemplo perfCounters.asmx, podríamos usar WebServiceUtil.exe para generar un proxy de .NET de Visual Basic en este servicio web:
WebServiceUtil.exe /command:proxy PerfCounter.sdl /language:VB
Esto genera un archivo de origen PerfCounters.vb que ahora es necesario compilar.
Con el compilador de línea de comandos de VB.NET, vbc.exe, podemos compilar nuestro archivo de código fuente de VB:
vbc /t:library /r:system.web.dll /r:system.web.services.dll /r:system.xml.serialization.dll perfcounters.vb
Lo que hemos hecho con el compilador de línea de comandos es especificar que queremos crear una biblioteca (dll) en lugar de un ejecutable (exe) y, además de asignar un nombre al archivo de origen para compilar, hemos especificado algunos ensamblados .NET (las bibliotecas que contienen clases que requiere nuestro archivo de origen) como argumentos para el compilador.
El resultado es PerfCounters.dll, un proxy completo para nuestro perfCounters.asmx ASP.NET servicio web que ahora podemos usar en las aplicaciones .NET para comunicarse a través de SOAP a nuestro servicio web.
Vamos a usar este proxy para crear una página de ASP.NET sencilla que consume y usa nuestro servicio web.
Uso del servicio web
En primer lugar, es necesario implementar el proxy compilado, conocido como ensamblado, en el directorio \bin de una aplicación web. Aunque aún no hemos analizado la implementación de código compilado en esta columna (otro tema para una columna futura), basta con decir que para "registrar" un ensamblado en el sistema simplemente requiere copiar el *.dll en el directorio \bin de una aplicación web. Se trata de una característica de .NET, pero el uso del directorio \bin es específico para ASP.NET.
Para simplificar las cosas, crearemos un directorio bin fuera del directorio raíz del servidor, c:\inetpub\wwwroot\bin, por ejemplo. Un directorio \bin debe existir en una raíz de la aplicación, ya sea la raíz de la Web o una carpeta marcada como una aplicación en IIS.
A continuación, copiamos el ensamblado, PerfCounters.dll, en el directorio \bin. Ahora podemos crear nuestra página de ASP.NET, que implementaremos en c:\inetpub\wwwroot. Lo llamaremos PerfCountersConsume.aspx:
<Script runat="server">
Public Sub Page_Load(sender As Object, e As EventArgs)
Dim perfcounters As New PerfCounters
Dim counters As Counters
counters = perfcounters.GetCounters()
webapp.InnerHtml = counters.ApplicationName
restarts.InnerHtml = counters.WorkerProcessRestarts.ToString()
procrunning.InnerHtml = counters.WorkerProcessRunning.ToString()
apprunning.InnerHtml = counters.ApplicationsRunning.ToString()
queued.InnerHtml = counters.RequestsQueued.ToString()
totalrequests.InnerHtml = counters.RequestsTotal.ToString()
failedrequests.InnerHtml = counters.RequestsFailed.ToString()
succeededrequests.InnerHtml = counters.RequestsSucceeded.ToString()
activesessions.InnerHtml = counters.ActiveSessions.ToString()
End Sub
</Script>
Web Application: <B id="webapp" runat="server"/><BR>
Process Restarts: <B id="restarts" runat="server"/><BR>
Processes Running: <B id="procrunning" runat="server"/><BR>
Applications Running: <B id="apprunning" runat="server"/><BR>
Requests Queued: <B id="queued" runat="server"/><BR>
Requests Total: <B id="totalrequests" runat="server"/><BR>
Requests Failed: <B id="failedrequests" runat="server"/><BR>
Requests Succeeded: <B id="succeededrequests" runat="server"/><BR>
Active Sessions: <B id="activesessions" runat="server"/><BR>
El código anterior crea una instancia de nuestra clase de proxy PerfCounters (disponible para nosotros, ya que es un ensamblado registrado en nuestro directorio \bin) llama a su método GetCounters() y devuelve una instancia de una clase Counters . A continuación, usamos la instancia de la clase Counters , contadores, para solicitar sus variables miembro y rellenar ASP.NET controles de servidor. El resultado es el siguiente:
Figura 4. controles de servidor ASP.NET
Resumen
Esta columna ha tomado una visión general de nivel muy alto de ASP.NET servicios web. Hay un poco de detalle que se ha filtrado o no se ha cubierto en absoluto, por ejemplo, seguridad, uso del estado de sesión, extensiones, etc. En la columna del mes siguiente veremos una característica más avanzada de ASP.NET Servicios web, extensiones, que podemos usar para crear atributos que nos permitan realizar un seguimiento de la solicitud o respuesta de nuestro servicio web de ASP.NET.
Rob Howard es administrador de programas para ASP.NET en el equipo de .NET Framework. Pasa cualquier tiempo libre que tenga con su familia o con la pesca en el este de Washington.