Вы находитесь на странице: 1из 43

ÍNDICE

1.- INTRODUCCIÓN A C#........................................................................................................................2

2.- DESARROLLO DE APLICACIONES DE CONSOLA.....................................................................4

2.1 ESCRITURA Y COMPILACIÓN DE UNA APLICACIÓN BÁSICA.................................................................................4


2.2 ESPACIOS DE NOMBRES................................................................................................................................7
2.3 APLICACIONES CON ARGUMENTOS.................................................................................................................8
2.4 TIPOS BÁSICOS ..........................................................................................................................................9
2.5 INSTRUCCIONES CONDICIONALES ..................................................................................................................9
2.6 INSTRUCCIONES ITERATIVAS........................................................................................................................11

3.- DESARROLLO DE APLICACIONES DE VENTANAS................................................................17

3.1 INTRODUCCIÓN A VISUAL STUDIO .NET.....................................................................................................17


3.2 DISEÑO DE LA INTERFAZ............................................................................................................................20
3.3 DISEÑO DE LOS MENÚS...............................................................................................................................22
3.4 ASOCIACIÓN DE CÓDIGO A EVENTOS............................................................................................................24
3.5 ASOCIACIÓN DE CÓDIGO A EVENTOS EN VISUAL STUDIO.NET.......................................................................26

4.- DESARROLLO DE SERVICIOS WEB............................................................................................33

4.1 INTRODUCCIÓN A LOS SERVICIOS WEB.........................................................................................................33


4.2 ESCRITURA DE UN SERVICIO WEB...............................................................................................................33
4.3 PÁGINA DE PRUEBA DE UN SERVICIO WEB....................................................................................................35
4.4 ACCESO A UN SERVICIO WEB MEDIANTE SOAP.........................................................................................36
4.5 MANTENIMIENTO DEL ESTADO....................................................................................................................37
4.6 SERVICIOS WEB CON VISUAL STUDIO.NET................................................................................................40

5.- DOCUMENTACIÓN DE REFERENCIA.........................................................................................43


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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.

Aunque en realidad es posible escribir código para la plataforma .NET en


muchos otros lenguajes, como Visual Basic.NET o JScript.Net, C# es el único que
ha sido diseñado específicamente para ser utilizado en esta plataforma, por lo que
programarla usando C# es mucho más sencillo e intuitivo que hacerlo con
cualquiera de los otros lenguajes. Por esta razón, Microsoft suele referirse a C#
como el lenguaje nativo de .NET, y de hecho, gran parte de la librería de clases
base de .NET ha sido escrito en este lenguaje.

C# es un lenguaje orientado a objetos sencillo, moderno, amigable, intuitivo y


fácilmente legible que ha sido diseñado por Microsoft con el ambicioso objetivo de
recoger las mejores características de muchos otros lenguajes, fundamentalmente
Visual Basic, Java y C++, y combinarlas en uno sólo en el que se unan la alta
productividad y facilidad de aprendizaje de Visual Basic con la potencia de C++.

Aunque con la beta actualmente disponible del lenguaje no se consiguen


prestaciones en velocidad tan altas como usando el C++ tradicional, Microsoft
asegura que en futuras versiones se irá aumentando la eficiencia del lenguaje,
gracias fundamentalmente a la posibilidad de generar dinámicamente código
optimizado para aprovechar las características de la máquina sobre la que se ejecute
el programa.

Quizás el más directo competidor de C# es Java, lenguaje con el que guarda un


enorme parecido en su sintaxis y características. En este aspecto, es importante
señalar que C# incorpora muchos elementos de los que Java carece (sistema de tipos
homogéneo, propiedades, indexadores, tablas multidimensionales, operadores
redefinibles , etc.) y que según los benchmarks realizados la velocidad de ejecución
del código escrito en C# es ligeramente superior a su respectiva versión en Java1

A continuación se recoge de manera resumida las principales características de


C#. No se preocupe si no entiende algunas de ellas, ya que no es indispensable
hacerlo para seguir adecuadamente el resto del contenido del taller. Sólo se
comentan ahora para que los programadores más experimentados puedan obtener
una visión general del lenguaje:

 Dispone de todas las características propias de cualquier lenguaje orientado a


objetos: encapsulación, herencia y polimorfismo.

 Ofrece un modelo de programación orientada a objetos homogéneo, en el


que todo el código se escribe dentro de clases y todos los tipos de datos,
incluso los básicos, son clases que heredan de System.Object (por lo que los
métodos definidos en ésta son comunes a todos los tipos del lenguaje)
1
Los benchmarks han sido realizados usando la beta 1 del .NET SDK y el JDK 1.3. En breve estarán
disponibles en el Rincón en español de C# (http://tdg.lsi.us.es/~csharp)

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 2


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

 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)

 Es un lenguaje fuertemente tipado, lo que significa se controla que todas


las conversiones entre tipos se realicen de forma compatible, lo que asegura
que nunca se acceda fuera del espacio de memoria ocupado por un objeto.
Así se evitan frecuentes errores de programación y se consigue que los
programas no puedan poner en peligro la integridad de otras aplicaciones.

 Tiene a su disposición un recolector de basura que libera al programador de


la tarea de tener que eliminar las referencias a objetos que dejen de ser útiles,
encargándose de ello éste y evitándose así que se agote la memoria porque al
programador olvide liberar objetos inútiles o que se produzcan errores
porque el programador libere áreas de memoria ya liberadas y reasignadas.

 Incluye soporte nativo para eventos y delegados. Los delegados son


similares a los punteros a funciones de otros lenguajes como C++ aunque
más cercanos a la orientación a objetos, y los eventos son mecanismos
mediante los cuales los objetos pueden notificar de la ocurrencia de sucesos.
Los eventos suelen usarse en combinación con los delegados para el diseño
de interfaces gráficas de usuario, con lo que se proporciona al programador
un mecanismo cómodo para escribir códigos de respuesta a los diferentes
eventos que puedan surgir a lo largo de la ejecución de la aplicación.
(pulsación de un botón, modificación de un texto, etc.)

 Incorpora propiedades, que son un mecanismo que permite el acceso


controlado a miembros de una clase tal y como si de campos públicos se
tratasen. Gracias a ellas se evita la pérdida de legibilidad que en otros
lenguajes causa la utilización de métodos Set() y Get() pero se mantienen
todas las ventajas de un acceso controlado por estos proporcionada.

 Permite la definición del significado de los operadores básicos del


lenguaje (+, -, *, &, ==, etc.) para nuestros propios tipos de datos, lo que
facilita enormemente tanto la legibilidad de las aplicaciones como el
esfuerzo necesario para escribirlas. Es más, se puede incluso definir el
significado del operador [] en cualquier clase, lo que permite acceder a sus
objetos tal y como si fuesen tablas. A la definición de éste último operador se
le denomina indizador, y es especialmente útil a la hora de escribir o
trabajar con colecciones de objetos.

 Admite unos elementos llamados atributos que no son miembros de las


clases sino información sobre éstas que podemos incluir en su declaración.
Por ejemplo, indican si un miembro de una clase ha de aparecer en la
ventana de propiedades de Visual Studio.NET, cuáles son los valores
admitidos para cada miembro en ésta, etc.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 3


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

2.- Desarrollo de aplicaciones de consola


2.1 Escritura y compilación de una aplicación básica

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:

// HolaMundo1.cs: Ejemplo típico


class HolaMundo1
{
public static void Main()
{
System.Console.WriteLine(“¡Hola Mundo!”);
}
}

Si almacenamos este código en un fichero de texto plano de nombre


HolaMundo.cs podemos compilarlo abriendo una ventana de consola (MS-DOS) y, tras
colocarnos en el directorio donde hayamos almacenado el fichero, ejecutando:

csc HolaMundo1.cs

csc es el nombre del compilador de C#, y la orden anterior simplemente indica


que deseamos compilar el fichero de código fuente HolaMundo.cs, y tras ejecutarla el
compilador generará un fichero de nombre HolaMundo.exe que contendrá el ejecutable
de nuestra sencilla aplicación de ejemplo. Para ejecutarlo basta escribir:

