Contract-First web services con Visual Studio 2008

Utilizaremos Visual Studio 2008 con el addin WSCF.blue para generar contract-first web services (servicios web dirigidos por contrato)

Contract-First web services con Visual Studio 2008

Índice

  1. Introducción
  2. Descriptor del contrato
    1. Definición de los tipos del documento con XML Schema
    2. Definición del contrato con WSDL
  3. Implementación con Visual Studio 2008. WSCF.blue
    1. Instalación de WSCF.blue
    2. Crear el servicio e importar el contrato
    3. Implementar el web service
    4. Publicar y acceder al servicio
  4. Probar el web service con soapUI
  5. Conclusión

Introducción

En el diseño y desarrollo de servicios web podemos utilizar dos aproximaciones:

  • Dirigido por contrato, o Contract-First. Primero se describen las funcionalidades del servicio web en cuanto a su interfaz, semántica y aspectos administrativos de la invocación, siendo la especificación WSDL el estándar. El WSDL, como documento XML, puede ser parseado por una herramienta para facilitar la implementación del web service proveedor o consumidor.
  • Contract-Last, en el que primero se implementa el servicio web en un determinado lenguaje y posteriormente se genera un WSDL que lo describa.

Cada cual tiene sus ventajas e inconvenientes [1] [2] [3]. En este tutorial veremos la primera de las dos opciones, implementando en C# un servicio web proveedor. Utilizaremos las siguientes herramientas:

  • Windows Vista Home Edition SP2, C2D@1.5, 3GB Ram
  • Microsoft Visual Studio 2008 Professional SP1
  • Microsoft .NET Framework 3.5 SP1
  • thinktercure WSCF.blue V1 Final (1.0.5) (*)
  • soapUI 3.0.1

(*) En el momento de escribir este tutorial no existe una versión para Visual Studio 2008 Express Edition

El código fuente de este tutorial puede descargarse aquí: wsEncriptacion_adictosaltrabajo.zip

Descriptor del contrato

Vamos a trabajar con un web service de encriptación mediante Triple-DES y MD5 que ofrece dos operaciones :

  • encriptar. Recibe tres tipos simples: la cadena de texto en claro, la clave de encriptación y un flag para el uso o no de hashing. Devuelve la cadena de texto encriptada.
  • desencriptar. Recibe un tipo complejo compuesto por tres tipos simples: la cadena de texto encriptada, la clave utilizada en la encriptación y el flag para indicar el uso de hashing. Devuelve la cadena de texto desencriptada.

El uso de tipos simples o complejos es una cuestión de diseño, y en nuestro caso lo hacemos así para ampliar la cobertura de capacidades de WSCF.blue.

Definición de los tipos del documento con XML Schema

La definición del tipo de datos complejo lo implementamos mediante un XML Schema. Se muestra a continuación, y puede descargarse aquí: cryptoSchema.xsd

<?xml version=

Text
"1.0"
encoding=
Text
"UTF-8"
?> <!-- cryptoSchema.xsd Tutorial: Contract-
Text
First
web services con Visual Studio 2008 www.adictosaltrabajo.com - Ivan Garcia Puebla --> <xsd:
Text
schema
xmlns:xsd=
Text
"http://www.w3.org/2001/XMLSchema"
targetNamespace=
Text
"http://tutorial.adictosaltrabajo.com/schema/cryptoSchema"
xmlns:tns=
Text
"http://tutorial.adictosaltrabajo.com/schema/cryptoSchema"
elementFormDefault=
Text
"qualified"
> <xsd:complexType name=
Text
"datosDesencriptar"
> <xsd:
Text
sequence
> <xsd:element name=
Text
"encriptado"
Text
type
=
Text
"xsd:string"
></xsd:element> <xsd:element name=
Text
"clave"
Text
type
=
Text
"xsd:string"
></xsd:element> <xsd:element name=
Text
"usarHashing"
Text
type
=
Text
"xsd:boolean"
></xsd:element> </xsd:
Text
sequence
> </xsd:complexType> </xsd:
Text
schema
>

Definición del contrato con WSDL

Implementamos el contrato del web service en un descriptor WSDL concreto. Utilizaremos el Schema anterior, SOAP sobre HTTP, y el resto de detalles se muestran a continuación:

cryptoService.WSDL
descriptor cryptoService.wsdl

