Академический Документы
Профессиональный Документы
Культура Документы
1.- Introducción a C#
C# (pronunciado en inglés “C Sharp” y en español “C Almohadilla”) es el nuevo
lenguaje diseñado por Microsoft para su plataforma .NET. En concreto, ha sido
diseñado por Scott Wiltamuth y Anders Hejlsberg, éste último también conocido por
haber sido el diseñador del lenguaje Turbo Pascal y la herramienta RAD Delphi.
Permite definir estructuras, que son clases un tanto especiales: sus objetos
se almacenan en pila, por lo que se trabaja con ellos directamente y no
referencias al montículo, lo que permite accederlos más rápido. Sin embargo,
esta mayor eficiencia en sus accesos tiene también sus inconvenientes,
fundamentalmente que el tiempo necesario para pasarlas como parámetros a
métodos es mayor (hay que copiar su valor completo y no sólo una
referencia) y no admiten herencia (aunque sí implementación de interfaces)
Como primer contacto con C#, nada mejor que escribir el típico programa de
iniciación “Hola Mundo”. Este programa lo único que hace al ejecutarse es mostrar por
pantalla el mensaje “Hola Mundo”, y su código es:
csc HolaMundo1.cs
HolaMundo1
¡Hola Mundo!
Una vez que ya sabemos cómo compilar y ejecutar aplicaciones escritas en C#,
es el momento de analizar detenidamente el significado del código anterior:
1: class HolaMundo1
2: {
3: public static void Main()
4: {
5: System.Console.WriteLine(“¡Hola Mundo!”);
6: }
7: }
los caracteres // y el final de la línea donde aparecen y a todo texto comprendido entre
los caracteres /* y */
La partícula que antecede al nombre del método indica cuál es el tipo de valor
que se devuelve tras la ejecución del método, y en este caso es void que significa que no
se devuelve nada. Por su parte, los paréntesis que se colocado tras el nombre del método
indican cuáles son los parámetros éste toma. Éstos parámetros permiten variar el
resultado de la ejecución del método en cada llamada al mismo, según los valores que
para ellos se especifiquen. Como en este caso los paréntesis están vacíos, nuestro
método no toma parámetros de ningún tipo.
Las palabras public y static que anteceden a la declaración del tipo de valor
devuelto son modificadores opcionales del significado de la declaración de método.
public indica que el método es público; es decir, que puede llamársele desde código
escrito dentro cualquier otra clase. En caso de no incluirse este modificador se habría
considerado que el método es privado (equivalente a haber usado la partícula private),
lo que significa que sólo sería correcto llamarle desde dentro de la misma clase en que
se declara. Por su parte, static indica que es un método estático; es decir, asociado a la
clase dentro de la que se define y no a los objetos que se creen a partir de la misma, por
lo que para acceder a él se usará la sintaxis nombreClase.NombreMétodo(parámetros) –
en nuestro caso HolaMundo1.Main()- y no objeto.NombreMétodo(parámetros) como
corresponde a los métodos no estáticos.
de este parámetro es String[], que significa que es una tabla de cadenas de texto
(objetos String); y su nombre, que es el que habrá de usarse dentro del código del
método Main() para hacerle referencia, puede ser cualquiera (en el ejemplo es args)
Por otro lado, la primera y última forma de uso del método Main() muestran que
éste no tiene porque no devolver ningún valor, sino que puede devolver uno de tipo int.
Dicho valor sería interpretado como código de retorno de la aplicación, que suele usarse
para indicar si la aplicación a terminado con éxito (generalmente valor 0) o no (otros
valores según la causa de la terminación anormal) Un int no es más que un tipo de datos
capaz de almacenar valor enteros comprendidos entre –2.1471483.648 y 2.1471483.647.
Finalmente, la única línea que nos queda por estudiar de nuestro sencillo
programa de ejemplo es precisamente el código a ejecutar; es decir, el código de su
método Main() Recordemos que este código era:
5: System.Console.WriteLine(“¡Hola Mundo!”);
Nótese que también es necesario usar la opción /t: para indicar que deseamos
crear un ejecutable de ventanas, pues por defecto se crean ejecutables de consola.
using System;
class HolaMundo2
{
public static void Main()
{
Console.WriteLine(“¡Hola Mundo!”);
}
}
Los espacios de nombres también son útiles para evitar conflictos en caso de que
se quiera usar clases de igual nombre pero procedentes de distintos fabricantes, pues las
diferenciaríamos por su espacio de nombres. Para esto, es necesario que no coincidan
los nombres éstos espacios, y una buena forma de hacerlo es dándoles el nombre de la
empresa que desarrolló la clase, o el nombre del dominio de Internet de ésta, etc.
Para indicar que una clase forma parte de un espacio de nombres basta incluir su
definición dentro de la definición de un espacio de nombres. Por ejemplo, si queremos
definir nuestra clase de ejemplo anterior dentro de un espacio de nombres llamado
Pruebas bastaría añadir estas líneas:
using System;
namespace Pruebas
{
class HolaMundo3
{
public static void Main()
{
Console.WriteLine(“¡Hola Mundo!”);
}
}
}
Antes se comentó que es posible declarar el método Main() de modo que tome
un parámetro de tipo String[] que contenga los argumentos con los que se llamó a la
aplicación. Es decir, de una de estas dos formas:
using System;
class HolaMundo4
{
public static void Main(String[] args)
{
Console.WriteLine(“¡Hola {0}!”, args[0]);
}
}
HolaMundo4 José
¡Hola José!
En C# los tipos básicos son tipos del mismo nivel que cualquier otro tipo del
lenguaje. Es decir, heredan de System.Object y pueden ser tratados como objetos de la
misma por cualquier rutina que espere un System.Object, lo que cual es muy útil para
el diseño de rutinas genéricas, que admitan parámetros de cualquier tipo. En realidad
todos los tipos básicos de C# son simples alias de tipos del espacio de nombres System,
como se recoge en la última columna de la tabla. Por ejemplo, sbyte es alias de
System.Sbyte y da igual usar una forma del mismo u otra.
if (condición)
intruccionesIf
else
intruccionesElse
using System;
class HolaMundo5
{
public static void Main(String[] args)
{
if (args.Length > 0)
Console.WriteLine(“¡Hola {0}!”, args[0]);
else
Console.WriteLine(“¡Hola mundo!”);
}
}
B) Instrucción Switch Para aquellos casos en los haya que ejecutar unos u otros
bloques de instrucciones según el valor de una determinada expresión C#
proporciona la instrucción condicional switch, cuya forma de uso es:
switch(condición)
{
case caso1: instrucciones1: break;
case caso2: instrucciones2: break;
...
default: instruccionesDefecto; break;
}
using System;
class HolaMundo6
{
public static void Main(String[] args)
{
if (args.Length > 0)
switch(args[0])
{
case “José”: Console.WriteLine(“Hola José. Buenos
días”);
break;
case “Paco”: Console.WriteLine(“Hola Paco. Me alegro
de verte”);
break;
default: Console.WriteLine(“Hola {0}”, args[0]);
}
else
Console.WriteLine(“Hola Mundo”);
}
}
while (condición)
instrucciones
using System;
class HolaMundo7
{
public static void Main(String[] args)
{
int actual = 0;
if (args.Length > 0)
while (actual < args.Length)
{
Console.WriteLine(“¡Hola {0}!”,
args[actual]);
actual = actual + 1;
}
else
Console.WriteLine(“¡Hola mundo!”);
}
}
Puede observarse que la primera línea del método Main() no contiene ahora una
instrucción, sino que contiene una declaración de una variable de tipo int, nombre
actual y valor inicial 0 que usaremos en la sentencia iterativa para saber cuál es la
posición del argumento a mostrar en cada ejecución de la misma. El valor de esta
variable se irá aumentando en una unidad, para así asegurar que siempre mantiene el
valor adecuado para ir mostrando cada uno de los argumentos de llamada y para
asegurar que la instrucción while termine de ejecutarse alguna vez, lo cual ocurrirá
cuando se hallan mostrado todos los argumentos.
do
instrucciones
while (condición);
Como se ve, do ... while especialmente útil para aquellos casos en los que hay
que asegurar que las instrucciones en él contenidas se ejecuten al menos una vez, aún
cuando la condición sea falsa desde el principio. Un ejemplo de su uso es este código:
using System;
class HolaMundo8
{
public static void Main()
{
String leído;
do
{
Console.WriteLine(“Clave: “);
leído = Console.ReadLine();
}
while (leído != “José”);
Console.WriteLine(“Hola José”);
}
}
B) Instrucción For Es otra variante del while que permite compactar el código de
este tipo de bloques. Su forma de uso es:
Como se ve, la instrucción for recoge de una forma muy compacta el uso
principal de la instrucción while normal, siendo un ejemplo de su uso:
using System;
class HolaMundo9
{
public static void Main(String[] args)
{
if (args.Length > 0)
for (int actual = 0; actual < args.Length;
actual++)
Console.WriteLine(“¡Hola {0}!”,
args[actual]);
else
Console.WriteLine(“¡Hola mundo!”);
}
}
2
En realidad, los campos de inicialización e incremento pueden contener cualquier tipo de instrucción,
aunque no suele ser habituar usarlos en un sentido diferentes al descrito.
using System;
class HolaMundo10
{
public static void Main(String[] args)
{
if (args.Length > 0)
foreach(String arg in args)
Console.WriteLine(“¡Hola {0}!”, arg);
else
Console.WriteLine(“¡Hola mundo!”);
}
}
b) Para los programadores más avanzados, puede ser interesante comentar que
la instrucción foreach puede usarse para recorrer cualquier objeto que sea
una colección, entendiéndose como tal cualquier objeto de una clase que
implementa la interfaz IEnumerable Esta interfaz consta de un único
método getEnumerator(), que ha de devolver un objeto que implemente la
interfaz IEnumerator. Esta interfaz define las operaciones necesarias para
recorrer los elementos de la colección, y consta de los siguientes métodos:
Lo primero que hemos de hacer es crear un nuevo proyecto donde almacenar los
archivos de la aplicación. Para ello pulsamos File -> New -> Project y obtendremos
una ventana desde la que podremos seleccionar tanto el lenguaje con el que vamos a
trabajar como el tipo de proyecto que vamos a desarrollar, el nombre del mismo y el
directorio base en el que se almacenarán los archivos del proyecto. Así, con las opciones
que nosotros seleccionaremos el aspecto final de esta ventana será el siguiente:
Una vez configuradas todas estas opciones, sólo queda pulsar el botón OK para
que se cree toda la infraestructura adecuada para que podamos empezar a trabajar en
nuestro proyecto. La ventana que tras ello se obtiene tiene un aspecto similar al
siguiente:
Haciendo doble click sobre el título de cada una de las dos últimas ventanas
anteriores veremos que aparece un nuevo botón junto a la típica cruz de cierre de
ventana. Este botón nos permitirá ocultar estas ventanas en la barra derecha que hay en
la ventana principal de Visual Studio. De este modo, se consigue que mientras no nos
hagan falta las tendremos ocultas y nuestro área de trabajo será mayor, mientras que en
el momento que nos sean necesarias, las recuperaremos rápidamente sin ni siquiera
tener que hacer un click (basta llevar el ratón sobre ellas)
Ahora que ya estamos familiarizados con el entorno con el que vamos a trabajar,
podemos empezar a diseñar la interfaz de nuestra aplicación. Para ello, de la barra de
herramientas iremos seleccionando los controles que necesitemos y los iremos
arrastrando sobre la ventana de diseño (ver Imagen 4). A medida que los vayamos
usando se explicarán a fondo estos controles, y por el momento sólo diremos que son:
Como podrá notar, no todos los controles que arrastremos sobre la ventana de
diseño se mostrarán sobre ésta, sino que algunos lo harán en un área en blanco situado
debajo de ella. Esto se debe a que son controles que, o no tienen una componente visual,
o no merece la pena mostrarla en la zona de diseño.
Si tras arrastrar un control éste no tiene el tamaño que a nos interesa, podemos
modificar este tamaño “tirando” de él mediante los cuadrados que aparecen en sus
extremos (igual que en cualquier programa de tratamiento de imágenes) Nótese como a
medida que vaya modificando el tamaño o posición de un control se irán actualizando
automáticamente los valores de las propiedades correspondientes a su alto (propiedad
Height), ancho (Width), posición en el eje OX de su esquina superior izquierda (Left)
y posición en OY de su esquina superior izquierda (Top)
Todos los controles que hemos creado cuentan con una serie de valores por
defecto para sus propiedades, como se puede observar echándoles un vistazo en la
ventana de propiedades. Muchos de estos valores son los más utilizados generalmente y
nos vienen bien; sin embargo, hay otros que no nos interesan tal y como están por lo
que tendremos que cambiarlos (por ejemplo, el texto por defecto de nuestro editor de
texto no debería ser richTextBox1) Para ello, iremos seleccionando cada uno de los
objetos de nuestra aplicación y modificando los valores de sus propiedades en la
ventana de propiedades como se indica:
Para terminar con el diseño la interfaz de nuestra aplicación nos queda por
diseñar únicamente el menú principal. De las propiedades del objeto MainMenu sólo
hemos de cambiar su nombre por menu, siendo lo verdaderamente interesante el diseño
de los submenús que en el se contendrán, lo cual se hace de forma muy sencilla y
vistosa sin más que ir rellenando los recuadros Type Here adecuados con los nombres
de los submenús que deseemos ir creando hasta obtener la siguiente estructura:
Salir
La siguiente imagen muestra gráficamente el proceso de relleno de recuadros
Type Here antes comentado:
+ En el texto que muestran los menús (y otros controles como los botones) le
podemos incluir un carácter & antes de cualquier letra que será interpretado como
carácter a usar para acceder al mismo mediante la combinación Alt+tecla Además, el
carácter que haya a la derecha de este & aparecerá subrayado para indicar que es el
usado para acceder rápidamente al control con dicha combinación4.
4
Si se incluyen más de un & los siguientes al primero son ignorados. Si se desea que & forme parte del
texto del control habrá que incluir dos & seguidos (&&)
+ Por defecto todos los submenús aparecen activados; es decir, de modo que
puedan ser seleccionados. Sin embargo, en el caso del submenú Reabrir no nos interesa
que esto sea posible hasta que se haya abierto algún fichero, por lo que hemos de
modificar su propiedad Enabled y darle el valor false inicialmente.
// ...
miMenu.Click += new EventHandler(miCódigoRespuesta);
// ...
6
También conocido como Common Language Runtime ó CLR
Este será el método que usaremos en nuestro editor de texto para asociar código
de respuesta, y a continuación se describe cómo escribir este código para cada uno de
los controles de nuestra aplicación para conseguir la funcionalidad deseada en la misma:
1. menuNuevo:
Nótese que también realizamos otras acciones en el código del método. Éstas
consisten en cambiar el título de la ventana principal por EditorEjemplo, ya que en este
título almacenaremos información sobre el nombre del fichero abierto en cada momento
pero al crear uno nuevo no tiene nombre, y desactivar el submenú Reabrir, ya que no
tiene sentido reabrir ningún archivo porque estamos creando uno nuevo.
2. menuAbrir
Tras cargar el contenido del fichero de texto en nuestra caja de texto, sólo queda
modificar el título de la ventana de propiedades para que contenga el nombre del fichero
abierto entre corchetes (nótese el uso de + como operador de concatenación de cadenas)
y, dado que ahora sí tenemos un fichero abierto, activar la posibilidad de reabrirlo.
3. MenuReabrir
rtbTexto.LoadFile(nombreFichero,
RichTextBoxStreamType.PlainText);
}
El código de este método es mucho más sencillo que en el caso anterior, ya que
ahora no hemos de actualizar la barra de título con el nombre del fichero abierto porque
era el que ya había; y no hemos de activar el menú Reabrir porque ya estaba activado
(de hecho, es el botón pulsado)
Para obtener el nombre del fichero hemos usado el método Substring() definido
para cualquier cadena (clase String) que devuelve la subcadena comprendida entre el
elemento cuyo índice coincide con el valor de su primer parámetro y cuya longitud es la
indicada en el segundo. Como el primer elemento de la barra de título siempre será un
corchete ya que lo que se indica en ella es el nombre del fichero abierto, nos saltaremos
el primer elemento del texto del título y obtendremos la subcadena que comienza en el
índice 1 (las cadenas se indexan desde 0 en C#) Para obtener la longitud de la subcadena
a obtener usamos el método LastIndexOf() de la clase String que devuelve el valor del
índice de la última aparición de la subcadena que se le pasa como parámetro.
4. menuGuardar
Al pulsar este submenú hemos de guardar el contenido del texto que se esté
editando dentro del fichero que se está editando, de modo que todos los cambios hechos
en la caja de texto se hagan permanentes en el fichero. Para ello, hemos de comprobar si
el fichero que estamos escribiendo es un fichero nuevo o no, ya que en el primer caso
habría que solicitar al usuario un nombre de fichero donde guardar esta información y
en el segundo caso no. Esto lo hacemos así:
if (this.Text == "EditorEjemplo")
menuGuardarComo.PerformClick();
else
{
nombreFichero = this.Text.Substring(1,
this.Text.LastIndexOf("]") - 1);
rtbTexto.SaveFile(nombreFichero,
RichTextBoxStreamType.PlainText);
}
}
Véase pues, que lo que se hace para detectar si el fichero es nuevo consiste en
comprobar si el texto de la barra de título de la ventana del editor coincide con el valor
de ésta por defecto, caso en que ello querría decir que sí es nuevo y, por consiguiente,
habría que solicitar el nombre del fichero donde guardar; es decir, estaríamos en un caso
equivalente al de haber pulsado el submenú Guardar como, por lo que lo que haremos
será simular que este se ha pulsado llamando al método PerformClick() del mismo.
5. menuGuardarComo
Cuando se selecciona este botón hay que mostrar al usuario una de las típicas
ventanas de Windows en las que se solicita un nombre de fichero donde guardar
información. Sólo en caso de que se haya seleccionado un nombre de fichero en esta
ventana y se haya pulsado su botón OK se guardará el contenido de la caja de texto de
nuestro editor en el archivo indicado. Para hacer esto se ejecuta el siguiente código:
Del código puede deducirse fácilmente que lo único que se hace es llamar al
método ShowDialog() del dlGuardarArchivo para que muestre la ventana antes
comentada, comprobar que se pulse el botón OK de la misma viendo si el valor de
6. menuImprimir
El código de respuesta a este evento es, por tanto, tan simple como:
cadena que se le pasa como parámetro usando la fuente y el color indicados dentro del
área del papel que se le especifica en su último parámetro. Para especificar el texto y el
color se usan directamente los valores almacenados en las propiedades Text y Font de
nuestro rtbTexto, mientras que para especificar el color a usar es necesario generar un
SolidBrush a partir del color almacenado en la propiedad ForeColor de dicha caja de
texto, ya que esto es lo que DrawString() espera. Finalmente, para especificar el área
de impresión se ha optado por utilizar un objeto RectangleF que almacena información
sobre el rectángulo correspondiente a los márgenes a usar (posición en OX de su
esquina superior izquierda, posición en OY, ancho y alto) Los valores pasados a éste
objeto en su constructor son los que se obtienen por defecto a través de la propiedad
MarginBounds del objeto PrintPageEventArgs pasado como argumento al método.
7. menuSalir
Cuando se pulse el botón Salir lo que hay que hacer es, como su propio nombre
indica, abortar la ejecución del editor. Esto se hace con una única instrucción: llamando
al método Close() de la ventana principal del editor para cerrarla. Es decir, así:
8. menuFuente
9. menuCréditos
En este caso hemos usado una variante del método Show() diferente a la vista
anteriormente en la que como segundo parámetro pasamos la cadena de texto que será
utilizada como título de la ventana a mostrar.
Una vez escrito todo los códigos de respuesta indicados, nuestra aplicación ya
estará lista para funcionar. Podemos probarla seleccionando en el menú principal de
Visual Studio Debug -> Start, siendo el aspecto de la misma durante su ejecución:
Una de las grandes ventajas de los servicios Web es que pueden ser accedidos
desde cualquier aplicación que sea capaz de generar mensajes e interpretar mensajes
escritos en SOAP, aún cuando ésta no esté diseñada para la plataforma .NET Es más,
los aplicaciones que consuman estos servicios no necesitan conocer ni cuál es la
plataforma ni cuál es el modelo de objetos ni cuál es el lenguaje utilizado para
implementar estos servicios. Otra gran ventaja es que son tremendamente sencillos de
escribir, pues como veremos a continuación basta hacer unos retoques mínimos al
código de una clase cualquiera para convertirla en un servicio Web que podrá ser
accedido remotamente; por no mencionar la enorme facilidad y transparencia con la que
aquellos clientes del servicio escritos bajo .NET pueden acceder al mismo, gracias a las
utilidades generadoras de proxys que Microsoft proporciona.
Para ver lo fácil que es escribir un servicio Web, en primer lugar vamos a
escribir una sencilla clase en C# que simplemente consta de un único método que nos
devuelve la fecha actual. Más adelante veremos cómo es trivial la conversión de la
misma en servicio Web. El código de nuestra clase es:
using System;
class ServicioFecha
{
public String Fecha (bool detalles)
{
if (detalles)
return DateTime.Now.ToLongDateString();
else
return DateTime.Now.ToShortDateString();
}
}
Como se ve, los objetos de esta clase constan de sólo un método propio: el
método Fecha(), que devuelve la fecha actual incluyendo información detallada (día de
la semana, número de mes, día del mes y año con cuatro dígitos) o no (sin día de la
semana y sólo dos dígitos para el año) según indique su parámetro
Para convertir esta clase en un servicio Web sólo hemos de hacerla heredar de la
clase System.Web.Services, colocar el atributo [WebMethod] antes de la declaración
de cada uno de los métodos de la clase que deseemos que sean accesibles remotamente
e incluir una directiva WebService que indique al motor de ASP.NET (que es quien se
encargará de gestionar el acceso al servicio Web) de cuál es el lenguaje en que está
escrito el servicio Web y cuál es la clase que se expondrá como servicio Web
// Fichero: ServicioFecha.asmx
<% @ WebService Language=”C#” Class=”ServicioFecha” %>
using System;
using System.Web.Services;
Al abrir con Internet Explorer una página .asmx alojada en un servidor Web con
soporte ASP.NET se obtiene una página con información sobre el los servicios en esta
almacenados. Por ejemplo, si situamos nuestro anterior ejemplo en el directorio raíz de
la jerarquía virtual de IIS, al teclear en la barra de direcciones de Internet Explorer
http://localhost/ServicioFecha.asmx se obtiene:
Véase que esta página contiene información incluye datos sobre cuál es el
servicio Web ofrecido, cuáles son los métodos que se ofrecen y cuál es la signatura de
estos. Además, la página también incluye formularios desde los que podemos hacer
llamadas de prueba a los métodos del servicio Web.
Es importante señalar que para que la página de prueba se obtenga hay que
acceder al fichero .asmx a través de IIS; es decir, de modo que se haga que este se
active y procese la petición. Por eso, para acceder a ella no basta hacer doble click sobre
su icono en la ventana de exploración de discos de Windows, sino que hay utilizar un
dirección como la arriba indicada (URL)
Un proxy es una clase que ofrece la misma interfaz que el servicio Web al que se
pretende acceder pero que esta almacenada en la máquina local y no contiene la
verdadera implementación de los métodos ofrecidos por el servicio, sino que en su lugar
contiene código encargado de redirigir las llamadas que hagamos a sus métodos al
verdadero servicio Web. Gracias a los proxies, conseguimos comunicarnos con el
servicio remoto como si de una clase normal escrita en C# se tratase, y es el proxy el
encargado de intercambiar los menajes SOAP necesarios para la comunicación remota.
wsdl http://localhost/ServicioFecha.asmx
El proxy generado tendrá el mismo nombre que el fichero .asmx a partir del que
se genera pero extensión .cs Es posible cambiar este nombre si así se desea indicando
uno nuevo mediante la opción /out: de webserviceutil
A partir del proxy la escritura de una aplicación que haga uso del servicio es
trivial. Sólo hay que utilizar el proxy como si de la clase remota se tratase. Por ejemplo:
using System;
class ClienteFecha
{
public static void Main()
{
ServicioFecha s = new ServicioFecha();
De este código es fácil deducir que lo que se hace es crear un objeto de la clase
remota ServicioFecha y mostrar dos mensajes de texto, uno para probar el
funcionamiento de cada una de las formas de llamar al método Fecha(). Nótese la
absoluta transparencia de éste código respecto a la ubicación real de la clase remota.
Para compilar este cliente hay que tener en cuenta que en la clase proxy se
utilizan elementos definidos en otras librerías, por lo que hay que referenciarlas con:
Por defecto un servicio Web carece de estado, ya que por cada llamada a un
método de un servicio se crea una nuevo objeto de la clase a la que se hace la petición;
objeto que la atiende y es destruido tras ello. Por consiguiente, no se guarda
información sobre llamadas previas y por tanto los objetos de un servicio Web escrito
así no son verdaderos objetos, ya que lo que el realmente el cliente hace son llamadas
sueltas que no tienen relación entre sí.
método Accesos() mediante el cual los clientes pueden consultar el número total de
accesos que ha tenido la aplicación y un método AccesosMíos() mediante el cual los
clientes pueden consultar cuántos accesos ellos mismos han realizado:
using System;
using System.Web.Services;
class ServicioFechaEstado:WebService
{
[WebMethod(EnableSession=true)] public String Fecha(bool
detallada)
{
if (Application["Accesos"] == null)
Application["Accesos"] = 1;
else
Application["Accesos"] = ((int) Application["Accesos"]) +
1;
if (Session["Accesos"] == null)
Session["Accesos"] = 1;
else
Session["Accesos"] = ((int) Session["Accesos"]) + 1;
if (detallada)
return DateTime.Now.ToLongDateString();
else
return DateTime.Now.ToShortDateString();
}
if (Session["Accesos"] == null)
return 0;
else
return ((int) Session["Accesos"]);
Una vez modificado el .asmx sólo queda modificar el cliente que hemos estado
usando para probar el servicio para que haga uso de sus nuevas características:
using System;
using System.Net;
class ClienteFechaEstado
{
public static void Main()
{
ServicioFechaEstado s = new ServicioFechaEstado();
s.CookieContainer = new CookieContainer();
Visual Studio permite escribir y utilizar los servicios Web de una forma mucho
más cómoda que utilizando directamente el compilador en línea de comandos csc.exe
como se ha hecho en los ejemplo previos. A continuación veremos como escribir y
utilizar el servicio Web de ejemplo anterior usando esta herramienta.
Una vez que se cree el proyecto, Visual Studio nos ofrecerá un pantalla en
blanco donde podríamos ir colocando todos los controles que necesitemos 12 Nosotros
haremos doble click sobre la misma y pasaremos directamente a editar el código fuente
del servicio Web. Como se verá entonces, Visual Studio ya ha generado un esqueleto
para el mismo que incluye la directiva WebService con los valores de sus atributos
perfectamente configurados para funcionar con nuestra aplicación e incluso, dentro de
un comentario, habrá colocado código de ejemplo de cómo escribir un servicio Web.
Gracias a toda esta infraestructura generada automáticamente, nosotros sólo tenemos
que copiar los métodos antes escritos para ServicioFecha en esta ventana de código y
todo estará listo para funcionar.
11
Se supone que no hay más clientes accediendo simultáneamente al servicio Web
12
Aunque no tiene mucho sentido colocar controles con parte visual, ya que un servicio Web no tiene
componente visible, sino que es sólo lógica.
Una vez escrito el servicio Web, podemos pulsar CTRL+F5 para probar nuestro
servicio Web. Con ello conseguiremos que Visual Studio abra una ventana de Internet
Explorer que nos mostrará la página de prueba del servicio.
Tras esto sólo queda escribir el cliente que accederá al mismo. Para ello de
nuevo optaremos por realizar la aplicación cliente de consola ya creada pero con las
pequeñas modificaciones derivadas de que ahora la clase remota se llama WebService1
y de que Visual Studio evita tener que generar a mano el proxy para acceder a la misma.
Para crear una aplicación de consola seleccionamos File -> New -> Project en
el menú principal de Visual Studio y configuramos la ventana que aparece con:
Hecho esto sólo nos queda añadir la referencia al servicio Web necesaria para
que se pueda compilar correctamente el código del cliente. Esto se hace seleccionando
Project -> Add Web Reference en el menú principal de Visual Studio y escribiendo el
la barra de direcciones de la ventana que aparecerá (Address) la ruta del servicio Web a
referenciar, en nuestro caso http://localhost/ServicioFechaVS/ServicioFechaVS.asmx
Nótese que hay que incluir en la ruta el subdirectorio ServicioFechaVS, ya que es allí
donde Visual Studio colocó el servicio Web cuando se creó, que no es necesario
concatenar el ?WSDL al final de la misma, y que con sólo pulsar el botón OK de esta
ventana se añade al proyecto la referencia adecuada para poder acceder desde el mismo
al servicio ServicioFechaVS, sin que sea necesario que nosotros usemos alguna utilidad
que genere el proxy.
Sólo falta comentar que hay que añadir un using localhost; al comienzo del
código fuente, ya que por defecto todas las referencias a servicios Web se importan
organizándolas dentro de espacios de nombres llamados igual que el servidor donde
están alojados los servicios. Si nos interesase modificar esto siempre podremos hacerlo
a través del Explorador de Solución, seleccionando la carpeta Web References del
mismo y cambiando el nombre localhost que tiene un icono con la bola del mundo al
lado por el nombre deseado.
Dado que este protocolo se basa en HTTP y XML, puede ser interesante también
consultar las especificaciones de HTTP v1.1 (http://www.ietf.org/rfc/rfc2616.txt) y XML
v1.0 (http://www.w3.org/TR/REC-xml)
“Web Services: Building Reusable Web Components with SOAP and ASP.NET”
(http://www.msdn.microsoft.com/msdnmag/issues/01/02/webcomp/print.asp) de David S. Platt