HolaMundo1

El resultado que veremos por la pantalla será:

¡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: }

Nótese que se ha eliminado la línea // HolaMundo.cs: Ejemplo típico que


aparecía en la versión original del código. Esto se debe a que es sólo un comentario que
se introduce para facilitar la legibilidad del código a los lectores humanos pero que el
compilador ignora completamente, por lo que no la incluiremos en el presente análisis.
Cabe señalar que en C# se considera comentario a todo aquel texto comprendido entre

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 4


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

los caracteres // y el final de la línea donde aparecen y a todo texto comprendido entre
los caracteres /* y */

Como en la introducción se comentó, todo el código escrito en C# se ha de


escribir dentro de una clase. Así, lo que en la línea 1: se dice es que lo a que
continuación se incluirá es la definición de una clase (class) a la que le daremos el
nombre de HolaMundo1, estando la definición de la misma comprendida entre la
primera llave que aparezca (línea 2:) y su correspondiente llave de cierre (línea 7:)

Lo que dentro de la definición de la clase se dice (línea 3:) es que va a tener un


método de nombre Main cuyo código es el indicado entre la próxima llave de apertura
(línea 4:) y su respectiva llave de cierre (línea 6:) Un método no es más que un conjunto
de instrucciones a las que se les asocia un nombre, de modo que si posteriormente se
desea ejecutarlas basta referenciarlas por su nombre en vez de tener que reescribirlas.

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.

El nombre, modificadores, tipos de parámetros y tipo de valor devuelto que se


han dado al método Main() del ejemplo no son arbitrarios, sino que se corresponden con
una de las cuatro posibles formas de definir el punto de entrada de nuestra aplicación.
Este punto de entrada es sencillamente el método a partir del cual se comenzará a
ejecutar el código de nuestra aplicación, y su declaración ha de ser de una de estas
cuatro formas posibles:

public static int Main()


public static void Main()
public static void Main(String[] args)
public static int Main(String[] args)

El parámetro que puede tomar el método Main() almacena la lista de


argumentos con los que se llamó a la aplicación; y como se ve, en caso de que no
vayamos a utilizarla no es necesario especificarla en la declaración de Main(). El tipo

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 5


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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!”);

Esta instrucción lo único que hace es ejecutar el método WriteLine() de la clase


Console Ésta clase viene predefinida en la librería de clases de .NET, y WriteLine() es
un método de clase (static) definido dentro de ella (al igual que nuestro Main() lo está
en la clase HolaMundo1) cuyo código lo que hace es imprimir en el dispositivo de
salida estándar de nuestra máquina (por defecto la ventana de consola) la cadena de
texto que le pasemos como parámetro. Una cadena de texto es cualquier secuencia de
caracteres encerrada entre comillas dobles (“...”), aunque dichas comillas no forman
parte de la cadena como puede observarse viendo que al ejecutar el ejemplo no se
muestran en pantalla.

Antes de continuar es importante resaltar algunos aspectos:

1) C# es un lenguaje sensible a las mayúsculas, los que significa que no da igual


la capitalización con la que se debe escribir cada identificador. Es decir, no es lo mismo
escribir Console que COnsole o que CONSOLE, y en caso de que lo hagamos de una de
las dos últimas formas el compilador producirá un error indicando que no conoce
ninguna clase con ese nombre. Un error común entre programadores acostumbrados a
Java es llamar al punto de entrada del programa main() en vez de Main()

2) Todo el código escrito en un fichero de código fuente en C# es autocontenido.


Es decir, no son necesarios ni ficheros de cabecera ni ficheros IDL ni ningún otro tipo
de fichero adicional aparte del propio fichero de código fuente.

3) Por defecto, el compilador sólo busca definiciones de clases predefinidas en el


fichero mscorlib.dll, y si vamos a usar clases definidas en otro fichero hemos de
indicárselo mediante la opción /r del compilador. Por ejemplo, un error frecuente entre
principiantes es no saber cómo compilar una aplicación de ventanas, pues hay que
indicar en qué ficheros se encuentran las clases predefinidas necesarias así:

csc /t:winexe /r:System.Winforms.dll;System.dll;Microsoft.Win32.Interop.dll


Fuente.cs

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.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 6


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

2.2 Espacios de nombres

Un espacio de nombres es una forma de organizar las clases definidas en la


librería de .NET en grupos de clases relacionadas entre sí. Por ejemplo, dentro del
espacio de nombres System usando en el ejemplo HolaMundo están incluidas todas las
clases más frecuentemente usadas en cualquier aplicación .NET. Dado que puede ser
tedioso tener que preceder todas nuestras referencias a clases con el nombre del espacio
de nombres en que están definidas, en C# también se da la posibilidad de hacer:

using System;

class HolaMundo2
{
public static void Main()
{
Console.WriteLine(“¡Hola Mundo!”);
}
}

Las sentencias using siempre han de incluirse en el fichero fuente antes de la


declaración de cualquier clase y permite indicar cuáles son los espacios de nombres que
se usaran implícitamente. En nuestro ejemplo, gracias al uso esta sentencia no es
necesario preceder la referencia a la clase Console con el nombre del espacio de
nombres en que está definida, sino que el compilador automáticamente intentará
encontrarla buscándola en el espacio de nombres System.

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!”);
}
}
}

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 7


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

2.3 Aplicaciones con argumentos

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:

public static void Main(String[] args)


public static int Main(String[] args)

String[] indica que el parámetro Main() es una tabla de cadenas. Como en la


mayoría de lenguajes de programación, una tabla no es más que una conjunto de valores
ordenados y de tamaño fijo. Los corchetes [] en la declaración del parámetro indican
que éste es una tabla, y String indica que es una tabla de cadenas. Es importante resaltar
el hecho de que aunque una tabla siempre tiene un tamaño fijo, éste tamaño no forma
parte de la declaración de la misma. Esto permite que una misma variable de tipo tabla
pueda almacenar tablas de diferentes tamaños, aunque el tamaño de la tabla almacenada
en cada instante no pueda modificarse.

Los elementos de la tabla de cadenas que puede tomar como parámetro el


método Main() son cada uno de los argumentos con los que se llamó al programa. En
C# las tablas se indexan desde 0, lo que significa que su primer argumento se almacena
en la posición 0, el segundo en la posición 1, etc. Esto es importante tenerlo presente a
la hora de acceder a cada elemento de una tabla, para lo que se usa la notación
tabla[posiciónElemento] como muestra la siguiente variante de la clase HolaMundo

using System;

class HolaMundo4
{
public static void Main(String[] args)
{
Console.WriteLine(“¡Hola {0}!”, args[0]);
}
}

Es importante notar la forma especial en que se ha realizado la llamada al


método WriteLine() En este caso, la cadena a imprimir contiene una secuencia de
caracteres de la forma {número} que indica que se ha de mostrar en su lugar el valor del
argumento número+2 de WriteLine() Así, en nuestro ejemplo {0} indica que se ha de
mostrar el valor del segundo argumento; es decir, el de args[0], que es el primer
argumento con que se llamó a HolaMundo4 (las tablas se indizan empezando por 0)

Ahora cuando ejecutemos el programa hemos de pasarle un argumento y en


función del valor que éste tome se mostrará un mensaje de bienvenida personalizado.
Por ejemplo, si ejecutamos el programa así:

HolaMundo4 José

Se nos mostrará el siguiente mensaje de saludo:

¡Hola José!

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 8


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

2.4 Tipos básicos

Ahora que ya sabemos cuál es la estructura básica de un programa en C#, es el


momento más adecuado para empezar a conocer cuáles son los tipos de datos básicos de
los que el lenguaje dispone. Estos se resumen en la siguiente tabla:

Tipo Descripción Bi tsRango Alias