El fuente del fichero puede descargarse aquí: cryptoService.wsdl.

<?xml version=

Text
"1.0"
encoding=
Text
"UTF-8"
?> <!-- cryptoServiceWSDL.wsdl Tutorial: Contract-
Text
First
web services con Visual Studio 2008 www.adictosaltrabajo.com - Ivan Garcia Puebla --> <definitions name=
Text
"cryptoServiceWSDL"
targetNamespace=
Text
"http://tutorial.adictosaltrabajo.com/wsdl/cryptoServiceWSDL"
xmlns=
Text
"http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdl=
Text
"http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd=
Text
"http://www.w3.org/2001/XMLSchema"
xmlns:tns=
Text
"http://tutorial.adictosaltrabajo.com/wsdl/cryptoServiceWSDL"
xmlns:ns=
Text
"http://tutorial.adictosaltrabajo.com/schema/cryptoSchema"
xmlns:soap=
Text
"http://schemas.xmlsoap.org/wsdl/soap/"
> <types> <xsd:
Text
schema
targetNamespace=
Text
"http://tutorial.adictosaltrabajo.com/wsdl/cryptoServiceWSDL"
> <xsd:import namespace=
Text
"http://tutorial.adictosaltrabajo.com/schema/cryptoSchema"
schemaLocation=
Text
"cryptoSchema.xsd"
/> </xsd:
Text
schema
> </types> <message name=
Text
"encriptarRequest"
> <part name=
Text
"original"
Text
type
=
Text
"xsd:string"
/> <part name=
Text
"clave"
Text
type
=
Text
"xsd:string"
/> <part name=
Text
"usarHashing"
Text
type
=
Text
"xsd:boolean"
/> </message> <message name=
Text
"encriptarResponse"
> <part name=
Text
"resultado"
Text
type
=
Text
"xsd:string"
/> </message> <message name=
Text
"desencriptarRequest"
> <part name=
Text
"datosDesencriptar"
Text
type
=
Text
"ns:datosDesencriptar"
/> </message> <message name=
Text
"desencriptarResponse"
> <part name=
Text
"resultado"
Text
type
=
Text
"xsd:string"
/> </message> <portType name=
Text
"cryptoServiceWSDLPortType"
> <
Text
operation
name=
Text
"encriptar"
> <
Text
input
name=
Text
"inputEncriptar"
message=
Text
"tns:encriptarRequest"
/> <
Text
output
name=
Text
"outputEncriptar"
message=
Text
"tns:encriptarResponse"
/> </
Text
operation
> <
Text
operation
name=
Text
"desencriptar"
> <
Text
input
name=
Text
"inputDesencriptar"
message=
Text
"tns:desencriptarRequest"
/> <
Text
output
name=
Text
"outputDesencriptar"
message=
Text
"tns:desencriptarResponse"
/> </
Text
operation
> </portType> <binding name=
Text
"cryptoServiceWSDLBinding"
Text
type
=
Text
"tns:cryptoServiceWSDLPortType"
> <soap:binding style=
Text
"rpc"
transport=
Text
"http://schemas.xmlsoap.org/soap/http"
/> <
Text
operation
name=
Text
"encriptar"
> <soap:
Text
operation
/> <
Text
input
name=
Text
"inputEncriptar"
> <soap:body use=
Text
"literal"
namespace=
Text
"http://tutorial.adictosaltrabajo.com/wsdl/cryptoServiceWSDL"
/> </
Text
input
> <
Text
output
name=
Text
"outputEncriptar"
> <soap:body use=
Text
"literal"
namespace=
Text
"http://tutorial.adictosaltrabajo.com/wsdl/cryptoServiceWSDL"
/> </
Text
output
> </
Text
operation
> <
Text
operation
name=
Text
"desencriptar"
> <soap:
Text
operation
/> <
Text
input
name=
Text
"inputDesencriptar"
> <soap:body use=
Text
"literal"
namespace=
Text
"http://tutorial.adictosaltrabajo.com/wsdl/cryptoServiceWSDL"
/> </
Text
input
> <
Text
output
name=
Text
"outputDesencriptar"
> <soap:body use=
Text
"literal"
namespace=
Text
"http://tutorial.adictosaltrabajo.com/wsdl/cryptoServiceWSDL"
/> </
Text
output
> </
Text
operation
> </binding> <service name=
Text
"cryptoServiceWSDLService"
> <port name=
Text
"cryptoServiceWSDLPort"
binding=
Text
"tns:cryptoServiceWSDLBinding"
> <soap:address location=
Text
"http://localhost:8080/cryptoService"
/> </port> </service> </definitions>

