lunes, 5 de mayo de 2008

WSE Parte I


Web Service Enhancements.

Antes de iniciarnos con WSE, debemos entender que es un web service, ya que WSE, como su nombre lo indica, trabaja sobre WebServices y realza o amplia los protocolos de transferencia y transmisión de datos, así como la seguridad entre un websrvice y una aplicación.

Para poder utilizar WSE, lo primero que debemos hacer es descargarnos esta librería e instalarla en el servidor en el cual se ejecutarán los WebServices y en el PC en donde se desarrollará la aplicación, esta librería se la pueden descargar desde aquí



WebService.


Un webservice en un servicio que una organización entrega a sus clientes a través de la web, ya sea en canales de Internet o de Intranet, para ser consumidos en aplicaciones web y/o aplicaciones Windows. Cuando hablo de aplicaciones Windows, me refiero a cualquier tipo de aplicación que se puede crear en plataforma Windows y que puede consumir web services.


Los web services contienen métodos que se llaman desde las aplicaciones que consumen estos web services, estos métodos son conocidos como métodos web y son definidos como cualquier otro método de una aplicación, con la salvedad de que estos llevan la etiqueta de firma que los define como métodos web (Web Method).


Bueno ahora debemos saber que un Web Method de un Web Service se pude consumir de dos forma: Sincrona o Asíncrona.

  • Cuando solicitamos directamente un método y la aplicación queda esperando respuesta (no permite seguir operando en la interfaz) estamos hablando de que estamos realizando una llamada sincrona.
  • Cuando solicitamos un método de forma asincrona, la aplicación permite que se realicen otras acciones en la interfaz hasta que el Web Method del Web Service responde a la aplicación.


Dependiendo del canal de transferencia y de la velocidad de respuesta del metodo web, es que utilizaremos uno u otro.

En esta primara parte veremos como ejecutar un Web Method de un Web Service de forma sincrona y asíncrona, luego cuando veamos el comportamiento del Web Services, veremos WSE, que permite otros tipos de forma de transferencia de datos.

Los casos de WSE que veremos en la segunda parte estarán orientados a SOAP y a Enrutamiento (esto es bueno cuando deseas enmascarar el web services original).


Ahora al web services simple con WSE.

El ejercicio que presento a continuación tiene incluída la librería de WSE, así que recomiendo que se descargen WSE 3.0 y lo instalen antes de seguir con el ejercicio:


Los ejercicios que vamos a hacer están rescatados de los ejemplos que vienen en WSE 3.0 que se instalan con la librería, pero como siempre, en esta ocación vienen explicados paso a paso:


1 - Antes de realizar cualquier acción para la creación del WebServices, crearemos el proyecto de cliente que consumirá el WS, esto nos permitirá agregar el proyecto WS a la carpeta de solución, el proyecto de Windows se llamará WseWinBasico. Luego crearemos una aplicación de web services que llamaremos WseWsvBasico, dentro de este proyecto, eliminaremos el servio web por defecto y agregaremos un Servicio llamado WseEjercicioUNO.


2 - Como siguiente paso realizaremos la instanciación a las dll que nos permitirán utilizar los Servicios de WSE:

Nos posicionaremos en el nodo raíz del proyecto y seleccionaremos con el botón derecho la opción Agregar Referencias, como se muestra a continuación.




Al abrirse la ventana que nos permitirá agregar las referencias, buscaremos las referencias a la librería Microsoft.Web.Service3, como se muestra en la siguiente imagen:



Presionar el botón aceptar, con esto se observará que se ha agregado la referencia a esta librería, viendo en las propiedades del proyecto de WebService.

3 - El siguiente paso será agregar la instanciación de la librería en el proyecto, para esto agregaremos la siguiente línea de código en la cabecera de directivas:

using Microsoft.Web.Services3;

4 - Adicionalmente, agregaremos una llamada de instanciación a la librería:

using System.Xml.Serialization;
using System.Collections.Generic;


Estas librería nos permitirán utilizar las opciones de generación de listas y la generación de archivos XML, tanto de llamadas a métodos como de respuestas de los mismos.

5 - Como siguiente paso, definiremos una estructura que nos permitirá retornar información al cliente que consuma el servicio. Esta estructura retornará valores de tio xml y se definirá de la siguiente forma:

[XmlRoot(Namespace = "http://wse/Ejemplo001")]
public class Usuario
{
public String Valor;
public String Apellido;
public String Nombre;
public double Sueldo;
public DateTime fecha;
}