sbyte Bytes con signo 8 -128 - 127 SByte
byte Bytes sin signo 8 0 - 255 Byte
short Enteros cortos con signo 16 -32.768 - 32.767 Int16
ushort Enteros cortos sin signo 16 0 - 65.535 UInt16
int Enteros normales 32 -2.147.483.648 - 2.147.483.647 Int32
uint Enteros normales sin signo 32 0 - 4.294.967.295 UInt32
-9.223.372.036.854.775.808 – Int64
long Enteros largos 64
9.223.372.036.854.775.807
ulong Enteros largos sin signo 64 0 - 18.446.744.073.709.551.615 Uint64
float Reales con 7 dígitos de precisión 32 1,5×10-45 - 3,4×1038 Float
double Reales con 15-16 dígitos de precisión 64 5,0×10-324 - 1,7×10308 Double
decimal Reales con 28-29 dígitos de precisión 128 1,0×10-28 - 7,9×1028 Decimal
boolean Valores lógicos 32 true, false Boolean
char Caracteres Unicode 16 Unicode 0 – Unicode 65535 Char
string Cadenas de caracteres var Permitido por memoria String
object Cualquier objeto var Depende del objeto Object

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.

2.5 Instrucciones condicionales

C# ofrece una serie de instrucciones que permiten ejecutar bloques de código


sólo si se da una determinada condición. Estas son:

A) Intrucción If  Como la mayoría de los lenguajes de programación, C# incluye la


instrucción condicional if, cuya forma de uso es:

if (condición)
intruccionesIf
else
intruccionesElse

El significado de esta instrucción es el siguiente: se evalúa la condición indicada,


y en caso de ser cierta se ejecutan las instruccionesIf; mientras que si no lo es se
ejecutan las instruccionesElse La rama else es opcional, y si se omite y la condición es
falsa se seguiría ejecutando a partir de la siguiente instrucción al if. Si las
intruccionesIf o las instruccionesElse constan de más de una instrucción es necesario
encerrar el conjunto de instrucciones de las que constan entre llaves ({...})

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 9


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

Un ejemplo de aplicación de esta instrucción es esta variante del HolaMundo:

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!”);
}
}

En este caso, si ejecutamos el programa sin indicar ningún argumento al lanzarlo


veremos que el mensaje que se imprime es ¡Hola Mundo!, mientras que si lo
ejecutamos indicando algún argumento se mostrará un mensaje de bienvenida
personalizado (del mismo tipo que en el HolaMundo2)

Nótese que para saber si se han pasado argumentos en la llamada al programa


y tomar una u otra decisión según el caso, lo que se hace en la condición del if es
comprobar si la longitud de la tabla de argumentos es superior a 0. Para conocer esta
longitud se utiliza la propiedad Length que toda tabla tiene definida. Recuérdese que el
tamaño de una tabla es fijo, por lo que esta propiedad es de sólo lectura y no es válido
intentar escribir en ella (como por ejemplo, haciendo args.Length = 2)

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;
}

El significado de esta instrucción es el siguiente: se evalúa la condición, y si su


valor coincide con el de caso1, se ejecutan las instruciones1; si coincide con el de caso2
se ejecutan las instrucciones2; y así para cada caso mientras no se encuentra alguno que
coincida con el valor resultante de la evaluación. La rama default es opcional, y en caso
de agotarse todos los casos y no encontrarse coincidencia, entonces se pasaría a ejecutar
las intruccionesDefault en caso de que dicha rama apareciese; y si no apareciese, se
pasaría directamente a ejecutar la instrucción siguiente al switch
En realidad, la rama default, si se usa, no tiene porqué aparecer la última,
aunque se recomienda que lo haga porque ello facilita la legibilidad del código.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 10


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

Un ejemplo de uso de esta instrucción es el siguiente:

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”);
}
}

Ahora, nuestro programa reconoce a algunas personas y les saluda de forma


especial. Nótese que al final de cada grupo de instrucciones se ha de incluir una
instrucción break que indique el final de la lista de instrucciones asociadas a esa rama
del switch En realidad, esta instrucción puede ser sustituida por una instrucción goto
usada de la forma goto casoi (o goto default) que indique qué otras ramas del switch
han de ejecutarse tras llegar a ella. Además, en la última rama del switch no tiene
porqué aparecer obligatoriamente ninguna de estas dos sentencias.

Para los programadores habituados a lenguajes como C++ es importante


resaltarles el hecho de que, a diferencia de dicho lenguaje, C# obliga a incluir una
sentencia break o una sentencia goto al final de cada rama del switch, con la idea de
evitar errores muy comunes en éste lenguaje, donde no es forzoso hacerlo.

2.6 Instrucciones iterativas

C# ofrece un buen número de instrucciones que permiten la ejecución de


bloques de códigos repetidas veces. A continuación se comentan las principales:

A) Instrucción While  Es la instrucción iterativa más común en los lenguajes de


programación, y en C# se usa de la siguiente forma:

while (condición)
instrucciones

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 11


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

El significado de esta instrucción es el siguiente: se evalúa la condición, y en


caso de ser cierta se ejecutan las instrucciones. Tras ejecutarlas, se repite el proceso de
evaluar la condición y ejecutar las instrucciones en caso de seguir siendo cierta. Este
proceso se repite continuamente hasta que la condición deje de verificarse. Si las
instrucciones constan de más de una instrucción es necesario encerrarlas entre llaves,
del mismo modo que se comentó para el caso del if

Un ejemplo de aplicación de esta sentencia es:

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!”);
}
}

En este caso, si se indica más de un argumento en la llamada a nuestro programa


se mostrará por pantalla un mensaje de saludo para cada uno de ellos.

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.

Es importante señalar que C# no proporciona ningún valor inicial a las variables


locales de los métodos, por lo que es tarea del programador proporcionárselos antes de
ser leídos. En cualquier caso, si el compilador detecta que en el código hay alguna
posibilidad de que se lea algún parámetro no inicializado informará al programador de
ello dando error. La idea detrás de todo esto es conseguir evitar errores comunes y
difíciles de detectar que se dan en otros lenguajes cuando se olvida inicializar un
parámetro y su valor por defecto no es el esperado.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 12


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

B) Instrucción Do...while  Es una variante del while que se usa así:

do
instrucciones
while (condición);

En este caso, el significado de la instrucción es ahora el siguiente: se ejecutan las


instrucciones (que en caso de ser varias habrán de ir encerradas entre llaves), y tras ello
se evalúa la condición. Si el resultado de evaluarla es cierto se vuelve a repetir el
proceso, mientras que si no lo es se continúa ejecutando a partir de la instrucción
siguiente al do ... while Es importante resaltar que en esta instrucción es obligatorio
incluir el punto y coma (;) al final del paréntesis de cierre de la condición, ya es un error
frecuente entre novatos olvidar incluirlos.

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é”);
}
}

Al ejecutarse la aplicación puede observarse que lo que se hace es preguntar al


usuario una clave, de modo que mientras no se introduzca la clave correcta (que es
José), no se continuará con la ejecución de la aplicación; y una vez que se introduzca
correctamente se dará un mensaje de bienvenida al usuario.

Aparte de la instrucción do ... while, en este ejemplo se ha introducido un nuevo


elemento en el ejemplo: una llamada al método ReadLine() de la clase Console Este
método detiene la ejecución de la aplicación y la deja en espera de que el usuario
introduzca una cadena de caracteres y pulse la tecla ENTER, cadena que es devuelta por
el método ReadLine() y que en la aplicación se guarda en la variable de tipo cadena
llamada leído para comprobar posteriormente, en la condición del do ... while, si
coincide con la clave esperada (José)

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 13


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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:

for (inicialización; condición; incremento)


instrucciones

El significado de esta instrucción es el siguiente2: se realizan las inicializaciones


de variables indicadas en inicialización y luego se evalúa la condición; si es cierta, se
ejecutan las instrucciones indicadas (entre llaves si son varias) Tras ello se ejecutan las
operaciones de incremento (o decremento) indicadas y se reevalúa la condición.
Mientras ésta sea cierta se irá repitiendo el proceso de ejecución de instrucciones,
incremento de variables y reevaluación de la condición hasta que deje de serlo. En caso
de que se desee inicializar o declarar varias variables en el campo de inicialización o de
que se realizar varias operaciones incremento/decremento en el campo decremento
habría que separarlas mediante comas (,)

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!”);
}
}