Implementación con Visual Studio 2008. WSCF.blue

A partir del descriptor generaremos los stubs en C# del servicio que ofrezca las dos operaciones; posteriormente damos cuerpo al webservice y añadimos la lógica de negocio. En .NET podemos hacerlo a través del plugin/add-in para Visual Studio 2008, WSCF.blue. En el MSDN hay un interesante artículo publicado, http://msdn.microsoft.com/en-us/magazine/ee335699.aspx, sobre Contract-First Web Services y WSCF.blue, e incluye el enlace http://se.ethz.ch/~meyer/publications/computer/contract.pdf al artículo original de Bertrand Meyer: Applying «Design by Contract», aparecido en el IEEE en 1992

Instalación de WSCF.blue

Descargamos el instalador del acceso Download de http://www.codeplex.com/WSCFblue/ y lo instalamos siguiendo el asistente, de manera habitual.

Crear el servicio e importar el contrato

En Visual Studio 2008 creamos un nuevo proyecto de tipo Web de Visual C#. Utilizaremos la plantilla: Aplicación de servicio web de ASP.NET y damos como nombre wsEncriptacion. Agregamos una nueva carpeta llamada wscfEncriptacion y a continuación nuestros WSDL y Schema:

Proyecto creado en Visual Studio 2008
Proyecto creado en Visual Studio 2008

Bien en el menú Herramientas | Web Services Contract-First o bien pulsando con el botón derecho sobre cryptoServiceWSDL.wsdl, accedemos a las funcionalidades de WSCF.blue y escogemos Generate Web Service Code:

Menu contextual de WSCF.blue en Visual Studio 2008
Menú contextual de WSCF.blue

Establecemos las opciones de generación de código siguientes:

Opciones de generacion de codigo de WSCF.blue
Generación de código con WSCF.blue

Como se observa en la imagen, hemos establecido las opciones siguientes:

  • Server-side stub: vamos a generar el web service proveedor
  • Format SOA Actions: determinamos que las acciones SOAP de cada operación del contrato sigan el formato estándar de contratos de web services: <namespace>/<service>/<operation>[Response]
  • Separate files: cada tipo de dato del servicio web será generado en un fichero de C# distinto
  • Adjust casing: los tipos de datos generados seguirán la notación de .NET
  • Use synchronization context: el contexto determinará en qué hilo se ejecutará el web service
  • Generate a regular service class …: permitiremos generar métodos en donde implementar la lógica del servicio

Estas opciones son expuestas a modo de ejemplo. Cada proyecto requerirá de la configuración más adecuada para sus propósitos. La documentación se encuentra en: https://www.thinktecture.com/

Pulsamos en Generate y en unos instantes se confirmará la ejecución correcta de la operación:

Codigo generado correctamente
Código generado correctamente

En el explorador de soluciones podemos observar el código que ha sido generado:

Stubs del web service
Stubs generados del web service proveedor

Implementar el web service

La clase cryptoServiceWSDLPortType es la que finalmente alberga los métodos donde se implementará la lógica de negocio de nuestro servicio web. En su definición vemos que es una clase derivada de la interfaz IcryptoServiceWSDLPortType. En este tutorial implementaremos el fichero ASP web service, Service1.asmx, directamente con estos métodos. Para ello editamos el código de Service1.asmx y trasladamos el código de cryptoServiceWSDLPortType.cs de la siguiente manera.

  • Los atributos de compilación de la clase cryptoServiceWSDLPortType los establecemos en la clase de Service1
  • La clase Service1 la convertimos en derivada de IcryptoServiceWSDLPortType
  • Los métodos encriptar y desencriptar de cryptoServiceWSDLPortType los copiamos como métodos públicos no virtuales en la clase de Service1 con el atributo [WebService]

Finalmente eliminamos de cada método la sentencia de lanzamiento de excepción y añadimos nuestra lógica de encriptación/desencriptación. En este caso me he basado en el post: http://www.csharper.net/blog/library_encrypt_and_decrypt_methods_using_tripledes_and_md5.aspx. En resumen, Service1.asmx.cs queda de la forma:


Text
using
System;
Text
using
System.Collections.Generic;
Text
using
System.Linq;
Text
using
System.Web;
Text
using
System.Web.Services;
Text
using
System.Text;
Text
using
System.Security.Cryptography;
Text
namespace
wsEncriptacion {
Text
/// &lt;summary&gt;
Text
/// Service1.asmx
Text
/// Tutorial: Contract-First web services con Visual Studio 2008
Text
/// www.adictosaltrabajo.com - Ivan Garcia Puebla
Text
/// &lt;/summary&gt;
[WebService(
Text
Namespace
=
Text
"http://tempuri.org/"
)] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(
Text
false
)] [System.ServiceModel.ServiceBehaviorAttribute(InstanceContextMode = System.ServiceModel.InstanceContextMode.PerCall, ConcurrencyMode = System.ServiceModel.ConcurrencyMode.Single)]
Text
public
Text
class
Service1 : System.Web.Services.WebService, IcryptoServiceWSDLPortType { [WebMethod]
Text
public
OutputEncriptar Encriptar(InputEncriptar request) {
Text
string
textoAEncriptar = request.Encriptar.Original;
Text
string
clave = request.Encriptar.Clave;
Text
bool
usarHashing = request.Encriptar.UsarHashing;
Text
byte
[] keyArray;
Text
byte
[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(textoAEncriptar);
Text
if
(usarHashing) { MD5CryptoServiceProvider hashmd5 =
Text
new
MD5CryptoServiceProvider(); keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(clave)); hashmd5.Clear(); }
Text
else
keyArray = UTF8Encoding.UTF8.GetBytes(clave); TripleDESCryptoServiceProvider tdes =
Text
new
TripleDESCryptoServiceProvider(); tdes.Key = keyArray; tdes.Mode = CipherMode.ECB; tdes.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tdes.CreateEncryptor();
Text
byte
[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
Text
string
textoEncriptado = Convert.ToBase64String(resultArray, 0, resultArray.Length); tdes.Clear(); OutputEncriptar output =
Text
new
OutputEncriptar(); EncriptarResponse response =
Text
new
EncriptarResponse(); response.Resultado = textoEncriptado; output.EncriptarResponse = response;
Text
return
output; } [WebMethod]
Text
public
OutputDesencriptar Desencriptar(InputDesencriptar request) {
Text
string
textoADesencriptar = request.Desencriptar.DatosDesencriptar.Encriptado;
Text
string
clave = request.Desencriptar.DatosDesencriptar.Clave;
Text
bool
usarHashing = request.Desencriptar.DatosDesencriptar.UsarHashing;
Text
byte
[] keyArray;
Text
byte
[] toEncryptArray = Convert.FromBase64String(textoADesencriptar);
Text
if
(usarHashing) { MD5CryptoServiceProvider hashmd5 =
Text
new
MD5CryptoServiceProvider(); keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(clave)); hashmd5.Clear(); }
Text
else
keyArray = UTF8Encoding.UTF8.GetBytes(clave); TripleDESCryptoServiceProvider tdes =
Text
new
TripleDESCryptoServiceProvider(); tdes.Key = keyArray; tdes.Mode = CipherMode.ECB; tdes.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tdes.CreateDecryptor();
Text
byte
[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
Text
string
textoDesencriptado = UTF8Encoding.UTF8.GetString(resultArray); tdes.Clear(); OutputDesencriptar output =
Text
new
OutputDesencriptar(); DesencriptarResponse response =
Text
new
DesencriptarResponse(); response.Resultado = textoDesencriptado; output.DesencriptarResponse = response;
Text
return
output; } } }

Publicar y acceder al servicio

Iniciamos la depuración del proyecto y en la URL http://localhost:49193/Service1.asmx accedemos a la descripción del servicio web:

Probar el web service con soapUI

Para probar nuestro servicio utilizaremos soapUI (ejemplo de uso en el tutorial de Roberto Canales: Servicio Web con NetBeans 6 y prueba con SoapUI). El descriptor de nuestro servicio es http://localhost:49193/Service1.asmx?wsdl.

Creamos un mensaje SOAP request hacia la operación Encriptar con valores de ejemplo:

<soap:Envelope xmlns:soap=