Esta estructura será definida fuera del espacio de nombre de la definición del Web Service. Si no tenemos habilitada la instanciación a System.Xml.Serializacion y System.Collections.Generic no se podrá definir la estructura de retorno.

6 - El siguiente paso será construir el método que capturará la información que se envía desde el cliente, para ello definiremos las siguientes directrices que estarán asociadas al método:

[WebMethod]

Asociado a todos los métodos que se presentarán como disponibles dentro de un servicio web.

[SoapDocumentMethod(ResponseElementName = "Usuario")]

Al aplicar SoapDocumentMethod, a un método se especifica que los mensajes SOAP hacia y desde el método utilizan el formato Document.ResponseElementName obtiene o establece el elemento asociado a la respuesta SOAP de un método de servicios Web XML.

[return: XmlElement("Usuario")]

Define que el parámetro de retorno será enviado a través de SOAP.

7 - Definiremos el método de la siguiente forma:

public List UsuarioDatoSolicitud([XmlArray(IsNullable = true), XmlArrayItem("Valor", IsNullable = false)] string[] Valores)
{
}

Si se observa el método tiene una estructura de lista, como la que se ha definido.

8 - Dentro del método definiremos las siguientes líneas de código:

List<Usuario> usuarioDato = new List<Usuario>();

foreach (String valor in Valores)
{
Usuario usu = new Usuario();
usu.Valor = valor;
if (valor == "m.roa")
{
usu.Nombre = "Mario Antonio";
usu.Apellido = "Roa Vidal";
usu.Sueldo = 5.5;
}
else
{
usu.Nombre = "Walter Borney";
usu.Apellido = "Roa Cleary";
usu.Sueldo = 1.15;
}
usuarioDato.Add(usu);
}
return usuarioDato;



Con esto ya tenemos listo el Método Web del Web Service para ejecutarlo. Si ejecutamos el Web Service observaremos que nos solicitará definir el modo de depuración dl WebService, a lo cual diremos que si.



Se podrá observar que la aplicación Web, no solicita parámetros, aunque tenga definido parámetros de entrada, lo que permite ver son las solicitudes de llamada y las estructura de retorno del Metodo Web.



I - CONSUMO DEL SERVICIO WEB DESDE UNA APLICACIÓN WINDOWS SINCRONICAMENTE


Ya creado el servicio web, debemos realizar el consumo del mismo para ello crearemos una referencia web al webservices que llamaremos WseWsv, y luego crearemos en la aplicación windows una interfaz de tipo winforms, luego agregaremos tres botones, un list box, tres controles label y tres textbox, a la interfaz que hemos definido en nuestra aplicación Windows, quedando la internas de la siguiente forma:



Con esto definido, podremos seguir con los siguientes pasos:

1 - En el proyecto Windows , agregaremos la referencia a la librería Microsoft.Web.Service3

2 - Agregaremos una definición de uso de la referencia Web dentro del archivo de código del formulario, de la siguiente forma:

using WseWinBasico.WseWsv;

3 - Dentro del espacio de nombre de la solución de la aplicación agregaremos una referencia al servicio web que utilizaremos, como se muestra a continuación:

// definimos la variable de instancia
WseEjercicioUno wsvProxi;


4 - Adicionalmente definiremos una variable de tipo GUID que utilizaremos en la llamada asincrona que realizaremos en previos pasos de la siguiente forma:

Guid guid;

También debemos agregar una referencia al WebService que vamos a consumir.

5 - En el método que atiende el evento load del formulario definiremos las siguientes líneas de código:

//cargamos el listbox
this.lbxUsuario.Items.Add("m.roa");
this.lbxUsuario.Items.Add("w.roa");

// creamos la instancia
wsvProxi = new WseEjercicioUno();

// usar una guía para el objeto
// UserState en vez de cancelar la solicitud
guid = new Guid();

this.btnCerrar.Enabled = false;

6 - Por ultimo, en el método que atiende el evento clic del botón de llamada sincrónica, definiremos las siguientes líneas de código:

this.btnSincrono.Enabled = false;

String[] symbols = new String[1];
symbols.SetValue((string)this.lbxUsuario.SelectedItem, 0);