El funcionamiento de este ejemplo es exactamente el mismo que el del


HolaMundo5, sólo que en este caso se ha aprovechado la eficacia de la instrucción for
para hacer reducir mucho más el tamaño del código. Si acaso, cabría señalar la
utilización del operador ++ en el campo de incremento, cuyo significado es sumar 1 a la
variable sobre la que se aplica. Simétricamente, también está definido el operador --,
cuyo significado es restar 1 a la variable sobre la que es aplicado.

C) Instrucción Foreach  Esta instrucción es la novedad más importante introducida


en el juego de instrucciones de C# respecto a Java y C++, sus más directos
competidores. Se utiliza así:

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.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 14


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

foreach (tipoElemento elemento in colección)


instrucciones

Esta instrucción se utiliza para recorrer colecciones de elementos (por ejemplo,


tablas), y su significado es muy sencillo: se ejecutan las intrucciones indicadas (estarán
encerradas entre paréntesis en caso de ser varias) para cada uno de los elementos de la
colección que se especifica.

El siguiente ejemplo muestra cómo se utiliza esta instrucción:

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!”);
}
}

El significado de este ejemplo es el mismo que el del HolaMundo5, aunque


como se ve, el uso de foreach simplifica mucho la escritura del mismo, aún más que el
uso del for que se vio en el ejemplo previo.

Es importante resaltar dos cosas sobre el foreach:

a) El elemento indicado va variando en cada ejecución de las instrucciones, de


modo que en cada ejecución se corresponde con uno de los elementos de la
colección indicada. Sin embargo, hay que tener en cuenta que este elemento
(arg en el ejemplo) es de sólo lectura, por lo que no puede usarse para
modificar los valores de la colección escribiendo en él.

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:

void Reset()  Reinicia el enumerador devolviéndolo a su estado inicial.


bool MoveNext()  Avanza el enumerador pasándose a considerar el
elemento siguiente al actual como el nuevo elemento actual. El valor
devuelto indica si se ha alcanzado el final de la colección.
Current  Propiedad de sólo lectura que devuelve el elemento actual de
la colección.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 15


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 16


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

3.- Desarrollo de aplicaciones de ventanas


3.1 Introducción a Visual Studio .NET

Aunque en principio sería posible desarrollar una aplicación de ventanas de


forma parecida a como hemos estado trabajando hasta ahora; es decir, con un simple
editor de texto y utilizando las clases de los espacios de nombres adecuados
(principalmente System.WinForms), esto no es lo que en la práctica se suele hacer, ya
que ello implicaría invertir mucho tiempo en la escritura del código encargado de
generar la interfaz de nuestra aplicación, tiempo que podríamos estar aprovechando para
centrarnos en resolver los problemas relativos a su lógica y no a su aspecto. Por esta
razón, vamos a utilizar la herramienta Visual Studio .NET de Microsoft.

Visual Studio.Net permite diseñar la interfaz de la aplicación de manera visual,


sin más que arrastrar con el ratón los elementos que necesitemos (botones, lista de
selección, etc.) sobre las posiciones adecuadas en la ventana de nuestra aplicación.
También incluye otras facilidades para el desarrollo, como una ventana de propiedades
desde la que se puede modificar los valores de las propiedades de cada objeto sin tener
que escribir código, un depurador de código gráfico, un editor de códigos inteligente
que puede detectar nuestros errores de sintaxis instantáneamente, etc.

Al arrancar Visual Studio.Net (por defecto en Inicio -> Programas ->


Microsoft Visual Studio .NET 7.0 -> Microsoft Visual Studio .NET) obtendremos
una pantalla como la siguiente:

[Imagen 1. Pantalla inicial de Visual Studio.NET]

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 17


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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:

[Imagen 2. Ventana de selección de tipo de proyecto]

Como se ve, nosotros hemos seleccionado en la ventana Project Types que


vamos a realizar un proyecto escrito en C# (opción Visual C# Projects), en la ventana
Templates que vamos a desarrollar una aplicación de venantas (opción Windows
Application), en el cuadro de texto Name que vamos a darle el nombre EditorEjemplo a
nuestro proyecto, y en el cuadro de texto Location que el directorio base donde
instalaremos el proyecto será c:\C# Nótese que debajo Location aparece un mensaje
que nos informa cual será el directorio donde finalmente se almacenarán los archivos de
nuestro proyecto, y como se ve, este directorio es el resultado de concatenar el nombre
de nuestro proyecto con la ruta del directorio base que hayamos especificado.

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:

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 18


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

[Imagen 3: Ventana principal de diseño de Visual Studio.NET]

Si alguna de las ventanas indicadas no nos apareciese al iniciar el proyecto,


siempre podemos obtenerlas nosotros mismo pulsando sobre los botones situados en la
zona superior derecha de la ventana principal de Visual Studio, junto al botón >>

Como se puede ver en el dibujo, se distingue tres partes muy importantes en


nuestra área de trabajo:

A) La ventana de diseño (central), donde iremos colocando los elementos que


formarán parte de la interfaz de nuestra aplicación y desde la que podemos
modificar el código de estos con sólo hacer doble click con el ratón sobre ellos.
Hay que tener en cuenta que los puntos que aparecen dentro de esta ventana no
aparecerán en la versión final de la misma, sino que sólo se incluyen durante el
diseño para facilitar la colocación de controles sobre ella. De todos modos, si
nos molestan podemos desactivarlos mediante Options -> .NET Framework
Designer -> ShowGrid

B) La ventana de herramientas (toolbox) donde se recogen los objetos más


comunes que se utilizan a la hora de crear aplicaciones de ventanas. Estos
objetos, a los que llamaremos controles, se pueden ir colocando sobre la
ventana de diseño sin más que ir seleccionándolo en la barra de herramientas y
arrastrándolos sobre la posición deseada de la ventana de diseño.

C) La ventana de propiedades (properties), desde donde aparecerán las


propiedades del objeto que en cada momento haya seleccionado haciendo click
sobre él con el ratón. A través de esta ventana podemos obtener una ayuda

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 19


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

rápida sobre sus propiedades y modificarlas con simples pulsaciones de ratón.


Por defecto las propiedades aparecen ordenadas en ella por categorías,
apareciendo juntas las relacionadas entre sí; sin embargo, podemos ordenarlas
alfabéticamente pulsando el segundo botón situado en la zona superior de esta
ventana (empezado a contar por la izquierda)

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)

3.2 Diseño de la interfaz

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:

+ Un RichTextBox, que será el área sobre el que mostrará el texto el editor.


+ Un MainMenu, que contendrá el menú principal de nuestra aplicación
+ Un OpenFileDialog, un SaveFileDialog, un FontDialog y un PrintDialog,
que se corresponden respectivamente con las ventanas estándar utilizadas en
Windows para la apertura y cierre de ficheros, selección de fuente e impresión.
+ Un PrintDocument, que será el objeto que utilicemos para imprimir el texto
de nuestro editor y que tomará como información los datos que recoja el
PrintDialog previamente introducido.

[Imagen 4: Ventana de diseño con los controles necesarios para el editor]

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 20


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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:

1.) Al RichTextBox le cambiaremos el texto por defecto dejándoselo en blanco,


para lo que seleccionaremos su propiedad Text y borraremos su valor. A
continuación, le vamos a modificar el nombre con el que lo identificaremos
desde nuestro código por uno más español, para lo que cambiaremos el
contenido de su propiedad3 (Name) por rtbTexto.

Tras esto, le cambiamos el valor de su propiedad Anchor de manera que


todos los rectángulos que aparecen en la ventana asociada a la misma, que
aparecerá al pulsar sobre la fecha junto a ella incluida, queden marcados. Esta
propiedad indica respecto a qué lados de su ventana contenedora se “anclará” el
control, y seleccionar todos los rectángulos como se ha indicado indica que
deseamos que sean todos, con lo que siempre que se redimensione la ventana
nuestro control se ajustará automáticamente al nuevo tamaño que se le dé.

