Apuntes de ADO.NET
Llop Site Home > Visual Studio .NET > Apuntes > ADO.NET 16-Feb-2005
16 Febrero 2005
Con la lección de hoy aprendemos a crear bases de datos en el servidor desde una aplicación local,
las múltiples prestaciones de la clase 'DataAdapter', más detalles sobre cómo crear ficheros XML
para almacenar 'DataSet's, y el funcionamiento de las aplicaciones remotas, tanto a nivel de servidor
como de cliente.
Índice de programas de prueba:
* DDL: Data Definition Lanaguage.
* TestDA: Aprendiendo a exprimir los recursos de DataAdapter.
* Intro XML: De 'DataSet's y de cómo éstos leen y escriben '.xml's y '.xsd's.
* Remoting: Accedediendo a objetos remotos desde una aplicación local.
DDL: Data Definition Language
Imports System.Data Imports System.Data.SqlClient Public Class Form1 : Iherits System.Windows.Forms.Form 'Constantes para no tener que picar cada vez el salto de línea y la tabulación. Const l As String = vbCrLf Const t As String = vbTab #Region " Código generado por el Diseñador " Public Sub New() MyBase.New() 'Se inicializan los componentes creados con el 'Diseñador'. InitializeComponent() End Sub ''Dispose' se sobrecarga para eliminar los componentes en la lista. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Contenedor para los componentes. Private components As System.ComponentModel.IContainer 'Código del 'Diseñador'; no tocar con el 'Editor de código'. Friend WithEvents TextBox1 As System.Windows.Forms.TextBox Friend WithEvents Label1 As System.Windows.Forms.Label Friend WithEvents Button1 As System.Windows.Forms.Button 'Método que inicializa los componentes creados con el 'Diseñador'. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.TextBox1 = New System.Windows.Forms.TextBox Me.Label1 = New System.Windows.Forms.Label Me.Button1 = New System.Windows.Forms.Button Me.SuspendLayout() 'TextBox1 Me.TextBox1.BackColor = System.Drawing.Color.FromArgb(CType(224, Byte), CType(224, Byte), CType(224, Byte)) Me.TextBox1.Font = New System.Drawing.Font("Microsoft Sans Serif", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) Me.TextBox1.ForeColor = System.Drawing.Color.Navy Me.TextBox1.Location = New System.Drawing.Point(264, 8) Me.TextBox1.Multiline = True Me.TextBox1.Name = "TextBox1" Me.TextBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both Me.TextBox1.Size = New System.Drawing.Size(424, 328) Me.TextBox1.TabIndex = 0 Me.TextBox1.Text = "" 'Label1 Me.Label1.BackColor = System.Drawing.Color.FromArgb(CType(255, Byte), CType(224, Byte), CType(192, Byte)) Me.Label1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D Me.Label1.Font = New System.Drawing.Font("Microsoft Sans Serif", 10.0!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte)) Me.Label1.ForeColor = System.Drawing.Color.Maroon Me.Label1.Location = New System.Drawing.Point(0, 8) Me.Label1.Name = "Label1" Me.Label1.Size = New System.Drawing.Size(248, 40) Me.Label1.TabIndex = 1 Me.Label1.Text = "1.-DDL" Me.Label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter 'Button1 Me.Button1.Location = New System.Drawing.Point(0, 56) Me.Button1.Name = "Button1" Me.Button1.Size = New System.Drawing.Size(128, 24) Me.Button1.TabIndex = 4 Me.Button1.Text = "2.- Ejemplos" 'Form1 Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.AutoScroll = True Me.ClientSize = New System.Drawing.Size(696, 357) Me.Controls.Add(Me.Button1) Me.Controls.Add(Me.TextBox1) Me.Controls.Add(Me.Label1) Me.Name = "Form1" Me.Text = "Form1" Me.ResumeLayout(False) End Sub #End Region 'Subrutina que pone un texto en el TextBox1. Sub Mostrar() Me.TextBox1.Text = "" Me.TextBox1.AppendText("En lugar de querys a los objetos del servidor, se pretende administrarlos: CREATE TABLE, CRETE PROCEDURE, CREATE INEX, ALTER TABLE" & l & l) Me.TextBox1.AppendText("CREATE TABLE" & l & "maneja tablas, columnas, restricciones") End Sub 'Al cargar el Form1, se pega una texto en el TextBox1 mediante la sub superior. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Mostrar() End Sub 'Responde al click sobre el Button1. 'Crea una tabla -'test'-, y un procedimiento -'InsertCategory'-, en la base de datos 'Northwind'. Private Sub eje1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'Declara una conexión, y un comando. Dim cn As New SqlConnection Dim cm As SqlCommand 'Se conecta a la base de datos 'Northwind', en el servidor del equipo local. cn.ConnectionString = "Data Source=localhost,1433;Integrated Security=True; Database=Northwind" cn.Open() 'Con este comando omitido, borraríamos 'InsertCategory' y 'test' antes de crear 'test' de nuevo. 'Dim tx As String = "DROP PROC InsertCategory; " 'tx &= "DROP TABLE test; " 'tx &= "CREATE TABLE test (campo1 int); " 'Solamente crearemos 'test', una tabla con un campo numérico. Dim Tx As String = "CREATE TABLE test (campo1 int); " 'Otro comando; este crea un procedimiento para insertar un nuevo valor a 'Categories'. Dim createStr As String = "CREATE PROCEDURE InsertCategory " & _ " @CategoryName nchar(15), " & _ " @Identity int OUT " & _ "AS " & _ "INSERT INTO Categories (CategoryName) VALUES(@CategoryName) " & _ "SET @Identity = @@Identity " & _ "RETURN @@ROWCOUNT" 'Los comandos SQL: uno creará el procedimiento, y el otro la tabla. Dim CMD As SqlCommand = New SqlCommand(createStr, cn) cm = New SqlCommand(tx, cn) 'Intentamos ejecutar las instrucciones de Transact-SQL en la conexión. Try cm.ExecuteNonQuery() CMD.ExecuteNonQuery() Catch ex As SqlException 'Si algo ha fallado, mostramos los detalles de todos los errores en la 'SQLException'. Dim se As SqlError For Each se In ex.Errors Me.TextBox1.Text &= l & "Severidad" & se.[Class] & l Me.TextBox1.Text &= "Mensaje" & se.Message & l Me.TextBox1.Text &= "Número" & se.Number & l Me.TextBox1.Text &= "Servidor" & se.Server & l Me.TextBox1.Text &= "Provider" & se.Source & l Next Finally 'Se cierra la conexión, y se elimina. cn.Close() : cn.Dispose() End Try End Sub End Class Paginar : Traer una cantidad de datos limitada dentro de una BD. ¿Cuándo es conveniente paginar? Cuando la BD es bastante grande, y, por cuestiones de rendimiento, no sale a cuenta traerla toda.
TestDA: Aprendiendo a exprimir los recursos de DataAdapter
Imports System.Data Imports System.Data.SqlClient Imports System.Data.OleDb Public Class Form1 : Inherits System.Windows.Forms.Form 'INTRODUCCIÓN a la clase DataAdapter ' 'La misión es llenar objetos DataTable desde una base de datos. Una vez hecha la 'transferencia de información la conexión se cierra, trabajando el cliente en modo 'desconectado. Tras los cambios, estos son grabados usando la misma clase DA. ' 'Hay un DA por cada Provider, porque DA debe saber como conectarse y desconectarse 'a la fuente de datos. #Region " Código generado por el Diseñador " Public Sub New() MyBase.New() 'Se inicializan los componentes creados con el 'Diseñador'. InitializeComponent() End Sub ''Dispose' se sobrecarga para eliminar los componentes en la lista. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Contenedor para los componentes. Private components As System.ComponentModel.IContainer 'Código del 'Diseñador'; no tocar con el 'Editor de código'. Friend WithEvents Button1 As System.Windows.Forms.Button Friend WithEvents DataGrid1 As System.Windows.Forms.DataGrid Friend WithEvents Button2 As System.Windows.Forms.Button Friend WithEvents TextBox1 As System.Windows.Forms.TextBox Friend WithEvents Button3 As System.Windows.Forms.Button Friend WithEvents SqlDataAdapter1 As System.Data.SqlClient.SqlDataAdapter Friend WithEvents SqlSelectCommand1 As System.Data.SqlClient.SqlCommand Friend WithEvents SqlConnection1 As System.Data.SqlClient.SqlConnection Friend WithEvents Button5 As System.Windows.Forms.Button Friend WithEvents SqlDataAdapter2 As System.Data.SqlClient.SqlDataAdapter Friend WithEvents SqlSelectCommand2 As System.Data.SqlClient.SqlCommand Friend WithEvents DataSet11 As TestDA.DataSet1 Friend WithEvents Button6 As System.Windows.Forms.Button Friend WithEvents Button7 As System.Windows.Forms.Button Friend WithEvents Button4 As System.Windows.Forms.Button Friend WithEvents Button8 As System.Windows.Forms.Button Friend WithEvents DataGrid2 As System.Windows.Forms.DataGrid Friend WithEvents Button9 As System.Windows.Forms.Button 'Método que inicializa los componentes creados con el 'Diseñador'. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.Button1 = New System.Windows.Forms.Button Me.DataGrid1 = New System.Windows.Forms.DataGrid Me.DataSet11 = New TestDA.DataSet1 Me.Button2 = New System.Windows.Forms.Button Me.TextBox1 = New System.Windows.Forms.TextBox Me.Button3 = New System.Windows.Forms.Button Me.SqlDataAdapter1 = New System.Data.SqlClient.SqlDataAdapter Me.SqlSelectCommand1 = New System.Data.SqlClient.SqlCommand Me.SqlConnection1 = New System.Data.SqlClient.SqlConnection Me.Button5 = New System.Windows.Forms.Button Me.SqlDataAdapter2 = New System.Data.SqlClient.SqlDataAdapter Me.SqlSelectCommand2 = New System.Data.SqlClient.SqlCommand Me.Button6 = New System.Windows.Forms.Button Me.Button7 = New System.Windows.Forms.Button Me.Button4 = New System.Windows.Forms.Button Me.Button8 = New System.Windows.Forms.Button Me.DataGrid2 = New System.Windows.Forms.DataGrid Me.Button9 = New System.Windows.Forms.Button CType(Me.DataGrid1, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.DataSet11, System.ComponentModel.ISupportInitialize).BeginInit() CType(Me.DataGrid2, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() 'Button1 Me.Button1.Location = New System.Drawing.Point(8, 32) Me.Button1.Name = "Button1" Me.Button1.TabIndex = 0 Me.Button1.Text = "Intro" 'DataGrid1 Me.DataGrid1.DataMember = "" Me.DataGrid1.DataSource = Me.DataSet11.CustOrdersDetail Me.DataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText Me.DataGrid1.Location = New System.Drawing.Point(192, 264) Me.DataGrid1.Name = "DataGrid1" Me.DataGrid1.Size = New System.Drawing.Size(488, 176) Me.DataGrid1.TabIndex = 1 'DataSet11 Me.DataSet11.DataSetName = "DataSet1" Me.DataSet11.Locale = New System.Globalization.CultureInfo("es-ES") 'Button2 Me.Button2.Location = New System.Drawing.Point(8, 64) Me.Button2.Name = "Button2" Me.Button2.TabIndex = 2 Me.Button2.Text = "Métodos" 'TextBox1 Me.TextBox1.Location = New System.Drawing.Point(184, 16) Me.TextBox1.Multiline = True Me.TextBox1.Name = "TextBox1" Me.TextBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both Me.TextBox1.Size = New System.Drawing.Size(480, 56) Me.TextBox1.TabIndex = 3 Me.TextBox1.Text = "TextBox1" 'Button3 Me.Button3.Location = New System.Drawing.Point(640, 240) Me.Button3.Name = "Button3" Me.Button3.Size = New System.Drawing.Size(32, 16) Me.Button3.TabIndex = 4 Me.Button3.Text = "+" 'SqlDataAdapter1 Me.SqlDataAdapter1.SelectCommand = Me.SqlSelectCommand1 Me.SqlDataAdapter1.TableMappings.AddRange(New System.Data.Common.DataTableMapping() {New System.Data.Common.DataTableMapping("Table", "Customers", New System.Data.Common.DataColumnMapping() {New System.Data.Common.DataColumnMapping("ContactName", "ContactName"), New System.Data.Common.DataColumnMapping("Phone", "Phone")})}) 'SqlSelectCommand1 Me.SqlSelectCommand1.CommandText = "SELECT ContactName, Phone FROM Customers" Me.SqlSelectCommand1.Connection = Me.SqlConnection1 'SqlConnection1 Me.SqlConnection1.ConnectionString = "workstation id=RAUL;packet size=4096;integrated security=SSPI;data source=localho" & _ "st;persist security info=False;initial catalog=Northwind" 'Button5 Me.Button5.Location = New System.Drawing.Point(112, 32) Me.Button5.Name = "Button5" Me.Button5.Size = New System.Drawing.Size(56, 23) Me.Button5.TabIndex = 6 Me.Button5.Text = "DA prog" 'SqlDataAdapter2 Me.SqlDataAdapter2.SelectCommand = Me.SqlSelectCommand2 Me.SqlDataAdapter2.TableMappings.AddRange(New System.Data.Common.DataTableMapping() {New System.Data.Common.DataTableMapping("Table", "CustOrdersDetail", New System.Data.Common.DataColumnMapping() {New System.Data.Common.DataColumnMapping("ProductName", "ProductName"), New System.Data.Common.DataColumnMapping("UnitPrice", "UnitPrice"), New System.Data.Common.DataColumnMapping("Quantity", "Quantity"), New System.Data.Common.DataColumnMapping("Discount", "Discount"), New System.Data.Common.DataColumnMapping("ExtendedPrice", "ExtendedPrice")})}) 'SqlSelectCommand2 Me.SqlSelectCommand2.CommandText = "[CustOrdersDetail]" Me.SqlSelectCommand2.CommandType = System.Data.CommandType.StoredProcedure Me.SqlSelectCommand2.Connection = Me.SqlConnection1 Me.SqlSelectCommand2.Parameters.Add(New System.Data.SqlClient.SqlParameter("@RETURN_VALUE", System.Data.SqlDbType.Int, 4, System.Data.ParameterDirection.ReturnValue, False, CType(0, Byte), CType(0, Byte), "", System.Data.DataRowVersion.Current, Nothing)) Me.SqlSelectCommand2.Parameters.Add(New System.Data.SqlClient.SqlParameter("@OrderID", System.Data.SqlDbType.Int, 4)) 'Button6 Me.Button6.Location = New System.Drawing.Point(112, 64) Me.Button6.Name = "Button6" Me.Button6.Size = New System.Drawing.Size(56, 23) Me.Button6.TabIndex = 7 Me.Button6.Text = "DA.Fill" 'Button7 Me.Button7.Location = New System.Drawing.Point(112, 96) Me.Button7.Name = "Button7" Me.Button7.Size = New System.Drawing.Size(56, 23) Me.Button7.TabIndex = 8 Me.Button7.Text = "DA.Missing" 'Button4 Me.Button4.Location = New System.Drawing.Point(8, 144) Me.Button4.Name = "Button4" Me.Button4.Size = New System.Drawing.Size(56, 23) Me.Button4.TabIndex = 9 Me.Button4.Text = "Update0" 'Button8 Me.Button8.Location = New System.Drawing.Point(8, 96) Me.Button8.Name = "Button8" Me.Button8.TabIndex = 10 Me.Button8.Text = "FillSchema" 'DataGrid2 Me.DataGrid2.DataMember = "" Me.DataGrid2.HeaderForeColor = System.Drawing.SystemColors.ControlText Me.DataGrid2.Location = New System.Drawing.Point(184, 104) Me.DataGrid2.Name = "DataGrid2" Me.DataGrid2.Size = New System.Drawing.Size(480, 120) Me.DataGrid2.TabIndex = 11 'Button9 Me.Button9.Location = New System.Drawing.Point(8, 168) Me.Button9.Name = "Button9" Me.Button9.Size = New System.Drawing.Size(56, 23) Me.Button9.TabIndex = 12 Me.Button9.Text = "Update1" 'Form1 Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.AutoScroll = True Me.ClientSize = New System.Drawing.Size(704, 453) Me.Controls.Add(Me.Button9) Me.Controls.Add(Me.DataGrid2) Me.Controls.Add(Me.Button8) Me.Controls.Add(Me.Button4) Me.Controls.Add(Me.Button7) Me.Controls.Add(Me.Button6) Me.Controls.Add(Me.Button5) Me.Controls.Add(Me.Button3) Me.Controls.Add(Me.TextBox1) Me.Controls.Add(Me.Button2) Me.Controls.Add(Me.DataGrid1) Me.Controls.Add(Me.Button1) Me.Name = "Form1" Me.Text = "System.Data.SqlCliente.SqlDataAdapter" CType(Me.DataGrid1, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.DataSet11, System.ComponentModel.ISupportInitialize).EndInit() CType(Me.DataGrid2, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) End Sub #End Region 'DA para bases de datos SQL. Dim DA, daSQL As SqlDataAdapter 'DA para bases de datos OLE. Dim daExcel As OleDb.OleDbDataAdapter 'DS para almacenar las consultas a las BD. Dim ds As New DataSet ''daUpdate' actualizará la BD; 'dsUpdate' actualizará el DataSet Dim daUpdate As SqlDataAdapter, dsUpdate As DataSet 'Este método responde al click sobre el botón "intro". 'Llena un mismo DataSet con datos obtenidos de fuentes dispares (una tabla de Excel, 'y otra de SQL). Private Sub intro(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'EXCEL 'Nótese en la cadena de conexión que la tabla Excel está en el mismo directorio que la aplicación. Dim cnstrExcel As String cnstrExcel = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & Application.StartupPath & _ "\ListasDePrecios.xls;Extended Properties=Excel 8.0;" 'Se inicializa el objeto conexión. Gracias a éste, se inicializa el DA para la tabla 'de Excel 'Tarifas' -se recomienda poner el nombre de la tabla entre corchetes. Dim objConn As New System.Data.OleDb.OleDbConnection(cnstrExcel) daExcel = New OleDb.OleDbDataAdapter("SELECT * FROM [Tarifas$]", objConn) 'Se crea un DataSet, y se le añade la tabla que viene de Excel. Dim ds As New DataSet Try daExcel.Fill(ds, "TablaExcel") Catch ex As OleDbException End Try 'Ahora tres cuartos de lo mismo para llenar el DS con la tabla SQL. Dim cn As New SqlConnection cn.ConnectionString = "Integrated Security=false;" & _ "Initial Catalog=Northwind;" & _ "Data Source=localhost,1433; user id=sa; password=1234" daSQL = New SqlDataAdapter("SELECT * FROM Customers", cn) 'Rellenamos el 'DataSet', con los datos del 'DataAdapter'. Pero, ¿no se machacará la ''TablaExcel'? No: 'DataSet' puede almacenar más de una tabla al mismo tiempo. Try daSQL.Fill(ds, "TablaSQL") Catch ex As SqlException End Try 'Se rellena el 'DataGrid' con el 'DS'. También se le podría pasar: ' Una 'DataTable', ' un 'DataView', ' un 'DataViewManager', ' y cualquier componente que implemente la interfaz IListSource, o IList. With Me.DataGrid1 .DataSource = ds End With End Sub Private Sub métodos(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click With DA 'PROPIEDADES 'SelectCommand, UpdateCommand, DeleteCommand, InsertCommand. ' El TextBox1 enseñará las declaraciones SQL para SELECT, UPDATE, DELETE, INSERT la BBDD. 'Me.TextBox1.AppendText(.SelectCommand.ToString & vbCrLf) 'Me.TextBox1.AppendText(.UpdateCommand.ToString & vbCrLf) 'Me.TextBox1.AppendText(.DeleteCommand.ToString & vbCrLf) 'Me.TextBox1.AppendText(.InsertCommand.ToString & vbCrLf) 'TableMappings ' Mantiene la correspondencia entre las columnas y tablas del DataSet ' y las equivalentes de la fuente de datos. Inicializamos una instancia de ' 'DataTableMappingCollection' con los 'TableMappings' de este 'DataAdapter'. 'Dim tm As System.Data.Common.DataTableMappingCollection 'tm = .TableMappings 'MissingMappingAction() ' La acción a seguir cuando los datos no se casan con con una ' tabla o columna. Las acciones se enumeran como: ' 'Se genera una InvalidOperationException error: '.MissingMappingAction = MissingMappingAction.[Error] ' 'Columna o tabla ignorada si no tiene correspondencia, devuelve null: '.MissingMappingAction = MissingMappingAction.Ignore ' 'Se crea la tabla o columna no existente, añadiéndose al dataset con 'su nombre original: '.MissingMappingAction = MissingMappingAction.Passthrough 'MissingSchemaAction ' Acción a tomar cuando el Schema del DataSet no concuerda ' 'Se añaden las columnas que hagan falta para completar el schema. '.MissingSchemaAction = MissingSchemaAction.Add ' 'Se añaden las columnas que hagan falta para completar el schema 'junto con la clave primaria. '.MissingSchemaAction = MissingSchemaAction.AddWithKey ' 'Se genera una InvalidOperationException error. '.MissingSchemaAction = MissingSchemaAction.[Error] ' 'Se obvian las columnas extras. '.MissingSchemaAction = MissingSchemaAction.Ignore 'AcceptChangesDuringFill ' Determina si el método AcceptChanges es llamado cuando un DataRow es ' añadido a la tabla 'Dim bo As Boolean = .AcceptChangesDuringFill() End With 'MÉTODOS 'Fill ' Añade rows al DataSet; en los argumentos puedes definir el registro a partir ' del que copiar, y cuántos copiar. 'Dim cuantasFilasLeidas As Integer = DA.Fill(ds, 0, 100, "TablaASerRellenada") '¿Cómo utilizaríamos la construcción anterior para introducir navegación? 'ver AvanzarAPagina() 'Pasa que si la base de datos es muy grande, el 'DataSet' será enorme, y eso en 'pocos casos es práctico. '¿Cómo implementaríamos una paginación más avanzada? 'Update ' Actualiza la fuente de dtos con los comandos INSERT, UPDATE o DELETE ' necesarios '.Update(ds) 'ver sobrecarga del constructor End Sub 'Típica función para paginar: vemos que avanza de 5 en 5 registros. Function AvanzarAPagina(ByVal n As Integer) As Integer Return daExcel.Fill(ds, (n - 1) * 5, 5, "TablaExcel") End Function 'Método que responde al pulsar el botón 3; 'DataGrid' muestra los datos correspondientes a la página 3. Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click AvanzarAPagina(3) Me.DataGrid1.DataSource = ds End Sub 'Salta al pulsar el 'Button5'. Lo que hace es rellenar el 'DataGrid1' con datos devueltos por 'un 'procedimiento almacenado' de la base de datos. Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click Dim daProg As New SqlDataAdapter Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true") 'Comando normal y corriente: 'Dim cm As New SqlCommand("SELECT * FROM Products", cn) 'Variante si se trata de un 'stored procedure': Dim cmStoreProcedure As SqlCommand cmStoreProcedure.CommandText = "CustOrdersOrders" cmStoreProcedure.CommandType = CommandType.StoredProcedure daProg.SelectCommand = cmStoreProcedure Try daProg.Fill(ds) Me.DataGrid1.DataSource = ds Catch ex As Exception MsgBox(ex.Message) End Try End Sub 'Responde al pulsar sobre el 'Button6'. De nuevo se rellena el 'DataGrid1', sólo que esta 'vez se toman medidas para optimizar la carga de datos en el 'DataSet'. Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click Dim daProg As New SqlDataAdapter Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true") Dim cm As New SqlCommand("SELECT * FROM Customers", cn) daProg.SelectCommand = cm Dim ds As New DataSet ds.Tables.Add(New DataTable("Clientes")) 'Optimizaciones del método Fill Try 'Las restricciones no se tendrán en cuenta a la hora de hacer actualizaciones a 'ds'. ds.EnforceConstraints = False 'Se desactivan notificaciones, mantenimiento de índices y restricciones. ds.Tables(0).BeginLoadData() 'Se cargan los datos. daProg.Fill(ds, "Clientes") 'Al terminar la carga de datos, se activan notificaciones, mantenimiento de índices y restricciones. ds.Tables(0).EndLoadData() Me.DataGrid1.DataSource = ds.Tables(0).DefaultView Catch ex As SqlException MsgBox(ex.Message) End Try End Sub 'Con esta subrutina, que responde al click en 'Button7', se pretende mostrar lo que se puede 'hacer cuando el 'esquema' de un 'DataSet' no coincide con el de los datos para rellenarlo. Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true") Dim ds As New DataSet ds.Tables.Add("Clientes") ds.Tables("Clientes").Columns.Add(New DataColumn("nombre", GetType(String))) Dim da As New SqlDataAdapter 'Probar las variantes 'da.MissingSchemaAction = MissingSchemaAction.[Error] 'da.MissingSchemaAction = MissingSchemaAction.AddWithKey da.MissingSchemaAction = MissingSchemaAction.Ignore da.SelectCommand = New SqlCommand("SELECT * FROM Products", cn) 'Como la tabla 'Clientes' de 'ds' tiene un esquema ya, lo que se va a mostrar en el ''DataGrid1' dependerá del 'MissingSchemaAction' utilizado. Try da.Fill(ds.Tables("Clientes")) Me.DataGrid1.DataSource = ds Catch ex As SqlException MsgBox(ex.Message) End Try 'En el siguiente bloque, el 'Schema' se añadirá a 'ds' antes que los datos. Dim da2 As New SqlDataAdapter Dim cm2 As New SqlCommand("Select * From Employees", cn) da2.SelectCommand = cm2 Try da2.FillSchema(ds, SchemaType.Mapped) da2.Fill(ds) Me.DataGrid1.DataSource = ds.Tables(0).DefaultView Catch ex As SqlException End Try End Sub 'Click sobre el 'Button4': 'DataGrid1' toma los datos de la tabla 'Empleados' de 'dsUpdate', 'que ha sido primero creada, y luego rellenada por 'daUpdate'. Private Sub update0(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true") dsUpdate = New DataSet 'Se añade a 'dsUpdate' una tabla llamada 'Empleados'. dsUpdate.Tables.Add("Empleados") daUpdate = New SqlDataAdapter Dim cm As New SqlCommand("Select * From Employees", cn) daUpdate.SelectCommand = cm 'Llenado Try daUpdate.Fill(dsUpdate, "Empleados") Me.DataGrid1.DataSource = dsUpdate.Tables("Empleados").DefaultView Catch ex As SqlException MsgBox(ex.Message) End Try End Sub 'Método que salta al pinchar en 'Button9'. Se pretende mostrar: ' Si ha habido cambios en un 'DataSet'. ' De ser así, ¿qué tipo de cambios? -¿fila añadida, eliminada o modificada?. ' Una tabla con las filas retocadas. Private Sub update1(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button9.Click 'Detectemos qué cambios ha habido (para hacerlo bien, necesitaríamos una estructura ''Select Case'). 'Dim bo As Boolean 'If dsUpdate.HasChanges Then ' ¿Filas nuevas? ' bo = dsUpdate.HasChanges(DataRowState.Added) ' ¿Filas borradas? ' bo = dsUpdate.HasChanges(DataRowState.Deleted) ' ¿Filas modificadas? ' bo = dsUpdate.HasChanges(DataRowState.Modified) 'End If 'Veamos filas retocadas en el 'DataGrid2'. Dim dt As DataTable = dsUpdate.Tables("Empleados").GetChanges(DataRowState.Modified) If dt.Rows.Count > 0 Then Me.DataGrid2.DataSource = dt.DefaultView End If End Sub 'En esta 'sub' se muestra cómo cambiar la base de datos de la conexión, 'cómo traer más de una tabla -utilizando una consulta múltiple-, 'y mostrar en el 'DataGrid' una sola de las tablas del 'DataSet'. Private Sub Button8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button8.Click Dim cn As New SqlConnection("data source=localhost,1433;initial catalog=Northwind;integrated security=true") cn.Open() 'Cambiamos la base de datos a la que apuntaba la conexión. cn.ChangeDatabase("Pubs") 'La consulta deberá traer tres tablas de resultados. Dim sql As String = "SELECT * FROM Publishers;SELECT * FROM Titles;SELECT * FROM authors" Dim da As New SqlDataAdapter(sql, cn) 'Se añade una tabla sin nombre al 'DataSet'. Dim ds As New DataSet ds.Tables.Add("") With da .TableMappings.Add("Publishers", "DataPublishers") .ColumnMappings.Add("pub_id", "ID") .ColumnMappings.Add("pub_name", "Name") End With ''ds' toma el mismo esquema que el de 'da' -recordemos que éste almacena tres tablas 'de resultados. da.FillSchema(ds, SchemaType.Source, "Publishers") 'Se pone nombre a las otras 2 tablas de 'ds'. ds.Tables(1).TableName = "Titles" ds.Tables(2).TableName = "Authors" DataGrid1.DataSource = ds.Tables("Authors") End Sub End ClassIntro XML: De 'DataSet's y de cómo éstos leen y escriben '.xml's y '.xsd's
Imports System.Data Imports System.Xml Imports System.IO Public Class Form1 : Inherits System.Windows.Forms.Form Dim dsClase As DataSet #Region " Código generado por el Diseñador " Public Sub New() MyBase.New() 'Se inicializan los componentes creados con el 'Diseñador'. InitializeComponent() End Sub ''Dispose' se sobrecarga para eliminar los componentes en la lista. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Contenedor para los componentes. Private components As System.ComponentModel.IContainer 'Código del 'Diseñador'; no tocar con el 'Editor de código'. Friend WithEvents Button1 As System.Windows.Forms.Button Friend WithEvents SqlDataAdapter1 As System.Data.SqlClient.SqlDataAdapter Friend WithEvents SqlSelectCommand1 As System.Data.SqlClient.SqlCommand Friend WithEvents SqlConnection1 As System.Data.SqlClient.SqlConnection Friend WithEvents Button2 As System.Windows.Forms.Button Friend WithEvents DataGrid1 As System.Windows.Forms.DataGrid Friend WithEvents Button3 As System.Windows.Forms.Button Friend WithEvents TextBox1 As System.Windows.Forms.TextBox Friend WithEvents Button4 As System.Windows.Forms.Button Friend WithEvents Button5 As System.Windows.Forms.Button 'Método que inicializa los componentes creados con el 'Diseñador'. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.Button1 = New System.Windows.Forms.Button Me.SqlDataAdapter1 = New System.Data.SqlClient.SqlDataAdapter Me.SqlSelectCommand1 = New System.Data.SqlClient.SqlCommand Me.SqlConnection1 = New System.Data.SqlClient.SqlConnection Me.Button2 = New System.Windows.Forms.Button Me.DataGrid1 = New System.Windows.Forms.DataGrid Me.Button3 = New System.Windows.Forms.Button Me.TextBox1 = New System.Windows.Forms.TextBox Me.Button4 = New System.Windows.Forms.Button Me.Button5 = New System.Windows.Forms.Button CType(Me.DataGrid1, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() 'Button1 Me.Button1.Location = New System.Drawing.Point(24, 24) Me.Button1.Name = "Button1" Me.Button1.TabIndex = 0 Me.Button1.Text = "Intro" 'SqlDataAdapter1 Me.SqlDataAdapter1.SelectCommand = Me.SqlSelectCommand1 Me.SqlDataAdapter1.TableMappings.AddRange(New System.Data.Common.DataTableMapping() {New System.Data.Common.DataTableMapping("Table", "authors", New System.Data.Common.DataColumnMapping() {New System.Data.Common.DataColumnMapping("au_id", "au_id"), New System.Data.Common.DataColumnMapping("au_lname", "au_lname"), New System.Data.Common.DataColumnMapping("au_fname", "au_fname"), New System.Data.Common.DataColumnMapping("phone", "phone"), New System.Data.Common.DataColumnMapping("address", "address"), New System.Data.Common.DataColumnMapping("city", "city"), New System.Data.Common.DataColumnMapping("state", "state"), New System.Data.Common.DataColumnMapping("zip", "zip"), New System.Data.Common.DataColumnMapping("contract", "contract")})}) 'SqlSelectCommand1 Me.SqlSelectCommand1.CommandText = "SELECT au_id, au_lname, au_fname, phone, address, city, state, zip, contract FROM" & _ " authors" Me.SqlSelectCommand1.Connection = Me.SqlConnection1 'SqlConnection1 Me.SqlConnection1.ConnectionString = "workstation id=RAUL;packet size=4096;user id=sa;data source=localhost;persist sec" & _ "urity info=True;initial catalog=pubs;password=" 'Button2 Me.Button2.Location = New System.Drawing.Point(24, 56) Me.Button2.Name = "Button2" Me.Button2.TabIndex = 1 Me.Button2.Text = "Metadata" 'DataGrid1 Me.DataGrid1.DataMember = "" Me.DataGrid1.HeaderForeColor = System.Drawing.SystemColors.ControlText Me.DataGrid1.Location = New System.Drawing.Point(392, 40) Me.DataGrid1.Name = "DataGrid1" Me.DataGrid1.Size = New System.Drawing.Size(312, 240) Me.DataGrid1.TabIndex = 2 'Button3 Me.Button3.Location = New System.Drawing.Point(0, 96) Me.Button3.Name = "Button3" Me.Button3.Size = New System.Drawing.Size(96, 40) Me.Button3.TabIndex = 3 Me.Button3.Text = "Grabar XMLSchema" 'TextBox1 Me.TextBox1.Location = New System.Drawing.Point(120, 16) Me.TextBox1.Multiline = True Me.TextBox1.Name = "TextBox1" Me.TextBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both Me.TextBox1.Size = New System.Drawing.Size(256, 264) Me.TextBox1.TabIndex = 4 Me.TextBox1.Text = "" 'Button4 Me.Button4.Location = New System.Drawing.Point(0, 144) Me.Button4.Name = "Button4" Me.Button4.Size = New System.Drawing.Size(96, 24) Me.Button4.TabIndex = 5 Me.Button4.Text = "Grabar XMData" 'Button5 Me.Button5.Location = New System.Drawing.Point(0, 168) Me.Button5.Name = "Button5" Me.Button5.Size = New System.Drawing.Size(112, 24) Me.Button5.TabIndex = 6 Me.Button5.Text = "Grabar DiffGram-1" 'Form1 Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.AutoScroll = True Me.ClientSize = New System.Drawing.Size(736, 357) Me.Controls.Add(Me.Button5) Me.Controls.Add(Me.Button4) Me.Controls.Add(Me.TextBox1) Me.Controls.Add(Me.Button3) Me.Controls.Add(Me.DataGrid1) Me.Controls.Add(Me.Button2) Me.Controls.Add(Me.Button1) Me.Name = "Form1" Me.Text = "XML 1" CType(Me.DataGrid1, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) End Sub #End Region 'Responde al pulsar sobre 'Button1'. Se demuestra cómo inicializar un 'DataSet' de 'tres formas distintas. Private Sub intro(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'Cuando se crea un 'DataSet', carece de estructura alguna. Dim ds As New DataSet 'Dicha estructura se puede añadir a mano -ponemos una tabla, y a ésta una columna. ds.Tables.Add("Tabla1") ds.Tables("Tabla1").Columns.Add("Columna1") 'Pero además se puede obtener vía un XSD schema. ' XSD schema es un documento que describe la estructura de un documento XML ' y sus constraints, relaciones, claves, tipos de datos de cada elemento... Dim dsx As DataSet Try dsx = New DataSet ''..\' hace referencia al directorio superior del directorio base; 'se pueden ir subiendo directorios siguiendo este patrón: "..\\..\\" etcétera. dsx.ReadXmlSchema("..\\XSDschema.xsd") Catch ex As Exception MsgBox(ex.Message) End Try 'En lugar de leer directamente del fichero, podemos leer de un 'Stream' -un flujo de datos. ' Un Web service, o aplicación ASP no nos pasará un fichero; deberá ser un 'stream'. Dim dsx2 As DataSet Dim reader As StreamReader Try dsx2 = New DataSet reader = New StreamReader("..\\XSDschema.xsd") dsx2.ReadXmlSchema(reader) Catch ex As Exception MsgBox(ex.Message) Finally If Not reader Is Nothing Then reader.Close() End If End Try End Sub 'Esta sub, que salta al 'clickar' sobre 'Button2', muestra cómo se rellena un 'DataSet' 'a partir de un fichero '.xml', atendiendo al 'modo de lectura XML'. Private Sub metadata(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 'Propiedades del 'DataSet' para obtener info: ' 'Tables ' Permite referenciar la DataTableCollection de un DataSet. 'Relations ' Permite referenciar la DataRelationCollection de un DataSet. 'Tables.Count ' Devuelve el número de tablas en un DataSet. 'Tables(indice).TableName ' Devuelve el nombre de la tabla en el índice especificado del DataTableCollection. 'Tables(nombre | indice).Columns(indiceCol) ' Permite referenciar la DataColumnCollection de la columna indicada con 'indiceCol'. 'Tables(indice).Columns(indiceCol).ColumnName ' Devuelve el nombre de la columna indicada con 'indiceCol'. 'Tables(indice).Columns(indiceCol).DataType ' Devuelve el tipo de datos de la columna indicada con 'indiceCol'. 'Tables(indice).Columns.Count ' Devuelve el número de columnas en la tabla. 'Obtenemos el 'DataSet' a partir de un fichero '.xsd' -pero sólo copiamos los datos; 'el esquema lo obviamos. Dim dsx As DataSet Try dsx = New DataSet dsx.ReadXml("..\\XSDschema.xsd", XmlReadMode.IgnoreSchema) Catch ex As Exception MsgBox(ex.Message) End Try 'Aunque no tenga esquema, podemos conocer propiedades del 'DataSet'. With dsx Dim i As Int32 = .Tables.Count() 'Dim n As String = .Tables(0).TableName 'ojo, puede volver una cadena 'null'. End With 'Parámetros 'XMLReadMode' que podemos pasar al método 'readXML()', y sus consecuencias: Try 'XmlReadMode.IgnoreSchema: ' No lee el 'inline Schema', pero sí los datos del input. ' Añade las tablas sólo si coinciden con la estructura del DS. 'dsx.ReadXml("..\\XSDschema.xsd", XmlReadMode.IgnoreSchema) ' 'XmlReadMode.ReadSchema: Lee el schema (si lo hay), y luego carga los datos. ' Si el DS ya tiene un schema, añade las nuevas tablas. ' Si el DS ya tiene un schema, y no hay tablas nuevas, error. ' Si el DS no tiene schema, y no hay inline schema, no se lee nada 'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.ReadSchema) ' 'XmlReadMode.InferSchema: ' No lee el inline schema, más bien lo infiere de leer los datos XML. ' Si el DS ya tiene un schema, el nuevo es añadido. 'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.InferSchema) ' 'XmlReadMode.DiffGram: ' Lee un DiffGram y añade los datos al DS. 'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.DiffGram) ' 'XmlReadMode.Fragment: ' Añade datos a un schema ya existente en el DS (SQL). 'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.Fragment) ' 'XmlReadMode.Auto: Al examinar el fichero XML, decide lo que cree más apropiado: ' Si el DS tiene un schema o el archivo tiene un inline schema, ejecuta 'ReadSchema'. ' Si DS no tiene schema y tampoco el archivo, se usa 'InferSchema'. 'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.Auto) 'Por rendimiento, evitar Auto. 'Si probamos esto... dsx = New DataSet dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.ReadSchema) 'dsx.ReadXml("..\\Dataset1.xsd", XmlReadMode.ReadSchema) Dim i As Integer = dsx.Tables.Count Dim n As String = dsx.Tables(0).TableName Me.DataGrid1.DataSource = dsx '...no se cargaron los datos porque no había esquema en el DS. Catch ex As Exception MsgBox(ex.Message) End Try 'En cambio, si lo que probamos es esto... 'dsx = New DataSet 'dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.InferSchema) 'Dim i2 As Integer = dsx.Tables.Count 'Dim n2 As String = dsx.Tables(0).TableName 'Me.DataGrid1.DataSource = dsx '...se crea un nuevo 'schema' inferido de los datos, y éstos son cargados. End Sub 'Aquí mostramos cómo convertir el 'schema' de un 'DataSet' en un fichero '.xsd'. 'La subrutina salta al hacer click en el 'Button3'. Private Sub grabar(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click Dim dsx As DataSet Try dsx = New DataSet dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.InferSchema) Me.DataGrid1.DataSource = dsx 'El 'DataSet' -con datos y esquema- está listo y mostrándose en el 'DataGrid1'. 'Ahora escibimos la estructura del 'DataSet' como un fichero '.xsd', 'utilizando el método 'WriteXmlSchema()'. dsx.WriteXmlSchema("ficheroschema.xsd") 'Fichero en el directorio base. 'También podemos conocer el esquema XML mediante 'GetXmlSchema()', que lo 'escribe en una cadena de texto. Dim str As String = dsx.GetXmlSchema Me.TextBox1.Text = str Catch ex As Exception MsgBox(ex.Message) End Try End Sub 'La subrutina contesta al pinchar sobre 'Button4'. 'Se indica cómo escribir un 'DataSet' a presión en un fichero '.xml'. Private Sub grabardata(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click Dim dsx As DataSet Try dsx = New DataSet dsx.ReadXml("..\\XML basado en el schema.xml", XmlReadMode.InferSchema) Me.DataGrid1.DataSource = dsx 'El 'DataSet' -con datos y esquema- está listo y mostrándose en el 'DataGrid1'. 'Podemos grabar un fichero '.xml' con los datos de 'DataSet' usando 'WriteXml()'. dsx.WriteXml("fichero.xml") 'Fichero en el directorio base. 'Es posible especificar el 'modo de escritura XML' que utilizará 'WriteXml()', 'igual que se podía indicar el modo de lectura en 'ReadXml()'. ' 'No se incluye el schema con los datos. Y si tampoco hay datos, no se crea fichero. 'dsx.WriteXml("ficheroIgNoreSchema.xml", XmlWriteMode.IgnoreSchema) 'Sólo se escribe el 'schema', sin los datos. Si no hay esquema, no se crea fichero. 'dsx.WriteXml("ficheroWriteSchema.xml", XmlWriteMode.WriteSchema) 'Contiene los valores originales y actuales de la información. 'dsx.WriteXml("ficheroDiffGram.xml", XmlWriteMode.DiffGram) Catch ex As Exception MsgBox(ex.Message) End Try End Sub 'Muestra cómo grabar un 'Dataset' a un fichero '.xml' en modo 'DiffGram': de esta forma 'se guardan los valores originales del 'DataSet', y los nuevos. 'Por cierto, la sub saltará al accionar el 'Button5'. Private Sub grabardiff(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click Try 'Llenamos un 'DataSet' con los datos de una BD. Dim cn As New SqlClient.SqlConnection("data source=localhost;integrated security=True;initial catalog=pubs;") cn.Open() Dim da As New SqlClient.SqlDataAdapter("Select * from authors", cn) Dim ds As New DataSet da.Fill(ds, "Autores") 'Vamos a hacer unos cambios: ' Borramos la fila 0, ' y cambiamos el nombre y apellido del registro de la fila 1. With ds.Tables("Autores") .Rows(0).Delete() .Rows(1)("au_fname") = "PEpe" .Rows(1)("au_lname") = "gotera" End With 'Pasamos el 'DataSet' al 'DataGrid1', e intentamos escribir el 'DiffGram'. Me.DataGrid1.DataSource = ds ds.WriteXml("XMLSoloDiferencias.xml", XmlWriteMode.DiffGram) Catch ex As Exception Console.WriteLine("Excep: " & e.ToString()) End Try End Sub End Class
Remoting: Accedediendo a objetos remotos desde una aplicación local
La aplicación del cliente no se puede ejecutar si el servicio remoto no está corriendo. MarshalByRefObject es la clase base de los objetos que se comunican a través de los límites de los dominios de aplicación que utilizan un proxy para intercambiar mensajes. Proxy: Servidor 'intermediario' que se utiliza para hacer consultas a un servidor en lugar de conectar el equipo directamente a éste. Los proxys se utilizan para mejorar la seguridad del servidor, y tener más control administrativo. El objeto remoto: Namespace ServiciosRemotos 'La clase 'HelloWorld' debe heredar de 'MarshallByRefObject'. Public Class HelloWorld : Inherits MarshalByRefObject 'Función que devuelve un mensajito. Public Function Display () As String Return "Hola, soy un objeto remoto que viene del servidor." End Function End Class End Namespace El servidor: Imports ServiciosRemotos Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels.Tcp Imports System.Runtime.Remoting.Channels Imports System.Runtime.Serialization.Formatters.Binary Public Class Form1 : Inherits System.Windows.Forms.Form #Region " Código generado por el Diseñador " Public Sub New() MyBase.New() 'Se inicializan los componentes creados con el 'Diseñador'. InitializeComponent() End Sub ''Dispose' se sobrecarga para eliminar los componentes en la lista. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Contenedor para los componentes. Private components As System.ComponentModel.IContainer 'Método que inicializa el formulario. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() 'Form1 Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.ClientSize = New System.Drawing.Size(292, 273) Me.Name = "Form1" Me.Text = "Form1" End Sub #End Region Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Se crea un canal para comunicarnos con el servicio a publicar. Dim channel As TcpServerChannel = New TcpServerChannel(9932) ChannelServices.RegisterChannel(channel) 'Registramos 'HelloWorld' como un tipo conocido en el servicio: así se hace accesible al cliente. 'El modo de acceso a este objeto se definie como 'SingleCall' - Todos los mensajes entrantes 'son atendidos por una nueva instancia del objeto. Esto no sale a cuenta, por cuestión 'de rendimiento, cuando va a haber muchos clientes accediendo al objeto. RemotingConfiguration.RegisterWellKnownServiceType(GetType(HelloWorld), "HelloWorld", WellKnownObjectMode.SingleCall) End Sub End Class El cliente: Imports ServiciosRemotos Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels.Tcp Imports System.Runtime.Remoting.Channels Imports System.Runtime.Serialization.Formatters.Binary Public Class Form1 : Inherits System.Windows.Forms.Form #Region " Código generado por el Diseñador " Public Sub New() MyBase.New() 'Se inicializan los componentes creados con el ‘Diseñador'. InitializeComponent() End Sub ''Dispose' se sobrecarga para eliminar los componentes en la lista. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Contenedor para los componentes. Private components As System.ComponentModel.IContainer 'Método que inicializa el formulario. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() 'Form1 Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.ClientSize = New System.Drawing.Size(292, 273) Me.Name = "Form1" Me.Text = "Form1" End Sub #End Region 'Al ejecutarse la aplicación en el equipo del cliente, ... Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ChannelServices.RegisterChannel(New TcpClientChannel) '...'Activator.GetObject()' crea un proxy que administra el objeto 'HelloWorld' en el 'servidor, de tal forma que 'objRemoto' será un puntero a ese objeto 'HelloWorld' 'en el servidor. Dim objRemoto As HelloWorld = CType(Activator.GetObject(GetType(HelloWorld), "tcp://192.168.0.64:9932/HelloWorld"), HelloWorld) 'Ya se puede utilizar 'objRemoto' como si estuviera en RAM, aunque realmente no sea así. 'El objeto remoto determina el texto de título del formulario. Me.Text = objRemoto.Display End Sub End Class
¿Comentarios, sugerencias?: llopsite.at.yahoo.es | © 2005-07 Albert Lobo
Última actualización: 18-Feb-2007