Desarrollo de Componentes
Desarrollo de Componentes
Desarrollo de Componentes
Índice
Descripción 1
Descripción de los componentes 2
Creación de componentes con servicio 11
Demostración: creación de un componente con servicio 29
Creación de clases de componentes 31
Demostración: Creación de un componente Stopwatch 37
Creación de controles de formularios Windows Forms 39
Demostración: Creación de una caja de texto mejorada 46
Manejo de hilos de ejecución 48
Demostración: Uso de la instrucción SyncLock 61
Desarrollo de componentes en Visual Basic .NET 1
Descripción
Objetivo
Presentar los temas y
objetivos del módulo.
Presentación Components Overview
En este módulo, Creating Serviced Components
aprenderemos cómo crear
componentes en Creating Component Classes
Visual Basic .NET.
Creating Windows Forms Controls
Creating Web Forms User Controls
Threading
Tipos de componentes
Objetivo
Explicar los diferentes tipos
de componentes que
podemos crear en Estructuras
Visual Basic .NET.
Módulos
Presentación
Podemos crear varios tipos Clases
de componentes en una
aplicación basada en Visual Clases de componente
Basic .NET.
Componentes con servicio
Controles de usuario
z Controles de usuario de formularios Windows Forms
z Controles de usuario de formularios Web Forms
Módulos
Podemos utilizar los módulos como componentes declarándolos públicos
cuando los definamos. Declarar módulos públicos permite crear librerías de
código que contienen rutinas útiles para múltiples aplicaciones. También
podemos utilizar módulos para crear funciones reutilizables que no son de
aplicación a un componente, clase o estructura concretos.
Si hemos utilizado las clases GlobalMultiUse o GlobalSingleUse en versiones
anteriores de Visual Basic, el concepto de librería de código no nos resultará
nuevo. Estas clases proporcionan la misma funcionalidad en Visual Basic
.NET; el código cliente no necesita cualificar estas clases por el nombre de
clase para invocar las funciones.
4 Desarrollo de componentes en Visual Basic .NET
Clases
Podemos utilizar clases como componentes declarándolas públicas en un
ensamblado. Podemos utilizar clases públicas desde cualquier aplicación cliente
basada en .NET agregando una referencia al ensamblado del componente.
Podemos extender la funcionalidad de las clases mediante mecanismos como
propiedades, métodos y eventos. Las clases también son extensibles mediante la
herencia, lo cual permite a las aplicaciones reutilizar la lógica existente en estos
componentes.
Clases de componentes
Una clase se convierte en componente cuando se ajusta a un estándar para la
interacción con componentes. Este estándar se proporciona a través de la
interfaz IComponent. Cualquier clase que implemente la interfaz IComponent
es un componente. Las clases de componentes permiten abrir la clase en un
diseñador visual y permiten a la clase ser ubicada en otros diseñadores visuales.
Controles de usuario
Los controles de usuario son componentes creados por un desarrollador para
ubicarlos en formularios Windows Forms o Web Forms. Cada control de
usuario tiene su propio conjunto de propiedades, métodos y eventos que lo
hacen adecuado para un determinado uso. Podemos manipular controles de
usuario en los diseñadores de formularios Windows Forms y Web Forms y
escribir código para agregar controles de usuario dinámicamente en el entorno
de ejecución, al igual que con los controles proporcionados como parte del
.NET Framework.
'Client
'Client code
code
Imports
Imports MyAssembly
MyAssembly
...
...
Dim
Dim xx As
As Long
Long == Square(20)
Square(20)
En Visual Basic .NET podemos utilizar módulos como componentes fuera del
ensamblado en el que están definidos. Para que esto sea posible, debemos
declarar el módulo como público cuando lo definamos. A continuación,
necesitaremos crear una referencia en el ensamblado cliente al ensamblado
componente y utilizar la instrucción Imports para permitir el acceso a los
métodos del módulo.
El siguiente ejemplo muestra cómo crear un módulo público denominado
MyMathFunctions que define la función Square. Este módulo está definido en
el ensamblado MyAssembly. A continuación, el módulo puede utilizarse como
un componente en el código cliente, como muestra la segunda parte del
ejemplo.
Public Module MyMathFunctions
Public Function Square(ByVal lng As Long) As Long
Return (lng * lng)
End Function
...
End Module
'Client code
Imports MyAssembly
...
Dim x As Long = Square(20)
6 Desarrollo de componentes en Visual Basic .NET
'Client
'Client code
code
Imports
Imports MyAssembly
MyAssembly
Dim
Dim xx As
As New
New Account(
Account( ))
x.Debit(1021,
x.Debit(1021, 1000)
1000)
'Client code
Imports MyAssembly
Dim x As New Account( )
x.Debit(1021, 1000)
Desarrollo de componentes en Visual Basic .NET 7
Podemos crear componentes con Visual Basic .NET que pueden ser utilizados
por aplicaciones cliente no gestionadas. Esta interoperabilidad permite utilizar
características de los servicios de componentes como la agrupación de objetos o
las transacciones. Para exponer nuestros componentes a COM y a los servicios
de componentes, debemos establecer propiedades específicas del ensamblado y
crear nuestras clases adecuadamente.
De este modo, nuestro ensamblado tendrá un nombre seguro la próxima vez que
lo generemos.
8 Desarrollo de componentes en Visual Basic .NET
Límite de Remoting
Uso de transacciones
Objetivo
Examinar cómo los
componentes pueden El atributo Transaction especifica cómo participa una clase
utilizar transacciones de los en las transacciones
servicios de componentes.
La clase ContextUtil proporciona transaction voting
Presentación
Existen varios objetos y El atributo AutoComplete impide el uso de los
atributos que permiten a los métodosSetAbort, SetComplete y ContextUtil
componentes de <Transaction(TransactionOption.Required)>
<Transaction(TransactionOption.Required)> Public
Public Class
Class Account
Account
Visual Basic .NET utilizar Inherits
Inherits ServicedComponent
ServicedComponent
transacciones de los Public
Public Sub
Sub Debit(...)
Debit(...)
servicios de componentes. 'Perform
'Perform debit
debit action
action
ContextUtil.SetComplete(
ContextUtil.SetComplete( ))
End
End Sub
Sub
<AutoComplete(
<AutoComplete( )>)> Public
Public Sub
Sub Credit(...)
Credit(...)
'Perform
'Perform credit
credit action
action
'No
'No SetComplete
SetComplete because
because AutoComplete
AutoComplete is
is on
on
End
End Sub
Sub
End Class
End Class
Procesamiento de transacciones
Para evitar el uso de los métodos SetAbort y SetComplete de ContextUtil,
podemos establecer el atributo AutoComplete de los métodos específicos del
componente. Si no ocurren excepciones durante la ejecución del método, el
objeto se comporta como si se hubiera invocado SetComplete. Si ocurren
excepciones, el objeto se comporta como si se hubiera invocado SetAbort.
Uso de seguridad
Objetivo
Explicar cómo la seguridad
de los servicios de
componentes es accesible Security configuration attributes enable security and
por los componentes de role configuration
Visual Basic .NET.
SecurityCallContext class provides role checking and
Presentación caller information
Los servicios de
componentes proporcionan <ComponentAccessControl(True),
<ComponentAccessControl(True), SecurityRole("Manager")>
SecurityRole("Manager")> __
Public
Public Class
Class Account
Account
información de seguridad Inherits
que pueden utilizar los Inherits ServicedComponent
ServicedComponent
Public
Public Function
Function GetDetails(
GetDetails( )) As
As String
String
componentes de With
With SecurityCallContext.CurrentCall
SecurityCallContext.CurrentCall
Visual Basic .NET. If
If .IsCallerInRole("Manager")
.IsCallerInRole("Manager") Then
Then
Return
Return .OriginalCaller.AccountName
.OriginalCaller.AccountName
End
End If
If
End
End With
With
End
End Function
Function
End
End Class
Class
Activación Just-in-Time
Cuando se habilita la activación Just-in-time (JIT), un objeto es instanciado
automáticamente cuando se invoca un método en un componente con servicio
(activación), y desactivado automáticamente cuando el método finaliza
(desactivación). Cuando esta opción está habilitada, un objeto no mantiene el
estado entre llamadas a métodos, y esto incrementa el rendimiento y la
escalabilidad de la aplicación.
Podemos sobrecargar los métodos Activate y Deactivate heredados de la clase
ServicedComponent para realizar funcionalidad personalizada durante JIT. Si
la agrupación de objetos está habilitada, la activación ocurre cuando un objeto
existente se extrae de la agrupación, y la desactivación ocurre cuando el objeto
se inserta de nuevo en la agrupación.
JIT se habilita automáticamente si un componente es transaccional, y no puede
deshabilitarse. Podemos habilitar o deshabilitar JIT manualmente para
componentes no transaccionales utilizando el atributo JustInTimeActivation.
Componentes encolados
Los componentes encolados proporcionan comunicación asíncrona. Esto
permite a las aplicaciones cliente enviar peticiones a componentes encolados
sin esperar una respuesta. Las peticiones se “graban” y se envían al servidor,
donde permanecen encoladas hasta que la aplicación está lista para usar las
peticiones. A continuación, estas peticiones se “reproducen” y retornan a la
aplicación como si se hubieran enviado desde un cliente normal.
Podemos marcar una aplicación para que utilice colas utilizando el atributo
ApplicationQueuing a nivel de ensamblado. Marcamos los componentes
individuales con el atributo InterfaceQueuing.
26 Desarrollo de componentes en Visual Basic .NET
Propiedades compartidas
Podemos utilizar los componentes Shared Property Manager (SPM) para
compartir información entre múltiples objetos en el mismo proceso de
aplicación. Los componentes SPM se utilizan del mismo modo que los
componentes creados en Visual Basic 6.0.
Sincronización
Las aplicaciones distribuidas pueden recibir llamadas simultáneas de múltiples
clientes. Gestionar estas peticiones simultáneas implica una lógica de programa
compleja para garantizar que se accede a los recursos de forma segura y
correcta. Los servicios de componentes proporcionan este servicio
automáticamente para componentes que utilizan transacciones. También
podemos utilizar el atributo Synchronization para especificar este
comportamiento.
Desarrollo de componentes en Visual Basic .NET 27
<Assembly: ApplicationName("BankComponent")>
<Assembly: Description("VB .NET Bank Component")>
<Assembly: ApplicationActivation(ActivationOption.Server)>
<Assembly: AssemblyKeyFile("KeyFile.snk")>
Registro automático
Si no registramos nuestra aplicación manualmente, el registro se producirá
de modo automático cuando una aplicación cliente intente crear una
instancia de una clase gestionada que herede de la clase
ServicedComponent. Todas las clases ServicedComponent de nuestro
ensamblado se registrarán como parte de la aplicación de los Servicios de
componentes. Este proceso se denomina Lazy Registration.
Desarrollo de componentes en Visual Basic .NET 29
Ë Probar el componente
1. Ejecutar el proyecto.
2. Hacer clic en Pooling y explicar los mensajes que aparecen.
3. Hacer clic en No Pooling y explicar los mensajes que aparecen.
4. Cerrar la aplicación.
5. Ejecutar de nuevo el proyecto y mostrar que esta vez no hay nuevos objetos
creados.
6. Cerrar la aplicación y cerrar Visual Studio .NET.
Interfaz IComponent
La interfaz IComponent permite crear componentes personalizados o
configurar componentes existentes como MessageQueue o Timer en el
diseñador visual de nuestro componente. Después de incluir componentes
existentes al nuestro (ubicar), podemos acceder a ellos desde el código de
nuestro componente del mismo modo que cuando están colocados en la bandeja
de componentes de un formulario Windows Forms.
El procedimiento para crear una clase de componentes con Visual Basic .NET
es similar al procedimiento para crear clases estándares, pero hay algunos pasos
adicionales.
1. Heredar de la clase System.ComponentModel.Component.
El elemento de plantilla Component Class contiene el código necesario
para heredar de la clase System.ComponentModel.Component,
incluyendo el código de constructor requerido para agregar nuestra clase de
componentes a un contenedor. Agregar cualquier código de inicialización
para nuestra clase de componentes como parte del proceso de construcción
insertando código en el método Sub New anteriormente escrito.
Podemos sobrecargar el método Dispose de la Component Class heredada
para liberar recursos antes de que se destruya la instancia de nuestro
componente.
2. Agregar componentes ubicados.
Si nuestra clase de componentes requiere otros componentes para realizar su
propósito, podemos agregarlos a la vista de diseño arrastrándolos desde el
Cuadro de herramientas o el Explorador de servidores a nuestra clase de
componentes. Estos componentes pueden ser accedidos programáticamente
desde dentro del código de nuestra clase de componentes.
3. Crear la funcionalidad requerida.
Nuestra clase de componentes puede proporcionar propiedades, métodos y
eventos públicos para permitir que el usuario de nuestro componente pueda
interactuar con él tanto en tiempo de diseño como en tiempo de ejecución.
4. Generar el ensamblado.
La generación del ensamblado permite que otros clientes gestionados
puedan hacer referencia a nuestro componente.
Desarrollo de componentes en Visual Basic .NET 35
Ë Generar el componente
1. Generar el proyecto.
2. Cerrar el proyecto.
38 Desarrollo de componentes en Visual Basic .NET
Ë Probar el componente
1. Ejecutar el proyecto, asegurándonos de que la ventana Resultados está
visible en segundo plano.
2. Hacer clic en Start Stopwatch, y observar los eventos que se muestran en
la ventana Resultados. Hacer clic en Tick Events para desactivar los
eventos.
3. Hacer clic en Stop Stopwatch para mostrar cuánto tiempo ha pasado desde
que se invocó el método Start en el componente Stopwatch.
4. Cerrar la aplicación y cerrar Visual Studio .NET.
Ejemplo
El siguiente ejemplo muestra cómo crear un control de usuario sencillo que
contiene una etiqueta y un cuadro de texto:
Public Class LabelAndTextControl
Inherits System.Windows.Forms.UserControl
Los controles TextBox1 y Label1 son variables declaradas privadas dentro del
control de usuario a las que sólo puede accederse utilizando las propiedades
públicas TextBoxText y LabelText.
42 Desarrollo de componentes en Visual Basic .NET
Este código crea un nuevo control que hereda todas las funcionalidades de la
clase TextBox y añade una propiedad denominada HiddenData.
<Category("Appearance"), _
Description("Stores extra data"), _
DefaultValue("Empty")> _
Public Property HiddenData( ) As String
...
End Property
...
End Class
46 Desarrollo de componentes en Visual Basic .NET
Ë Visualizar el código
1. Abrir Visual Studio .NET.
2. Abrir el proyecto MyControls.sln project de la carpeta UserTextBox que se
puede encontrar dentro del fichero demos11.zip.
3. Visualizar el código para la clase MyTextBox y examinar todos los
miembros de la clase.
4. Generar el proyecto y cerrarlo.
Ë Probar el control
1. Ejecutar el proyecto.
2. Cambiar secuencialmente el valor del texto de cada cuadro de texto en base
a los siguientes valores:
Control Valor de texto
TextBox One
MyTextBox One
TextBox Two
MyTextBox Two
TextBox Three
MyTextBox Three
3. Hacer clic en el botón Undo cuatro veces y observar los cambios de cada
cuadro de texto.
4. Cerrar el formulario y cerrar Visual Studio .NET.
48 Desarrollo de componentes en Visual Basic .NET
Aviso Esta sección ofrece una descripción general sobre el uso de hilos en
Visual Basic .NET. Éste es un tema muy complejo, y debemos estar seguros de
que comprendemos completamente sus implicaciones antes de utilizar estos
métodos. Si deseamos obtener más información, consultar el SDK del .NET
Framework.
Desarrollo de componentes en Visual Basic .NET 49
¿Qué es un hilo?
Objetivo
Explicar los conceptos
La unidad de ejecución que procesa la CPU
básicos del manejo de hilos z Todos los procesos de una aplicación contienen al menos un
de ejecución. subproceso
Presentación Los subprocesos están programados
Antes de examinar cómo
Visual Basic .NET permite z Parece que el equipo realiza varias tareas a la vez
manejar hilos, es importante
z Cada subproceso contiene su propia pila de llamadas y
entender los conceptos almacenamiento
básicos del mismo.
Programador de subprocesos
Subproc.1
Proceso 1 Subproc. 321
CPU
Subproc. 2
Proceso 2
Subproc. 3
Tipos de hilos
Cada lenguaje de programación puede soportar un tipo de hilo distinto:
Las versiones anteriores de Visual Basic soportan el modelo de hilos
apartamento (apartment).
Este modelo impone algunas restricciones en los tipos de aplicaciones que
estas versiones pueden crear. Una de estas restricciones es que un objeto
está ligado al hilo en el que está creado, y no puede utilizarse con la
agrupación de objetos en los servicios de componentes. Sin embargo, este
modelo facilita el desarrollo, ya que nos evita tratar con aspectos más
complejos como la sincronización.
Visual Basic .NET soporta el modelo de hilos libre (free).
Este modelo permite utilizar múltiples hilos de ejecución y características
como la agrupación de objetos o continuar utilizando un único hilo como en
las aplicaciones creadas con las versiones anteriores de Visual Basic.
Desarrollo de componentes en Visual Basic .NET 51
Una aplicación con múltiples hilos de ejecución tiene varias ventajas respecto a
una aplicación con un único hilo.
Sin bloqueos
El bloqueo se produce porque una llamada a una aplicación con un único hilo
debe esperar hasta que cualquier llamada previa por parte de otra aplicación
cliente haya sido completamente satisfecha antes de ejecutar cualquier otro
código. En aplicaciones basadas en servidor, el bloqueo ocurrirá si múltiples
clientes realizan peticiones simultáneas de un proceso y sólo está disponible un
único hilo.
Aplicaciones con múltiples hilos de ejecución pueden realizar acciones sobre
diferentes hilos simultáneamente (mediante la planificación de hilos) sin
esperar a que otros hilos finalicen su ejecución actual. Esto permite a múltiples
clientes ser gestionados por hilos diferentes sin bloquearse en una aplicación
basada en servidor.
52 Desarrollo de componentes en Visual Basic .NET
Comunicación asíncrona
Es posible la comunicación asíncrona en una aplicación con múltiples hilos de
ejecución porque un hilo puede realizar una petición a otro hilo. El hilo
llamador puede proseguir con otro procesamiento porque la petición se ejecuta
en un hilo separado. Puede lanzarse un evento cuando el segundo hilo finalice
la ejecución de la funcionalidad solicitada, informando al primer hilo que ha
completado su trabajo.
Creación de hilos
Objetivo
Explicar cómo crear y
utilizar hilos. Uso de la clase System.Threading.Thread
Presentación z El constructor especifica el método delegado
El .NET Framework
proporciona la clase
z Los métodos proporcionan control del procesamiento de
System.Threading.Thread,
hilos
que permite crear múltiples z Las propiedades proporcionan información de estado y
hilos. prioridades
Utilizar una clase si se requieren parámetros
z Permitir acceso público a variables clase
z Lanzar un evento cuando finalice
Uso de hilos
Objetivo
Class
Class Calculate
Calculate
Explicar un ejemplo sencillo Public
Public iValue
iValue AsAs Integer
Integer
del manejo de hilos. Public
Public Event
Event Complete(ByVal
Complete(ByVal Result
Result As
As Integer)
Integer)
Public
Public Sub
Sub LongCalculation(
LongCalculation( ))
Presentación 'Perform
'Perform aa long
long calculation
calculation based
based on
on iValue
iValue
Un vistazo a un ejemplo ...
...
sencillo de manejo de hilos. RaiseEvent Complete(iResult)
RaiseEvent Complete(iResult) 'Raise
'Raise event
event to
to signal
signal finish
finish
End
End Sub
Sub
End
End Class
Class
Sub
Sub Test(
Test( ))
Dim
Dim calc
calc As
As New
New Calculate(
Calculate( ))
Dim
Dim th
th As
As New
New Threading.Thread(AddressOf
Threading.Thread(AddressOf calc.LongCalculation)
calc.LongCalculation)
calc.iValue
calc.iValue == 10
10
AddHandler
AddHandler calc.Complete,
calc.Complete, AddressOf
AddressOf CalcResult
CalcResult
th.Start(
th.Start( ))
End
End Sub
Sub
Sub
Sub CalcResult(ByVal
CalcResult(ByVal Result
Result As
As Integer)
Integer)
...
...
End
End Sub
Sub
Este tópico muestra cómo preparar una clase para el manejo de hilos; crear un
hilo, iniciar el hilo y realizar cálculos sobre el nuevo hilo.
Class Calculate
Public iValue As Integer
Public Event Complete(ByVal Result As Integer)
Public Sub LongCalculation( )
'Perform a long calculation based on iValue
...
RaiseEvent Complete(iResult)'Raise event to signal finish
End Sub
End Class
Recursos compartidos
Si múltiples hilos necesitan acceder a la misma información al mismo tiempo,
puede producirse un problema de concurrencia. Dos hilos accediendo a un
recurso global compartido pueden generar resultados inconsistentes si otros
hilos han alterado los datos.
He aquí un ejemplo de una situación en la que esto puede suceder:
El hilo A actualiza un valor en un recurso compartido como un entero,
estableciendo el valor a 10 antes de realizar alguna acción de larga duración.
El hilo B actualiza el mismo valor entero a 15 durante la duración de la
acción de larga duración del hilo A.
Cuando se completa esta acción, el hilo A puede leer de nuevo el valor
entero del recurso cuyo valor es ahora 15.
Desarrollo de componentes en Visual Basic .NET 59
Imports System.Threading
'Shared data
Public Class SharedReference
Public Id As Integer
End Class
Count = sr.Id
End SyncLock 'Release sr object lock
End Sub
End Class
Module MainModule
Sub Main( )
'Create shared data object
Dim sr As New SharedReference( )