Finalmente, vamos a cambiar el valor de la propiedad Font, que indica el


tipo de fuente que se usará el control para mostrar su texto, por otra fuente que
puede ser más bonita: la Arial de tamaño 10. Para ello, podemos teclear
manualmente Arial 10 pt como valor de esa propiedad o, lo que es más cómodo,
pulsar el botón con puntos suspensivos que aparece a su lado para seleccionar
gráficamente de la forma en que acostumbra a hacer en Windows.

2.) Al OpenFileDialog le cambiaremos el título que se mostrará en la ventana


de selección de archivo a abrir por un más intuitivo Seleccione el archivo a
abrir, para lo que cambiaremos el valor de su propiedad Title por dicho texto.
Al igual que en el caso del RichTextBox, también es conveniente que le
cambiemos su identificador por uno en castellano: dlAbrirArchivo
3
Nótese que (Name) aparece entre paréntesis ya que en realidad no es una propiedad del objeto, sino el
nombre del objeto. Sin embargo, por comodidad se ha optado por incluirlo en la ventana de propiedades.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 21


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

Por último, vamos modificar el valor de su propiedad Filter Esta propiedad


indica cuáles son los archivos que la ventana nos dejará seleccionar. El valor de
esta propiedad ha de ser una cadena de texto de la forma descripciónArchivo1|
filtroArchivo1|descripciónArchivo2|filtro2... Nosotros le daremos el valor
Archivos de texto|*.txt|Todos los archivos |*.* De este modo, nuestra ventana en
primer lugar sólo nos dejará seleccionar archivos de extensión .txt, pues el tipo
de archivo indicado en primer lugar; y en caso de que el usuario quiera
seleccionar otro siempre podrá hacerlo modificando la lista desplegable incluida
en la ventana de selección de archivo gracias a que como segundo tipo de
archivo admitido permitimos cualquier archivo (*.*)

3.) Al SaveFileDialog le hacemos cambios muy similares caso anterior. Ahora


cambiamos el Title por Seleccione el archivo donde guardar, el (Name) por
dlGuardarArchivo y el Filter por Archivos de texto |*.txt|Todos los archivos|
*.*

4.) Al FontDialog le cambiaremos el nombre por dlFuente, le daremos el


valor true a su propiedad ShowColor para que nos permita seleccionar también
nuevos colores para la fuente de nuestro texto y le cambiaremos el valor de la
fuente mostrada por defecto por Arial 10 pt, para que se corresponda con el valor
de nuestro texto por defecto.

5.) Al PrintDocument le cambiaremos su nombre por pdImpresor y al


PrintDialog se lo cambiaremos por dlImprimir Además, en éste último
modificaremos su propiedad Document por pdImpresor, para así indicarle que
el objeto PrintDocument cuyas propiedades ha de modificar a partir de la
información que recoja del usuario es pdImpresor

6.) Por último, a la ventana principal del editor le cambiaremos el texto de su


barra de título modificando su propiedad Texto por EditorEjemplo

3.3 Diseño de los menús

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:

Archivo Fuente Créditos


Nuevo
Abrir...
Reabrir
Guardar
Guardar como...
--------------------
Imprimir
--------------------

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 22


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

Salir
La siguiente imagen muestra gráficamente el proceso de relleno de recuadros
Type Here antes comentado:

[Imagen 5: Diseño visual de menús en Visual Studio.NET]

A cada submenú le daremos un nombre igual al texto que mostrará aunque


precedido de la cadena menu (por ejemplo, menuArchivo, menuGuardarComo...) La
única excepción a este caso serán las barras separadoras, que se incluyen escribiendo –
en el Type Here correspondiente al lugar donde se desee que aparezcan y que no
usaremos para nada aparte de para organizar un poco mejor el contenido de nuestros
menús, por lo que no tiene mucho sentido que le demos un nombre fácil de recordar.

Cabe destacar algunos aspectos:

+ A cada menú le podemos asociar una combinación de teclas para acceder


rápidamente al mismo. Para ello, hemos de seleccionar dicha combinación como valor
de la casilla correspondiente a la propiedad ShortCut en su ventana de propiedades.

+ 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 (&&)

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 23


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

+ Podemos indicar que un submenú es el que se activará por defecto cuando


hagamos doble click sobre el nombre del menú padre que lo contiene. Para ello, hemos
de dar el valor true a la propiedad DefaultItem del mismo. Este tipo de submenús se
caracterizan porque su texto aparece en negrita5.

+ 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.

3.4 Asociación de código a eventos

Windows es un sistema guiado por eventos, y cualquier aplicación gráfica


escrita para Windows consiste básicamente en escribir código de respuesta a eventos.
Por ejemplo, cuando el usuario pulsa un botón se lanza un evento con el que se indica
que dicho botón ha sido pulsado, y es el programador el que ha de determinar qué
acción se ha de realizar en respuesta a dicha pulsación.

En C# para escribir este código de respuesta, en la clase de cada control se


define una serie de miembros denominados eventos a los que les podemos asociar una o
más funciones a ejecutar en caso de que se produzca el evento apropiado. Por ejemplo,
la clase de los submenús (MenuItem) tiene un evento Click que se declararía así en la
definición de la clase:

class MenuItem: Menu


{
// ... (Otras definiciones)
public event EventHandler Click;
// ... (Otras definiciones)
}

Nótese que tras el nombre de la clase MenuItem se ha colocado el nombre de


otra clase (Menu) separado por dos puntos. Esto significa que la clase MenuItem que
estamos declarando deriva de la clase Menu. Es decir, básicamente esto significa que
incluye todas las definiciones de métodos, propiedades y demás miembros de la clase
Menu más los que definamos en ella; y que si definimos miembros de igual signatura
que miembros definidos en Menu las nuevas definiciones de estos sustituirán a las
heredadas de Menu. Nótese que también la clase principal de nuestra aplicación deriva
de clase Form, que incluye definiciones para el comportamiento básico de una ventana.

La definición de evento del ejemplo anterior significa que Click es un evento al


que le podemos asociar como código respuesta funciones cuya signatura (definición de
valor de retorno, nombre y parámetros de la función) sea compatible con la indicada por
el delegado EventHandler Un delegado podemos verlos como una declaración de valor
de retorno y parámetros de función a la que se le asocia un nombre. Por ejemplo, en el
caso concreto de EventHandler, éste delegado está definido de la siguiente forma:
5
Si se pone a true dos o más submenús de un mismo menú padre sólo se activará con el doble click el
primero. Sin embargo, ambos aparecerán en negrita.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 24


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

public delegate void EventHandler(object emisor, EventArgs e)

Por consiguiente, al evento Click le podremos asociar cualquier número de


funciones que tomen un primer parámetro de entrada de tipo object, un segundo de tipo
EventArgs y que no devuelva ningún valor de retorno (void) En concreto, el primer
parámetro representa al objeto que a provocado el evento (en nuestro caso el submenú
pulsado); mientras que el segundo está destinado a contener información variada sobre
el evento que se ha producido que a nosotros no nos va a hacer falta.

Nosotros podemos escribir el código de estas funciones de respuesta sin


preocuparnos de cómo se generan estos objetos que son pasados a nuestra función, ya
que de ello se encarga el sistema en tiempo de ejecución de .NET6 y podemos estar
totalmente seguros de que siempre estarán construidos correctamente.

El siguiente ejemplo muestra cómo podríamos asociar código de respuesta a la


pulsación de un botón de nombre miMenu:

// ...
miMenu.Click += new EventHandler(miCódigoRespuesta);
// ...

Este código de respuesta estaría escrito en una función como la siguiente:

public void miCódigoRespuesta(object o, EventArgs e)


{
MessageBox.Show(“Pulsado miMenu”);
}

La función Show() de la clase MessageBox es muy utilizada en aplicaciones de