try
{
Usuario[] usuario = wsvProxi.UsuarioDatoSolicitud(symbols);
foreach (Usuario usu in usuario)
{
this.txtNombre.Text = usu.Nombre;
this.txtApellido.Text = usu.Apellido;
this.txtSueldo.Text = usu.Sueldo;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
this.btnSincrono.Enabled = true;
}


7 - Ejecutamos la solución y observaremos el comportamiento del Web Service Sincrónico



II - CONSUMO DEL SERVICIO WEB DESDE UNA APLICACIÓN WINDOWS ASINCRONICAMENTE


Los llamados asincrónicos de WebServices tienen un comportamiento similar los de Hilos, en donde se realiza la llamada a un web services y este responde en cuanto se termine la solicitud. Para definir una llamada a un Web Service de forma asincrónica se deben seguir los siguientes pasos:

1 - Antes de realizar cualquier acción sobre el método que atiende el evento clic del bot´n de llamada asincrónica, se debe crear el siguiente método:

// llamada asincrónica al evento
private void WsvProxyUsuario(object sender, UsuarioDatoSolicitudCompletedEventArgs e) {

}

2 - Dentro del método recién creado agregaremos las siguientes líneas de código:

//inicializamos los estados de los botones
this.btnAsincrono.Enabled = true;
this.btnSincrono.Enabled = true;
this.btnCerrar.Enabled = false;

if (e.Error != null)
{
// llamada fallida
MessageBox.Show("La llamada al Web Service a Fallado");
}
if (e.Cancelled)
{
// llamada cancelada
MessageBox.Show("La llamada al Web Service a sido Cancelada");
}
else
{
// conexión exitosa
Usuario[] usuario = e.Result;
foreach (Usuario usu in usuario)
{
this.txtNombre.Text = usu.Nombre;
this.txtApellido.Text = usu.Apellido;
this.txtSueldo.Text = usu.Sueldo.ToString();
}
}


3 - En el método que atiende el evento clic del botón de llamada asincrónica, agregaremos las siguientes líneas de código.

this.btnAsincrono.Enabled = false;
this.btnSincrono.Enabled = false;
this.btnCerrar.Enabled = true;
this.txtNombre.Text = "";
this.txtApellido.Text = "";
this.txtSueldo.Text = "";

// asignación de llamada al método asincrónico
wsvProxi.UsuarioDatoSolicitudCompleted
+= new UsuarioDatoSolicitudCompletedEventHandler(WsvProxyUsuario);

// asignación de variable de llamada al método asincrónico
String[] symbols = new String[1];
symbols.SetValue((string)this.lbxUsuario.SelectedItem, 0);

// llamada asincrona del método
wsvProxi.UsuarioDatoSolicitudAsync(symbols, guid);

4 - Por ultimo, si se observa, hemos definido una variable de tipo Guid, la cual nos permitirá controlar la llamada y cancelación de la consulta asincrónica, por lo cual, podremos definir en el método que atiende el botón cerrar llamada asincrónica la siguiente línea de código.

// se cancela la llamada asincrona
wsvProxi.CancelAsync(guid);



III - CONSUMO DE SERVICIOS WEB DE FORMA ASINCRONA EN APLICACIONES WEB



Para desarrollar una interfaz que consuma el método del servicio web definido, se deben seguir los siguientes pasos:

1 - Crearemos una interfaz que tenga la siguiente apariencia:






2 - En el proyecto, agregaremos la referencia a la librería Microsoft.Web.Service3

3 - Agregaremos una definición de uso de la referencia Web dentro del proyecto al servicio web de la siguiente forma:

using WseWinBasico.WseWsv;

4 - Dentro del espacio de nombre de la solución de la aplicación agregaremos una referencia al servicio web que utilizaremos, como se muestra a continuación:

// definimos la variable de instancia
WseEjercicioUno wsvProxi;


Adicionalmente definiremos una variable de tipo GUID que utilizaremos en la llamada asincrona que realizaremos en previos pasos de la siguiente forma:

Guid guid;

También debemos agregar una referencia al WebService que vamos a consumir.

5 - En el método que atiende el evento load del formulario definiremos las siguientes líneas de código:

//cargamos el listbox
this.lbxUsuario.Items.Add("m.roa");
this.lbxUsuario.Items.Add("w.roa");

// creamos la instancia
wsvProxi = new WseEjercicioUno();

// usar una guía para el objeto
// UserState en vez de cancelar la solicitud
guid = new Guid();

this.btnCerrar.Enabled = false;


6 - Antes de realizar cualquier acción sobre el método que atiende el evento clic del botón de llamada asincrónica, se debe crear el siguiente método:

// llamada asincrónica al evento
private void WsvProxyUsuario(object sender, UsuarioDatoSolicitudCompletedEventArgs e)
{


}


7 - Dentro del método recién creado agregaremos las siguientes líneas de código:

//inicializamos los estados de los botones
this.btnAsincrono.Enabled = true;
this.btnSincrono.Enabled = true;
this.btnCerrar.Enabled = false;

if (e.Error != null)
{
// llamada fallida
MessageBox.Show("La llamada al Web Service a Fallado");
}
if (e.Cancelled)
{
// llamada cancelada
MessageBox.Show("La llamada al Web Service a sido Cancelada");
}
else
{
// conexión exitosa
Usuario[] usuario = e.Result;
foreach (Usuario usu in usuario)
{
this.txtNombre.Text = usu.Nombre;
this.txtApellido.Text = usu.Apellido;
this.txtSueldo.Text = usu.Sueldo.ToString();
}
}



8 - En el método que atiende el evento clic del botón de llamada asincrónica, agregaremos las siguientes líneas de código.

this.btnAsincrono.Enabled = false;
this.btnSincrono.Enabled = false;
this.btnCerrar.Enabled = true;
this.txtNombre.Text = "";
this.txtApellido.Text = "";
this.txtSueldo.Text = "";

// asignación de llamada al método asincrónico
wsvProxi.UsuarioDatoSolicitudCompleted
+= new UsuarioDatoSolicitudCompletedEventHandler(WsvProxyUsuario);

// asignación de variable de llamada al método asincrónico
String[] symbols = new String[1];
symbols.SetValue(this.lbxUsuario.SelectedItem.ToString(), 0);

// llamada asincrona del método
wsvProxi.UsuarioDatoSolicitudAsync(symbols, guid);


9 - Por ultimo, si se observa, hemos definido una variable de tipo Guid, la cual nos permitirá controlar la llamada y cancelación del la consulta asincrónica, por lo cual, podremos definir en el método que atiende el botón cerrar llamada asincrónica la siguiente línea de código.

// se cancela la llamada asincrona
wsvProxi.CancelAsync(guid);


En la cabecera de definición del código HTML se debe agregar la autorización de ejecución de las llamadas asincronas, para ello se debe definir la siguiente línea de código:

Async="true"

Quedando la cabecera HTML de llamada al ensamblado de la siguiente forma:

<%@ Page Language="C#" AutoEventWireup="true"
Async="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

WSE Parte II


No voy a perder tiempo en definirles que es WSE ya que nuestros amigos de microsoft ya tienen un sitio en donde explican este tema, por lo cual solo les pondré la url para que consulten que es WSE Ir a Explicación de WSE

Para poder utilizar WSE, lo primero que debemos hacer es descargarnos esta librería e instalarla en el servidor en el cual se ejecutarán los WebServices y en el PC en donde se desarrollará la aplicación, esta librería se la pueden descargar desde aquí

A continuación despliego la información del ejemplo:

MENSAJERÍA SOAP UTILIZANDO WSE

El presente ejercicio estará orientado a consumir desde un portal de Web Service una clase que contendrá un método que nos permitirá retornar la información que utilizaremos, para ello debemos crear tres proyectos de distinto índole, los cuales presentarán las siguientes características:

  • BILBIOTECA DE CLASE. El cual estará encargado de administrar las estructuras que se utilizarán, tanto en la aplicación de cliente como en la clase que residirá en el servicio Web. Adicionalmente se controlará el tipo de versión de cabecera SOAP que se utilizará en el enlace entre el cliente y el servidor Web.
  • WEB SERVICES. En esta aplicación residirá la clase que contendrá el método que se consumirá desde el cliente. Este portal de servicios Web no tendrá ningún servicio Web definido, solo contendrá la clase descrita.
  • CLIENTE DE CONSOLA. La cual utilizando la biblioteca de clase y la clase del Web Service, obtendrá los resultados deseados.

I - BILBIOTECA DE CLASE.

Para la creación del proyecto de solución con los proyectos antes descritos, se deben seguir los siguientes pasos:

1 - Crearemos un nuevo proyecto de bibliotecas de clases al cual llamaremos WseBase.

2 - Agregaremos las siguientes referencias a la solución.

  • Microsoft.Web.Service3
  • System.Configuration
  • System.Drawing
  • System.Security
  • System.Web
  • System.Web.Services
  • System.Windows.Forms.


3 - La clase que se crea por defecto la renombraremos de la siguiente forma Documents.cs

4 - Antes de realizar cualquier acción sobre esta clase, definiremos el uso de algunos espacios de nombres que se han referenciado o que se encuentran definidos por defecto en la aplicación, estos espacios de nombre deben ser:

using System;
using System.Xml.Serialization;


5 - Cambiaremos el nombre del espacio de nombre de la clase al siguiente Microsoft.Web.Services3.Usuario, quedando la definición del espacio de nombre de la siguiente forma:

namespace Microsoft.Web.Services3.Usuario
{
}


IMPORTANTE. Solo debe quedar definido el espacio de nombre y las definiciones de uso antes descritas en la clase creada.

6 - A continuación agregaremos las estructuras que se utilizarán dentro de la clase, estas serán:

USUARIO. Encargada de contener la estructura de definición de variables que se utilizarán en la ejecución del programa, tanto de asignación, como de despliegue de la misma.

[XmlRoot(Namespace="http://localhost/Wse")]
public class Usuario
{
public String usuario;
public String Nombre;
public String Apellido;
public double Sueldo;
}


USUARIOS. Estructura que contendrá una variable del tipo de la Clase Usuario variable.

public class Usuarios
{
[XmlElement("Usuario")]
public Usuario[] usuarios;
}

USUARIOREQUEST. Variable de tipo Usuarios, que será representada, cuando sea devuelta, en formato XML.

[XmlRoot(Namespace = "http://localhost/Wse")]
public class UsuarioRequest
{
[XmlArray("usuarios")]
[XmlArrayItem("Usuario")]
public String[] Usuarios;
}



7 - Como siguiente paso, agregaremos una nueva clase al proyecto de biblioteca de clase, la cual llamaremos AppBase. Dentro de esta clase definiremos el uso de algunos espacios de nombres que se han referenciado o que se encuentran definidos por defecto en la aplicación, estos espacios de nombre son:

using System;
using System.Collections;
using System.Configuration;
using System.Text;
using System.Net;
using System.IO;
using System.Web.Services.Protocols;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Configuration;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Tokens;
using Microsoft.Web.Services3.Security.X509;



8 - Cambiaremos el nombre del espacio de nombre de la clase al siguiente Microsoft.Web.Services3.Usuario, quedando la definición del espacio de nombre de la siguiente forma:

namespace Microsoft.Web.Services3.Usuario
{

}


IMPORTANTE. Solo debe quedar definido el espacio de nombre y las definiciones de uso antes descritas en la clase creada.

9 - Dentro del estacio de nombre agregaremos la definición de la clase AppBase de la siguiente forma:

public class AppBase
{
}

10 - Dentro del espacio de nombre de la clase recién creada, agregaremos la siguiente definición de variable de ambiente de clase:

SoapProtocolVersion _soapVersion = SoapProtocolVersion.Default;

11 - Agregaremos, a continuación (dentro del espacio de la clase), la siguiente propiedad.

protected SoapProtocolVersion SoapVersion
{
get
{
return _soapVersion;
}
}

12 - Por último agregaremos el siguiente constructor de la clase:

// define el tipo de versión de soap que se utilizará en la llamada
public AppBase() {
string soapVersion = System.Configuration.ConfigurationManager.AppSettings["soapversion"];
switch (soapVersion)
{
case "soap11":
_soapVersion = SoapProtocolVersion.Soap11;
break;
case "soap12":
_soapVersion = SoapProtocolVersion.Soap12;
break;
default:
case "default":
_soapVersion = SoapProtocolVersion.Default;
break;
}
}

II - CREACION DE WEBSERVICE



El siguiente paso será crear el proyecto de Web Service, para ello seguiremos los siguientes pasos.

1 - Agregaremos un proyecto de Web de tipo Servicio Web a la solución, al cual llamaremos Wse. Como característica especial, definiremos que este proyecto de Web será creado en el directorio virtual de IIS, con la siguiente definición http://localhost/Wse

2 - El siguiente paso será eliminar, tanto el servicios web como su clase de componente de código asociado.

3 - A continuación agregaremos una clase a la solución que llamaremos UsuarioServicio.cs, debemos aceptar la opción que permite crear la clase para que quede disponible en el proyecto.

4 - Agregaremos las siguientes referencias al proyecto:

  • Microsoft.Web.Service3
  • WseBase
  • System.Configuration.Install
  • System.Design
  • System.Security
  • System.Windows.Form


5 - Abriremos la clase en el editor de código fuente y agregaremos las siguientes instancias de uso de espacios de nombre:

using System;
using System.Collections;

using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Messaging;

using Microsoft.Web.Services3.Usuario;


NOTA: Debemos recordar que la instancia a Microsoft.Web.Service3.Usuario, está asociada a la biblioteca de clase WinBase

6 - El siguiente paso es asegurarnos que el nombre del espacio de nombre es el siguiente

namespace UsuarioServicio
{

}

7 - Dentro del espacio de nombre definido crearemos la siguiente clase:

[SoapService("http://localhost/Ejercicio002")]
public class UsuarioConsulta : SoapService
{

}

IMPORTANTE. Se debe considerar que los mismos espacios de nombre de cabecera SOAP deben ser definidos en los métodos que invocarán a la clase desde el cliente

8 - Dentro de la clase definida agregaremos la siguiente función, la cual estará encargada de retornar el XML con la lista de usuarios consultados.

[SoapMethod("http://localhost/Ejercicio002/UsuarioRequest")]
public Usuarios funUsuarioConsultar(UsuarioRequest message)
{
ArrayList list = new ArrayList();
foreach (String valor in message.Usuarios)
{
Usuario usu = new Usuario();
usu.usuario = valor;

if (valor == "m.roa")
{
usu.Nombre = "Mario Antonio";
usu.Apellido = "Roa Vidal";
usu.Sueldo = 5000;
}
else
{
usu.Nombre = "Walter Borney";
usu.Apellido = "Roa Cleary";
usu.Sueldo = 6000;
}
list.Add(usu);
}

Usuarios usuarios = new Usuarios();
usuarios.usuarios = (Usuario[])list.ToArray(typeof(Usuario));
return usuarios;
}

IMPORTANTE. Se debe considerar que los mismos espacios de nombre de cabecera SOAP deben ser definidos en los métodos que invocarán a la clase desde el cliente

9 - A continuación, reemplazaremos las líneas de código del we.config, con las siguientes:

<?xml version="1.0"?>
<configuration>
<configSections>
<section name="microsoft.web.services3" type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</configSections>
<system.web>
<httpHandlers>
<add verb="*" path="StockService.ashx" type="UsuarioServicio.UsuarioConsulta"/>
</httpHandlers>
<webServices>
<soapExtensionImporterTypes>
<add type="Microsoft.Web.Services3.Description.WseExtensionImporter, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</soapExtensionImporterTypes>
<webServices>
<compilation debug="true">
<assemblies>
<add assembly="Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Security, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Configuration.Install, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
</assemblies>
<compilation>
</system.web>
<configuration>



Generamos el proyecto WebService de solución

III - CREACION DE CLIENTE DE CONSOLA



Como último paso debemos crear el cliente que consumirá la aplicación, este cliente será de tipo de consola y lo agregaremos a la solución, para ello se deben seguir los siguientes pasos:

1 - Agregar un proyecto Windows de consola a la aplicación, el cual llamaremos WseConsola.

El archivo por defecto que se crea lo renombraremos con el nombre MAIN.

2 - Agregaremos las siguientes referencias a la aplicación:

  • Microsoft.Web.Service3
  • WseBase
  • System
  • System.Data
  • System.Web
  • System.Web.Services
  • System.Xml


3 - Abriremos el Archivo Main.cs con el editor de código y agregaremos las siguientes referencias de uso a los espacios de nombre que se detallan a continuación:

using System;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Addressing;
using Microsoft.Web.Services3.Messaging;
using Microsoft.Web.Services3.Usuario;


4 - Como siguiente paso, eliminaremos el espacio de nombre actual con todo lo creado y agregaremos el siguiente espacio de nombre:

namespace UsuarioClienteLlamada
{

}

5 - Dentro del espacio de nombre creado agregaremos la siguiente clase:

class UsuarioClienteLlamada : AppBase
{

}

6 - Dentro del espacio de clase, agregaremos el siguiente método de lectura

[MTAThread]
static void Main(string[] args) {
UsuarioClienteLlamada ucl = null;

try
{
ucl = new UsuarioClienteLlamada();

}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

Console.WriteLine("");
Console.WriteLine("Presione [Enter] para continuar...");
Console.WriteLine("");
Console.ReadLine();
}

7 - Antes de continuar con la definición de código de esta clase, agregaremos a la solución una nueva clase con el siguiente nombre:

UsuarioCliente.cs

8 - Abriremos el Archivo UsuarioCliente.cs con el editor de código y agregaremos las siguientes referencias de uso a los espacios de nombre que se detallan a continuación:

using System;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Messaging;
using Microsoft.Web.Services3.Usuario;

9 - A continuación definiremos el siguiente espacio de nombre:

namespace UsuarioClienteLlamada
{

}

10 - Dentro del espacio de nombre creado, definiremos la siguiente clase:

[SoapService("http://localhost/Ejercicio002")]
public class UsuarioCliente : SoapClient
{
public UsuarioCliente(Uri to) : base(to) { }

}


NOTA. Se debe observar que en la clase existe un constructor de clase que captura la URL que se entrega, esta URL estará asociada al WebService que se desea consumir.

IMPORTANTE. Se debe considerar que los mismos espacios de nombre de cabecera SOAP deben ser definidos en los métodos que invocarán a la clase desde el cliente

11 - El siguiente paso, será crear el método que llamará al método de la clase creada en el Web Service, esto se hará a continuación del constructor definido, definiendo las siguientes líneas de código:

[SoapMethod("http://localhost/Ejercicio002/UsuarioRequest")]
public Usuarios funUsuarioConsultar(UsuarioRequest message)
{
// se invoca el servicio utilizando mensajería de punto a punto
// (SoapServiceAttribute.TargetNamespace)
// y se define la función que se consumirá y que retorna las
// listas con los valores rescatados
return (Usuarios)base.SendRequestResponse("funUsuarioConsultar",
message).GetBodyObject(typeof(Usuarios),
SoapServiceAttribute.TargetNamespace);
}



IMPORTANTE. Se debe considerar que los mismos espacios de nombre de cabecera SOAP deben ser definidos en los métodos que invocarán a la clase desde el cliente

Guardamos el código creado y regresamos al archivo Main.cs

12 - Dentro del espacio de la clase UsuarioClienteLlamada, agregaremos el siguiente procedimiento que se encargará de realizar el consumo de la clase antes creada y de retornar la información:

public void prcConsumoEjecutar()
{

String[] symbols = { "m.roa", "w.roa" };
UsuarioRequest request = new UsuarioRequest();
request.Usuarios = symbols;

UsuarioCliente proxy = new UsuarioCliente(new Uri("http://" + System.Net.Dns.GetHostName() + "/Wse/StockService.ashx"));

Console.WriteLine("Llamando {0}", proxy.Destination.Address.Value);

Usuarios quotes = proxy.funUsuarioConsultar(request);

Console.WriteLine("La llamada al Web Service ha sido exitosa:");

foreach (Usuario quote in quotes.usuarios)
{
Console.WriteLine("");
Console.WriteLine("Usuario:\t\t" + quote.usuario);
Console.WriteLine("Nombre:\t\t\t" + quote.Nombre);
Console.WriteLine("Apellido:\t\t" + quote.Apellido);
Console.WriteLine("Sueldo:\t\t\t" + quote.Sueldo.ToString());
}
}

13 - Por ultimo dentro del bloque try definido en el Método Main de la aplicación agregaremos las siguientes líneas de código:

ucl = new UsuarioClienteLlamada();

ucl.prcConsumoEjecutar();



Quedando el bloque try de la siguiente forma:


try
{
ucl = new UsuarioClienteLlamada();
ucl.prcConsumoEjecutar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

Bueno amigos tienen todo, ahora si no les funciona es porque han picado algo mal.

Manejo de errores


Bueno amigos, el manejo de errores es más que el utilizar el conocido try catch, aunque este es muy bueno para elevar errores que se producen en sub capas, cuando se están utilizando, ya que como sabemos, si trabajamos con aplicaciones portables, debemos manejar y tratar los errores en la interfaz de usuario, así cada desarrollador definirá que errores y que mensajes aplicar cuando se presenta un error.

El siguiente artículo está desglosado en dos partes:

  • Manejo de errores en capas con try catch.
  • Manejo de errores en interfaz y en general.


1 - Manejo de errores en capas con try catch:



La forma más sencilla de tratar y elevar un error desde una capa a otra hasta llegar a la interfaz de usuario es lanzando la excepción, esto lo podemos apreciar a continuación:

try{

}Catch (Exception ex){
throw ex;
}

Yo, cuando defino, ya sea una capa de datos y/o una capa de negocios, nunca trato los errores en estos niveles, ya que si no existe un buen mecanismo de control de errores en estas capas, estos se pierden. Además que al construír aplicaciones portables y reutilizables y, no estar haciendo un buen control de errores en ellas, en la interfaz de usuario se puede perder el error real y el desarrollador puede pasar algunos problemas al tratar de saber cual es el error verdadero. Por lo cual, recomiendo siempre que eleven los errores de las capas capturados en los bloques try catch y, realizar el tratamiento de errores en la interfaz de usuario, en adelante UI.

2 - Manejo de errores en interfaz y en general.


Ahora, es posible manejar y administrar los errores que se presentan en cada una de las páginas que se ejecutan en una aplicación web. Los diversos tipos de errores que se pueden administrar son los siguientes:

  • Capturar errores en una página.
  • Capturar Errores de Aplicación.
  • Manejando los errores en el web.config


Captura de errores en una página:

Cuando estamos en una interfaz, podemos ya manejar los errores con un solo procedimiento, que capturará todos los errores que se presenten en la página, claro esta que podríamos hacerlo con el bloque try catch, pero si podemos crear un método de página que puede controlar los errores que se lanzan desde capas inferiores o que puede capturar los errores que se procuden en la misma página, ¿¿¿para que definir por cada método de página un bloque try catch???. La forma de realizar este ejemplo lo veremos a continuación:


a) Crearemos una página con el nombre wfrError.aspx, dentro de una aplicación o sitio web en vs2003, 2005 y/o 2008.

b) En el método que atiende el evento load del formulario, lanzaremos un evento que desplegará un error, utilizando las siguientes líneas de código:

throw new ApplicationException("Manejo de Error de Interfaz");

Si ejecutamos la página dentro de la aplicación creada veremos que se despliega un error manejado por el IIS, ahora lo que debemos hacer es crear el método de página que controlará todos los errores que se lancen dentro de esta, para ello agregaremos el siguiente procedimiento, el cual estará encargado de capturar y administrar el error que se ha desplegado:

void Page_Error(Object sender, EventArgs args) {

Exception e = Server.GetLastError();

Response.Write("Lo sentimos, se ha producido el siguiente error" + e.ToString());
Server.ClearError();
}


Capturar Errores de Aplicación.

Si no es posible capturar un error en la página, se puede capturar este globalmente creando funciones en el archivo global.asax, específicamente en el método Application_Error.

En este ejemplo defino como crear un archivo de logs, pero yo ya no uso este tipo de manejo de errores debido a que las aplicaciones deben tener permiso de lectura, escritura y modificación, dentro del directorio en donde se escribe el archivo. Yo ahora guardo los log de errores en una tabla que creo en una Base de datos, la cual se puede gestionar de mejor forma si se monta una interfaz de control de errores y de avisos automáticos. El caso es que para este ejemplo se debe hacer lo siguiente:

a) Agregar un nuevo elemento a la solución, seleccionando una aplicación de clase de plantilla global, que lleva por nombre global.asax..