Text
"http://www.w3.org/2003/05/soap-envelope"
xmlns:tem=
Text
"http://tempuri.org/"
> <soap:Header/> <soap:Body> <tem:Encriptar> <tem:request> <tem:Encriptar> <original>
Text
Lorem ipsum dolor sit
</original> <clave>
Text
autentia2009
</clave> <usarHashing>
Text
true
</usarHashing> </tem:Encriptar> </tem:request> </tem:Encriptar> </soap:Body> </soap:Envelope>

y obtenemos como mensaje SOAP response:

<soap:Envelope xmlns:soap=

Text
"http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi=
Text
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd=
Text
"http://www.w3.org/2001/XMLSchema"
> <soap:Body> <EncriptarResponse xmlns=
Text
"http://tempuri.org/"
> <EncriptarResult> <EncriptarResponse> <resultado xmlns=
Text
""
>
Text
m2K6Pf20MrNvX3uKR1e54KqpzLxnHmR0
</resultado> </EncriptarResponse> </EncriptarResult> </EncriptarResponse> </soap:Body> </soap:Envelope>

Realizamos la operación inversa, desencriptando el resultado anterior. El mensaje SOAP request será:

<soap:Envelope xmlns:soap=

Text
"http://www.w3.org/2003/05/soap-envelope"
xmlns:tem=
Text
"http://tempuri.org/"
xmlns:cry=
Text
"http://tutorial.adictosaltrabajo.com/schema/cryptoSchema"
> <soap:Header/> <soap:Body> <tem:Desencriptar> <tem:request> <tem:Desencriptar> <datosDesencriptar> <cry:encriptado>
Text
m2K6Pf20MrNvX3uKR1e54KqpzLxnHmR0
</cry:encriptado> <cry:clave>
Text
autentia2009
</cry:clave> <cry:usarHashing>
Text
true
</cry:usarHashing> </datosDesencriptar> </tem:Desencriptar> </tem:request> </tem:Desencriptar> </soap:Body> </soap:Envelope>

El mensaje de respuesta obtenido concuerda con el esperado:

<soap:Envelope xmlns:soap=

Text
"http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi=
Text
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd=
Text
"http://www.w3.org/2001/XMLSchema"
> <soap:Body> <DesencriptarResponse xmlns=
Text
"http://tempuri.org/"
> <DesencriptarResult> <DesencriptarResponse> <resultado xmlns=
Text
""
>
Text
Lorem ipsum dolor sit
</resultado> </DesencriptarResponse> </DesencriptarResult> </DesencriptarResponse> </soap:Body> </soap:Envelope>

Nuestro web service ha sido implementado correctamente partiendo de la descripción de un contrato.

Conclusión

En el Microsoft SDK existe la utilidad ServiceModel Metadata Utility Tool (Svcutil.exe) que permite asimismo generar las clases proxy del web service a partir del descriptor. Utilizar WSCF.blue no requiere de la instalación del SDK, no obstante, y aporta unas capacidades añadidas al propio IDE Visual Studio bastante interesantes para propósitos Contract-first.

 

 

Comentarios

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

He leído y acepto la política de privacidad

Información básica acerca de la protección de datos

  • Responsable: IZERTIS S.A.
  • Finalidad: Envío información de carácter administrativa, técnica, organizativa y/o comercial sobre los productos y servicios sobre los que se nos consulta.
  • Legitimación: Consentimiento del interesado
  • Destinatarios: Otras empresas del Grupo IZERTIS. Encargados del tratamiento.
  • Derechos: Acceso, rectificación, supresión, cancelación, limitación y portabilidad de los datos.
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad

¿Quieres publicar en Adictos al trabajo?

Te puede interesar

30/10/2025

Benjamín Suárez Menéndez

El Complex Problem Solving (CPS) es un proceso estructurado basado en herramientas, técnicas y actitudes que nos facilita la resolución de problemas complejos.

03/10/2025

Miguel García Rodríguez

Descubre cómo el diseño y la psicología del comportamiento utilizan sesgos cognitivos para influir en la toma de decisiones de los usuarios y potenciar la persuasión.

30/09/2025

Iván García Sainz-Aja

En este artículo exploraremos cómo utilizar ZenWave360 para generar un proyecto completo de Spring Boot con Kotlin a partir de un modelo DSL de Lenguaje Ubicuo.