ventanas, y lo que hace es mostrar por pantalla una pequeña ventana informativa con el
texto indicado y un botón con el texto Aceptar que permite cerrarla. Por consiguiente, lo
que hemos hecho con nuestro código es que cada vez que se pulse el menú identificado
por miMenu se mostrará una ventana informando que se ha pulsado dicho botón.

Nótese que para asociar un código de respuesta a un evento se utiliza el operador


+=. Este operador puede usarse tantas veces como se desee sobre un mismo evento, con
lo se asociarían diversos códigos de respuesta al mismo, que se ejecutarían uno detrás
tras otro en caso de producirse el evento.

También podemos eliminar de un evento códigos de respuesta ya asociados.


Para ello se usa el operador -=, y un ejemplo de cómo quitar el código asociado al
evento en el ejemplo anterior es:

miMenu.Click -= new EventHandler(miCódigoRespuesta);

A partir de esta instrucción, cada vez que se pulsase miMenu no se realizará


ninguna acción (a no ser que hayan asociado otros códigos de respuesta al evento Click)

6
También conocido como Common Language Runtime ó CLR

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 25


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

3.5 Asociación de código a eventos en Visual Studio.NET

Aunque la forma anteriormente comentada para asociar códigos de respuesta a


los eventos es la que realmente se usa, Visual Studio nos permite asociar los códigos de
respuesta más comunes a los eventos de una forma mucho más sencilla. Con tan sólo
hacer doble click sobre el control ya estaremos en condiciones de empezar a escribir el
código de respuesta a su evento más común (por ejemplo, en el caso de un menú o
botón sería el código de respuesta a su evento Click), pues ya se encarga Visual Studio
de declarar automáticamente la función de respuesta al evento y asociarla (con +=) al
evento apropiado.

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:

Cuando se pulse el botón nuevo se ha de eliminar cualquier texto que hubiese en


la caja de texto (rtbTexto) del editor. Esto es tan sencillo como hacer que el valor de su
propiedad Text pase a ser una cadena vacía (“”), y para conseguirlo simplemente
hacemos doble click sobre la opción del menú apropiada y rellenamos el código de
respuesta al evento con el siguiente contenido:

protected void menuNuevo_Click (object sender,


System.EventArgs e)
{
rtbTexto.Text="";
this.Text ="EditorEjemplo";
menuReabrir.Enabled = false;
}

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.

Es señalable el uso de la palabra reservada this para hacer referencia al objeto al


que pertenece el método que estamos escribiendo. Recordemos que los códigos de
respuesta los estamos escribiendo dentro de la de la clase que representa la ventana de la
aplicación (que deriva de Form), por lo que this hace referencia a la ventana nuestro
editor y Text es la propiedad de la ventana que almacena su título.

También puede destacarse el hecho de que Visual Studio añade el modificador


de visibilidad protected a la declaración de cualquier código de respuesta. Este
modificador indica que dicho código sólo puede ser llamado desde la clase dentro de la
que el método se ha definido o desde subclases de la misma.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 26


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

2. menuAbrir

En este caso hay que mostrar al usuario el fdAbrirArchivo para recoger


información sobre el nombre del archivo a abrir para, tras ello, abrirlo y guardar como
contenido de la caja de texto del editor la información en este almacenada. Esto lo
hacemos con un el siguiente código de respuesta (recordemos que para escribirlo basta
hacer doble click con el ratón sobre el submenú de título Abrir... y Visual Studio se
encargará de generar automáticamente el esqueleto del mismo):

protected void menuAbrir_Click (object sender, System.EventArgs


e)
{
if (dlAbrirArchivo.ShowDialog() == DialogResult.OK)
{
rtbTexto.LoadFile(dlAbrirArchivo.FileName,
RichTextBoxStreamType.PlainText);
this.Text = "["+dlAbrirArchivo.FileName + "]
EditorEjemplo";
menuReabrir.Enabled = true;
}
}

En este código lo que se hace es llamar al método ShowDialog() de nuestro


dlAbrirArchivo para que se muestre la típica ventana con la que en Windows pide al
usuario de las aplicaciones que seleccione un fichero a abrir. Este método puede
devolvernos los valores OK ó Cancel del tipo enumerado DialogResult según si el
usuario ha pulsado el botón Ok ó el botón Cancelar de dicha ventana.

Un tipo enumerado o enumeración es un tipo para el que indicamos


explícitamente cuáles son los valores que puede tomar. Por ejemplo, un tipo enumerado
de nombre Colores que sólo pueda tomar los valores Rojo, Verde o Azul se definiría así:

enum Colores {Rojo, Verde, Azul};

Sólo en caso de que se pulse Ok será cuando cargaremos el fichero de texto


seleccionado, por lo que hemos de comprobar en la condición del if que estemos en ese
caso. Una vez que el usuario ha seleccionado un archivo almacenamos su contenido en
la caja de texto llamando al método LoadFile() de ésta. Este método toma dos
parámetros: el primero contiene el nombre del fichero a abrir, que recuperamos a través
de la propiedad FileName del dlAbrirArchivo; mientras que el segundo indica cuál es el
formato en que se encuentra almacenada la información de dicho tipo, donde nosotros
indicamos que vamos a cargar un fichero en formato de texto plano7 usando el valor
PlainText de la enumeración RichTextBoxStreamType. Téngase en cuenta que un
objeto de clase RichTextBox también es capaz de almacenar texto en formato RTF8
(valor RichText de la enumeración RichTextBoxStreamType)
7
Este formato consiste en almacenar en el fichero sólo los caracteres que componen el texto a mostrar.
8
Este formato consiste en almacenar en el fichero también información que indiquen características de
formato del texto, márgenes, etc.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 27


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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

El funcionamiento de este menú es muy similar al anterior, sólo que ahora no


hemos de preguntar al usuario cuál es el fichero a abrir sino que podemos obtenerlo a
partir del nombre del último fichero abierto. Por ello, su código de respuesta es:

protected void menuReabrir_Click (object sender,


System.EventArgs e)
{
String nombreFichero = this.Text.Substring(1,
this.Text.LastIndexOf("]") - 1);

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í:

protected void menuGuardar_Click (object sender, System.EventArgs


e)
{
String nombreFichero;

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 28


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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.

En caso de que el fichero no sea nuevo, obtendremos su nombre de forma


similar a como se hizo en el código de respuesta a la pulsación de menuReabrir y
guardaremos el contenido de la caja de texto en dicho fichero llamando al método
SaveFile() de la caja de texto. Este método funciona de forma recíproca al LoadFile()
ya visto, sólo que en este caso en vez de cargar el texto del fichero en la caja de texto lo
que se hace es cargar el contenido de la caja de texto en el fichero.

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:

protected void menuGuardarComo_Click (object sender,


System.EventArgs e)
{
if (dlGuardarArchivo.ShowDialog() == DialogResult.OK)
{
rtbTexto.SaveFile(dlGuardarArchivo.FileName,RichTextBoxStr
eamType.PlainText);
this.Text = "["+dlGuardarArchivo.FileName + "]
EditorEjemplo";
menuReabrir.Enabled = true;
}
}

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

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 29


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

retorno de este método es el valor OK de la enumeración DialogResult y, en ese caso,


guardar el texto contenido en rtbTexto en el fichero indicado llamando al método
SaveFile() de dicho objeto RichTextBox. Finalmente, se cambia el título de la barra de
la ventana del editor para actualizar la información de la misma sobre el nombre del
fichero que se está editando y se habilita el submenú Reabrir dando el valor true a su
propiedad Enabled, ya que ahora sí se tiene un nombre de fichero para reabrir.

6. menuImprimir

El código de respuesta a la pulsación de este submenú es muy sencillo. Sólo


hemos de mostrar la ventana típica que en Windows se utiliza para recoger información
sobre los detalles de la impresión y, en caso de que el usuario pulse el botón OK de la
misma, llamar al método Print() del objeto pdImpresor para imprimir la página según
la configuración recogida. Recuérdese que el objeto dlImprimir está conectado al objeto
pdImpridor a través de su propiedad Document, y ésta será la conexión que se usará
para comunicar al pdImpresor cuál es la configuración de impresión recogida.

El código de respuesta a este evento es, por tanto, tan simple como:

protected void menuImprimir_Click (object sender,


System.EventArgs e)
{
if (dlImprimir.ShowDialog() == DialogResult.OK)
pdImpresor.Print();
}

La llamada a Print() inicia la ejecución del proceso de impresión, aunque


nosotros hemos de indicar cómo se realizará la impresión definiendo el cuerpo del
código de respuesta al evento PrintPage del pdImpridor que es lanzado al llamar a
Print() Como definición de este código se usará:

protected void pdImpresor_PrintPage (object sender,


System.Drawing.Printing.PrintPageEvent
Args e)
{
String texto = rtbTexto.Text;
Font fuente = rtbTexto.Font;
SolidBrush color = new SolidBrush(rtbTexto.ForeColor);
RectangleF área = new RectangleF(e.MarginBounds.Left,
e.MarginBounds.Top,
e.MarginBounds.Width,
e.MarginBounds.Height);

e.Graphics.DrawString(texto, fuente, color, área);


}

Para ir dibujando el contenido a imprimir sobre el papel se utiliza el método


DrawString() del objeto obtenido a través de la propiedad Graphics del argumento de
tipo PrintPageEventArgs con el que se llamó a éste método. DrawString() imprime la

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 30


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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í:

protected void menuSalir_Click (object sender, System.EventArgs


e)
{
this.Close();
}

8. menuFuente

Al activarse este submenú se mostrará al usuario una ventana estándar de


Windows donde podrá seleccionar las características de la fuente que desea utilizar para
mostrar el texto en el editor. Por tanto, lo único que se ha de hacer es mostrar al usuario
esta ventana cuando pulse el submenú y, en caso de que seleccione OK en la misma,
modificar las características de la fuente utilizada por las nuevas que haya seleccionado.
Esto se hace con el siguiente código

protected void menuFuente_Click (object sender,


System.EventArgs e)
{
if (dlFuente.ShowDialog() == DialogResult.OK)
{
rtbTexto.Font = dlFuente.Font; // Cambiamos fuente
rtbTexto.ForeColor = dlFuente.Color; // Cambiamos color
}
}

Como es deduce, la ventana de selección de fuente almacena en su propiedad


Font la fuente elegida y en Color el color seleccionado para la misma.

9. menuCréditos

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 31


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

Al seleccionarse este submenú simplemente mostraremos un mensaje con


información sobre la aplicación. Para ello vamos a usar el método Show() de la clase
MessageBox que, como ya vimos anteriormente, lo que hace es mostrar una pequeña
ventana con el texto que se le indique como parámetro. De este modo nos queda:

protected void menuCréditos_Click (object sender,


System.EventArgs e)
{
MessageBox.Show("Autor: José Antonio González Seco",
"Créditos de EditorEjemplo v1.0");
}

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:

[Imagen 6: La aplicación EditorEjemplo en funcionamiento]

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 32


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

4.- Desarrollo de servicios Web


4.1 Introducción a los servicios Web

Básicamente un servicio Web es un clase que se publica en un servidor Web


con soporte para ASP.NET (actualmente el único disponible es el Internet
Information Server 5.0 de Microsoft tras ser actualizado con el .NET SDK) y a cuyos
métodos es posible llamar remotamente. Estas clases pueden escribirse en la mayoría de
los lenguajes de los lenguajes adaptados a .NET, como Visual Basic.NET, Jscript.NET
y C#, pero nosotros nos centraremos en el desarrollo de servicios Web usando el último.

Para acceder a un servicio Web se pueden utilizar varios protocolos Web


estándar, como HTTP GET ó HTTP POST, aunque el específicamente diseñado para
ello por Microsoft es el Protocolo de Acceso a Objetos Simple (Simple Access
Protocol o SOAP), que se basa en la utilización del protocolo HTTP para el transporte
de mensajes y el lenguaje XML para la escritura del cuerpo de estos mensajes, y que ha
sido enviado al W3C por Microsoft en mayo de 2000 para su estandarizació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.

4.2 Escritura de un servicio Web

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();
}
}

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 33


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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 conocer cuál es la fecha actual se utiliza la propiedad Now de la clase


DateTime9, que devuelve un objeto DateTime que contiene información sobre la
misma; y para acceder obtener las cadenas de texto que contienen la información
detallada y no detallada sobre la fecha se usan, respectivamente, los métodos
ToLongDateString() y ToShortDateString() de la misma.

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

Además de estos cambios en el código del fichero fuente, también hemos de


cambiar su extensión por .asmx y colocarlo en algún directorio virtual del Internet
Information Server para que así las aplicaciones cliente puedan acceder a él. Con todo
ello, el código anterior quedará así:

// Fichero: ServicioFecha.asmx
<% @ WebService Language=”C#” Class=”ServicioFecha” %>

using System;
using System.Web.Services;

class ServicioFecha: WebService // Derivamos de WebService


{
[WebMethod] public String Fecha (bool detalles)
{
if (detalles)
return DateTime.Now.ToLongDateString();
else
return DateTime.Now.ToShortDateString();
}
}

De este código hay que comentar varias cosas:

+ La directiva WebService ha de incluirse antes que cualquier otro código en el


fichero .asmx

+ Es posible almacenar el código ya compilado en un fichero .dll10 separado del


.asmx. Este código se almacenaría en el subdirectorio /bin del directorio virtual de
9
En realidad DateTime es una estructura y no una clase. Sin embargo, a efectos prácticos en esta
introducción a los servicios Web en C# ello es indiferente.
10
Para compilar en formato .dll se ha de especificar la opción /t:library al llamar al compilador.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 34


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

nuestra aplicación y para referenciarlo desde la etiqueta WebService del .asmx se


usaría el atributo Codebehind de ésta del siguiente modo:

<% @ WebService Language=”C#” Codebehind=”ServicioFecha”


Class=ServicioFecha” %>

+ No hay que confundir el concepto de atributo en C# con los atributos de las


etiqueta ASP.NET Un ejemplo de lo primero es el atributo [WebMethod] ya visto, y en
general estos atributos sirven para indicar información sobre la clase o miembro al que
preceden ([WebMethod] indica que el método al que precede es accesible
remotamente); mientras que ejemplos de atributos de etiquetas ASP.NET son los
atributos Language y Codebehind también ya comentados, siendo la utilidad de este
tipo de atributos indicar información sobre la etiqueta a la que acompañan.

4.3 Página de prueba de un servicio Web

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:

[Imagen 7: Página de pruebas del servicio Web ServicioFecha]

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 35


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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)

4.4 Acceso a un servicio Web mediante SOAP

Ya se ha comentado que SOAP es el protocolo basado en HTTP y XML que


Microsoft ha desarrollado para el acceso a los servicios Web. Aunque podríamos
comunicarnos directamente con un servicio Web enviando mensajes escritos en el
formato de este protocolo e interpretando sus repuestas, lo cierto es que ello sería
bastante incómodo, por lo que Microsoft proporciona un mecanismo mucho más
sencillo y transparente basado en el uso de proxies.

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.

Para generar automáticamente el proxy es necesario contar con una


especificación del servicio (métodos ofrecidos, signatura de estos, protocolos
soportados, etc.) que sea fácil de interpretar por una máquina. Para ello se utiliza un
fichero XML escrito en el llamado Lenguaje Descriptor del Servicio Web (Web
Service Descriptor Language o WSDL) Para obtener este fichero sólo hay que acceder
al servicio Web concatenado la cadena ?WSDL al final del mismo. Así, siguiendo con
nuestro ejemplo la cadena sería http://localhost/ServicioFecha.asmx?WSDL

Gracias a este tipo de ficheros, podemos generar el proxy de manera automática


utilizando la utilidad wsdl.exe incluida en el .NET SDK. Esta utilidad se usaría así para
generar un proxy para nuestro ejemplo anterior:

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:

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 36


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

using System;

class ClienteFecha
{
public static void Main()
{
ServicioFecha s = new ServicioFecha();

Console.WriteLine(“Fecha actual: {0}”,


s.Fecha(false));
Console.WriteLine(“Fecha actual detallada: {0}”,
s.Fecha(true));
}
}

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:

csc ClienteFecha.cs ServicioFecha.cs

Así obtendremos un ClienteFecha.exe El resultado de ejecutarlo es:

Fecha actual: 07/11/2000


Fecha actual detallada: Tuesday, July 11, 2000

4.5 Mantenimiento del estado

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í.

Para conseguir almacenar información sobre llamadas previas, la clase


WebService de la que todo servicio Web hereda proporciona unos objetos llamados
Application y Session, de clase HttpApplicationState y HttpSessionState
respectivamente, que actúan como depósitos de información sobre llamadas previas. El
primero de estos objetos permite almacenar información que será compartida por todas
las aplicaciones clientes del servicio, mientras que la información almacenada en el
segundo sólo es compartida entre sucesivas llamadas de un mismo cliente

A continuación se muestra una modificación del ejemplo anterior en la que se


utilizan los dos objetos antes comentados para guardar información sobre cuántos
clientes han accedido al método Fecha() del servicio. Además, se proporcionan un

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 37


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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:

<% @ WebService Language="C#"


Class="ServicioFechaEstado" %>

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();
}

[WebMethod] public int Accesos()


{
if (Application["Accesos"] == null)
return 0;
else
return ((int) Application["Accesos"]);
}

[WebMethod(EnableSession=true)] public int AccesosMíos()


{

if (Session["Accesos"] == null)
return 0;
else
return ((int) Session["Accesos"]);

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 38


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

De este código cabe destacar los siguientes aspectos:

+ Para acceder a la información almacenada en los objetos Application y


Session basta indicar entre corchetes el nombre con el que identificaremos la
información que pretendemos usar (se usa pues una sintaxis similar a la de las tablas. A
ésta se le llama indizador en C#) Estos objetos devuelven elementos de tipo object, y
para convertirlos a int usamos el operador de conversión implícita (int) Además en el
caso de que la información que se pretende obtener no haya sido aún introducida
devuelven null, lo que controlamos mediante las condiciones de los if.

+ Es necesario modificar la forma en la que usamos el atributo [WebMethod]


dándole el valor true a la propiedad EnableSession en todos aquellos métodos que
utilicen el objeto Session para así habilitar el uso de éste.

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();

Console.WriteLine("Accesos Totales : {0} ({1} míos)",


s.Accesos(), s.AccesosMíos());
Console.WriteLine("Fecha actual: {0}", s.Fecha(false));
Console.WriteLine("Fecha actual detallada: {0}", s.Fecha(true));
Console.WriteLine("Accesos Totales : {0} ({1} míos)",
s.Accesos(), s.AccesosMíos());
}
}

Nótese que para conseguir el mantenimiento de sesión ha sido necesario


inicializar la propiedad CookieContainer del servicio web con un objeto
System.Net.CookieContainer que servirá de almacén donde guardar la información
necesaria para el mantenimiento de estado. Sin embargo, de cómo se gestiona este
objeto internamente y cómo se guarda en él dicha información es algo de lo que el
programador no ha de preocuparse, pues es un proceso completamente transparente a él
y puede usar el servicio web como si de cualquier objeto se tratase. Así, si ejecutamos
este cliente por primera vez obtendremos:

Accesos totales: 0 (0 míos)


Fecha actual: 07/11/2000
Fecha actual detallada: Tuesday, July 11, 2000
Accesos totales: 2 (2 míos)

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 39


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

Y si lo volvemos a ejecutar de nuevo obtendremos:

Accesos totales: 2 (0 míos)


Fecha actual: 07/11/2000
Fecha actual detallada: Tuesday, July 11, 2000
Accesos totales: 4 (2 míos)

Véase en los resultados de la ejecución del cliente cómo la información


almacenada en el objeto Session no es compartida entre sucesivas llamadas al cliente
mientras que la almacenada en el objeto Application sí11

4.6 Servicios Web con Visual Studio.NET

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.

Para escribir un servicio Web hemos de arrancar Visual Studio.NET y crear un


proyecto de aplicación de consola con:

- Project Types = Visual C# Projects


- Templates = Web Service
- Name = ServicioFechaVS
- Location = http://josan/

El valor dado a Location es el nombre del servidor donde se instalará el servicio


Web. Dejaremos este campo con su valor por defecto, que coincide con el nombre la
máquina donde se esté ejecutando Visual Studio (http://josan). Si nos interesa instalarlo
en otra máquina sólo tendríamos que cambiar este valor por el nombre de ésta

Con los datos anteriores se creará en el servidor Web de la máquina indicada un


directorio virtual con el nombre hayamos dado al proyecto en el que se depositaran los
archivos del proyecto. Entre estos archivos, hay que resaltar que Visual Studio sigue la
aproximación, ya comentada, de separar el código del servicio de su fichero .asmx

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.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 40


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

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:

- Project Types = Visual C# Projects


- Templates = Console Application
- Name = ClienteFechaVS
- Location = c:\C#

Una vez hecho esto, pulsando el botón OK se creará nuestro proyecto y


podremos empezar a escribir su código en un fichero Class1.cs Para cambiar el nombre
de éste podemos abrir el Explorador de Solución (View -> Solution Explorer) y hacer
click con el botón derecho del ratón sobre el mismo para renombrarlo; y para cambiar el
de la clase creada por defecto (Class1) hacemos lo mismo en la Vista de Clase (View ->
Class View). Nosotros optaremos por cambiar ambos nombres por ClienteFechaVS

El código ClienteFechaVS será el mismo que el del ClienteFecha ya escrito, por


lo que podemos cortarlo de éste y pegarlo sobre el Main() de ClienteFechaVS.

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.

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 41


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 42


Taller de C#: El nuevo lenguaje de Internet José Antonio González Seco

5.- Documentación de referencia

1. Guía de referencia del lenguaje C#: (http://www.msdn.microsoft.com/net/ecma)

Documento con la especificación del lenguaje C# enviado por Microsoft al


ECMA para su estandarización.

2. Compilador de C# (incluido en el .NET SDK):


(http://www.msdn.microsoft.com/code/sample.asp?url=/msdn-files/027/000/976/msdncompositedoc.xml)

3. Versión beta de Visual Studio .NET: (http://msdn.microsoft.com/vstudio/nextgen/beta.asp)

Es necesario disponer de subscripción MSDN Universal para descargarlo o


pedirlo por correo a Microsoft (sólo se pagan gastos de envío)

4. Portal de C# en español: (http://tdg.lsi.us.es/~csharp)

El “Rincón en español de C#” es el primer portal en Internet dedicado a C#


escrito en castellano. Ha sido desarrollado por profesores de la Facultad de Informática
y Estadística de Sevilla y contiene abundante información sobre el lenguaje, incluyendo
un seminario “on-line” sobre C#, un FAQ sobre el lenguaje, aplicaciones de ejemplo y
una lista de distribución de correo con muchos subscriptores.

5. Portal sobre .NET de Microsoft: (http://www.msdn.microsoft.net)

Sitio Web de Microsoft dedicado al desarrollo sobre su nueva plataforma .NET,


e incluye mucha información, novedades, software y artículos técnicos sobre la misma.
La mayoría de la información está escrita con ejemplos en C#.

6. Especificación del protocolo SOAP v1.1:


(http://www.msdn.microsoft.com/xml/general/soapspec.asp)

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)

7. Artículos destacados sobre servicios Web:

“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

“Web Services in ASP.NET” (http://www.msdn.microsoft.com/voices/asp02222001.asp) de


Rob Howard

8. Bibliografía (puede conseguirla a través de http://www.amazon.com)

“Inside C#” de Tom Archer. Editorial Microsoft


“A programmer’s introduction to C#” de Eric Gunnerson. Editorial Apress
“C# Essentials” de Beb Albahari, Peter Drayton y Brand Merril. Editorial O’Reilly

Jornadas de Informática Imaginática 2001(http://imaginatica.us.es) Página 43

Вам также может понравиться