b) En el archivo global.asax agregar las siguientes líneas de código en el método Applicatio_Error:

void Application_Error(object sender, EventArgs e) {
try {
string strFile = Server.MapPath("log.txt");
System.IO.StreamWriter log = new System.IO.StreamWriter(strFile);

System.Exception exc = Server.GetLastError();

log.WriteLine(exc.ToString());
log.Close();
} catch (System.Exception ex) {

}
finally {
Response.Redirect("Pagina de mensaje de error amigable.aspx");
}
}

Ahora, si la página se salta el manejo de errores de página, el error se capturará en este método y se registrará, luego se redireccionará a una página que puede desplegar un mensaje amigable a un usuario.


Manejando los errores en el web.config

Bueno amigos, este tipo de majeo de errores es el más conocido y es el que se utiliza siempre, lo voy a poner solo por los muchachos que consultan mi blogs y que se están iniciando en esto.

El manejo de errores en el web.config, consiste más que en registrar un error, esta asociado a controlar posibles tipos de errores y/o desplegar una interfaz con un mensaje amigable para el usuario, la forma de definir este tipo de manejo de errores es la siguiente:


a) Dentro del nodo system.web del archivo web,config habilitaremos o agregaremos el subnodo customError.

b) En el nodo customError definiremos los siguientes parámetros:

<configuration>
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="pagina error amigable.aspx"/>
</system.web>
</configuration>


Con esto se logra que cuando exista un error en alguna aplicación se despliegue un mensaje amigable al usuario

c) Tambien es factible definir la redirección de páginas por un un número de error en especícico, por ejemplo:

<configuration>
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="frmMensaje.aspx>
<error statusCode="500" redirect="PaginaError.aspx"/>
</system.web>
</configuration>


Para probar el funcionamiento del mensaje de error, agregaremos en la página de Default.aspx un link button, apuntando a una página inexistente, al ejecutarse este link button al no existir la página se redireccionará a la página de error en donde se encuentra el mensaje respectivo.