martes, 20 de septiembre de 2016

Conectando una app de Xamarin con SQL Server

¡Hola! En la semana me preguntaron acerca de cómo conectar una base de datos SQLServer en una red local con una app móvil en Xamarin, lo cual es posible a través de la clase SQLConnection que se encuentra en el espacio de nombres System.Data pero nunca lo había hecho, así que me dí a la tarea de intentarlo ayer porque es interesante. A continuación, les comparto la experiencia por si les sirve en alguna ocasión.

Parte 1. Creación de la base de datos, tablas e información
Inicia SQL Server Management Studio. En mi caso, tengo instalado SQL Server 2012, pero no debería haber diferencia si utilizas otra versión.

Para este ejemplo, he creado la base de datos Empresa con la tbla Empleados. Le he agregado 3 registros. Fácil, ¿no?

CREATE DATABASE Empresa
GO

USE Empresa
GO

CREATE TABLE Empleados(
ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
Nombre VARCHAR(100) NOT NULL,
Salario DECIMAL(12, 4) NOT NULL
)

INSERT INTO Empleados VALUES ('Ana Mendez', 7812.45)
INSERT INTO Empleados VALUES ('Juan Pérez', 10000.51)
INSERT INTO Empleados VALUES ('Raúl Rico', 4703.12)


Parte 2. Inicio de sesión y Configuración del servidor
A fin de que otros dispositivos se puedan conectar a nuestra base de datos a través de aplicaciones (en este caso, una app móvil), tenemos que configurar ciertos permisos en el servidor.

a) Inicio de sesión
El primer paso es que SQL Server acepte la autenticación mixta (la que nos interesa en realidad es la autenticación de SQL Server, no tanto la de Windows).


Esta propiedad se establece cuando instalas SQL Server, pero si elegiste la autenticación de Windows, simplemente realiza lo siguiente:


En SQL Server Management Studio inicia sesión. Da clic derecho en el nombre del servidor y selecciona Propiedades.


En la página Seguridad, modifica la propiedad Autenticación de servidor y establece su valor en Autenticación de SQL Server y Windows. Da clic en OK.


Es probable que te pida un reinicio del servicio de SQL Server. Acepta y espera. Una vez reiniciado, inicia sesión nuevamente. Ahora expande el panel del servidor y da clic derecho en Inicios de sesión dentro de Seguridad. Elige la opción Nuevo inicio de sesión:


En la página General, escribe un inicio de sesión, selecciona Autenticación de SQL Server, coloca y confirma una contraseña. Desmarca los 3 checkboxes de opciones de contraseña. Selecciona la base de datos Empresa y accede a la página Roles de servidor:


En Roles de Servidor, asigna los privilegios que este usuario tendrá. Ahora accede a la página Mapeo de Usuario:


En Mapeo de Usuario, marca la base de datos Empresa, escribe el login que acabas de crear y asigna el esquema dbo. Accede a la página Status:


Finalmente, en Status verifica que el permiso de conexión al motor de base de datos está concedido (Grant) y que el inicio de sesión está activado (Enabled). Da clic en OK:


Ahora intenta realizar una conexión con el inicio de sesión que has creado. Si es correcto, procederemos a configurar el servidor.


b) Configuración de servidor:
Inicia el Administrador de configuración de SQL Server:


En cada una de las siguientes categorías habilita el servicio TCP/IP (da clic derecho y selecciona Habilitar): Protocolos de cliente (dentro de Configuración de SQL Native Client 11.0 32 bits), Protocolos de y Protocolos de cliente (dentro de Configuración de SQL Native Client 11.0):


Inicia el servicio SQL Server Browser. Lo puedes hacer en la pestaña Servicios de SQL Server o desde Panel de Control -> Servicios:


Reinicia el servicio de SQL Server a fin de autorizar los cambios recién realizados:


Para que el servidor sea visible por otros dispositivos, es necesario dar de alta 4 reglas en el firewall de Windows (si utilizas otro firewall, los pasos pueden variar). Accede a la Configuración avanzada del Firewall:


Selecciona Nueva regla en la categoría Reglas de entrada:


La primer regla servirá para autorizar un Puerto. Da clic en Siguiente:


El tipo de puerto es TCP, específicamente el 1433. Da clic en Siguiente:


Permite la conexión. Da clic en Siguiente:


Selecciona los tres tipos de redes. Da clic en Siguiente:


Asigna un nombre a la primer regla, por ejemplo SQL - TCP 1433. Da clic en Finalizar:


Agrega otra regla. La segunda regla servirá para autorizar otro Puerto. Da clic en Siguiente:


Ahora selecciona UDP en tipo y especifica el puerto 1434. Da clic en Siguiente:


Permite la conexión. Da clic en Siguiente:


Selecciona los tres tipos de redes. Da clic en Siguiente:


El nombre de esta regla es SQL - UDP 1434. Da clic en Finalizar:


Agrega una tercer regla, la cual ahora será de tipo Programa. Da clic en Siguiente:


Selecciona ruta de acceso del programa. Localiza la aplicación sqlservr.exe que está localizada en C:/Program Files/ Microsoft SQL Server//MSSQL/Binn. Da clic en Abrir:


La ruta de acceso debería ser similar a la mostrada en la figura. Da clic en Siguiente:


Permite la conexión. Da clic en Siguiente:


Selecciona los tres tipos de redes. Da clic en Siguiente:


El nombre de la tercer regla es SQL - sqlservr.exe. Da clic en Finalizar:


Por último, agrega una nueva regla de tipo Programa. Da clic en Siguiente:


En ruta de acceso del programa, localiza sqlbrowser.exe, el cual se encuentra en C:/Program Files(x86)/Microsoft SQL Server/90/Shared:


La ruta de acceso será similar a la mostrada en la figura. Da clic en Siguiente:


Permite la conexión. Da clic en Siguiente:


Selecciona los tres tipos de redes. Da clic en Siguiente:


Por último, escribe un nombre para esta regla de entrada, por ejemplo, SQL - sqlbrowser.exe. Da clic en Finalizar:


Al final, tendrás cuatro reglas de entrada en tu Firewall, las cuales permitirán conexiones entrantes a tu servidor SQL Server:


Parte 3. Código de Xamarin
¡Ahora vamos con el código!

Abre Visual Studio 2015. Crea una nueva aplicación vacía de tipo Xamarin.Forms Shared, localizado en la categoría Cross-Platform. El nombre de la app es XamarinSQL:


Descarga estas 3 imágenes, las cuales serán utilizadas en el Toolbar de la app para agregar, modificar o eliminar registros en nuestra tabla.

Para agregarlas, recuerda que en Xamarin no se recomienda agregar las imágenes al SharedProject. Es mejor incluirlas en cada proyecto específico. Da clic derecho en la carpeta especificada a continuación (dependiendo el proyecto) y elige Agregar > Elemento existente, seleccionando las 3 imágenes:


  • Android: Resources > Drawable
  • iOS: Resources
  • UWP, Windows, WinPhone: Carpeta raíz del proyecto



En el SharedProject (XamarinSQL) agrega 3 carpetas: Clases, Datos y Paginas dando clic derecho en el nombre del proyecto y seleccionando Agregar > Nueva carpeta:


En la carpeta Clases, agrega una clase llamada Empleados:


El código de la clase se presenta a continuación (básicamente es el modelado de la tabla Empleados):

namespace XamarinSQL.Clases
{
    public class Empleados
    {
        public int ID { get; set; }
        public string Nombre { get; set; }
        public decimal Salario { get; set; }
    }
}

Para conectar la app con SQLServer, se hará uso de clases que están en System.Data. Es necesario agregar esta referencia a cada proyecto de plataforma específica. A continuación se muestra como realizarlo en el proyecto de Android (repite este paso para los otros proyectos que desees incluir en tus pruebas). Da clic derecho en References dentro del proyecto de plataforma específica. Selecciona Agregar Referencia:


En la categoría Assemblies, elige Framework y selecciona System.Data de la lista de ensamblados que aparece. Da clic en OK para que esta referencia sea agregada al proyecto de Android.


Ahora ya podemos crear código que incluya la conexión a la base de datos, lea e inserte información en tablas, etc. Para ello, crea otra clase en la misma carpeta. Su nombre es BaseDatos:


El código de la clase se presenta a continuación:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;

namespace XamarinSQL.Clases
{
    public static class BaseDatos
    {
        static string cadenaConexion = @"data source=10.82.96.2;initial catalog=Empresa;user id=sa;password=tupassword;Connect Timeout=60";

        public static List<empleados> ObtenerEmpleados()
        {
            List<empleados> listaEmpleados = new List<empleados>();
            string sql = "SELECT * FROM Empleados";

            using (SqlConnection con = new SqlConnection(cadenaConexion))
            {
                con.Open();

                using (SqlCommand comando = new SqlCommand(sql, con))
                {
                    using (SqlDataReader reader = comando.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            Empleados empleado = new Empleados()
                            {
                                ID = reader.GetInt32(0),
                                Nombre = reader.GetString(1),
                                Salario = reader.GetDecimal(2)
                            };

                            listaEmpleados.Add(empleado);
                        }
                    }
                }

                con.Close();

                return listaEmpleados;
            }
        }

        public static void AgregarEmpleado(Empleados empleado)
        {
            string sql = "INSERT INTO Empleados (Nombre,Salario) VALUES(@nombre, @salario)";

            using (SqlConnection con = new SqlConnection(cadenaConexion))
            {
                con.Open();

                using (SqlCommand comando = new SqlCommand(sql, con))
                {
                    comando.Parameters.Add("@nombre", SqlDbType.VarChar, 100).Value = empleado.Nombre;
                    comando.Parameters.Add("@salario", SqlDbType.Decimal).Value = empleado.Salario;
                    comando.CommandType = CommandType.Text;
                    comando.ExecuteNonQuery();
                }

                con.Close();
            }
        }

        public static void ModificarEmpleado(Empleados empleado)
        {
            string sql = "UPDATE Empleados set Nombre = @nombre, Salario = @salario WHERE ID = @id";

            try
            {
                using (SqlConnection con = new SqlConnection(cadenaConexion))
                {
                    con.Open();

                    using (SqlCommand comando = new SqlCommand(sql, con))
                    {
                        comando.Parameters.Add("@nombre", SqlDbType.VarChar, 100).Value = empleado.Nombre;
                        comando.Parameters.Add("@salario", SqlDbType.Decimal).Value = empleado.Salario;
                        comando.Parameters.Add("@id", SqlDbType.Int).Value = empleado.ID;
                        comando.CommandType = CommandType.Text;
                        comando.ExecuteNonQuery();
                    }

                    con.Close();
                }
            }
            catch(Exception ex)
            {

            }
        }

        public static void EliminarEmpleado(Empleados empleado)
        {
            string sql = "DELETE FROM Empleados WHERE ID = @id";

            using (SqlConnection con = new SqlConnection(cadenaConexion))
            {
                con.Open();

                using (SqlCommand comando = new SqlCommand(sql, con))
                {
                    comando.Parameters.Add("@id", SqlDbType.Int).Value = empleado.ID;
                    comando.CommandType = CommandType.Text;
                    comando.ExecuteNonQuery();
                }

                con.Close();
            }
        }
    }
}

En el código anterior se establece la cadena de conexión, que contiene:

  • El data source: Representa el servidor (y su instancia, si es requerida). En este caso, se ha usado la IP del servidor (equipo). Si se tiene una instancia, se puede agregar con una diagonal invertida, por ejemplo, IP\SQLEXPRESS,
  • El initial catalog: La base de datos de inicio 
  • El user id: El login de acceso a la base de datos
  • El password: Su contraseña de acceso
  • Connect Timeout: Es opcional, pero es deseable manejar un límite de tiempo de conexión en segundos.

En la clase tienen 4 métodos estáticos que representan las operaciones CRUD (Create, Read, Update and Delete) sobre la tabla Empleados. En cada caso se hace uso de:

  • La clase SqlConnection para conectarse a la base de datos. 
  • Una vez conectado:
    • Se abre una conexión (con.Open)
    • Se ejecuta una instrucción SQL mediante SqlCommand.
    • El método ObtenerEmpleados utiliza un SqlDataReader para leer cada registro obtenido en la consulta y agregarlo a la lista que se retorna al final del método. Para leer el valor de cada campo se hace uso de los métodos Get: GetInt32(index), GetString(index), GetDecimal(index), etc., donde index es la posición (comenzando desde cero) del campo a leer.
    • Los otros 3 métodos utilizan instrucciones parametrizadas, lo que quiere decir que los valores se envían como parámetros del comando SQL.
    • Se cierra la conexión (con.Close). 

Por cierto, como los métodos son estáticos, no requieres crear un objeto de la clase BaseDatos, sino que los métodos serán llamados directamente (BaseDatos.método).

Ahora vamos a crear una página para mostrar la información de los empleados de nuestra base de datos. En la carpeta Paginas da clic derecho y selecciona Agregar > Nuevo elemento. Localiza Forms Xaml Page dentro de la categoría Cross Platform para agregar una página de contenido (ContentPage) que incluye un archivo para el diseño (XAML) y otro para el código funcional (C#). El nombre de la página es PaginaListaEmpleados:


El código XAML de esta página es:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinSQL.Paginas.PaginaListaEmpleados">
   <ContentPage.Content>
    <StackLayout BackgroundColor="White">
      <Label Text="Empleados" FontSize="40" HorizontalOptions="Center"/>

      <ListView x:Name="lsvEmpleados" ItemSelected="lsvEmpleados_ItemSelected">
        <ListView.ItemTemplate>
          <DataTemplate>
            <ViewCell>
              <StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
                <StackLayout Orientation="Horizontal">
                  <Label Text="{Binding Nombre}" TextColor="Blue" FontSize="16"/>
                  <Label Text="{Binding Salario}" TextColor="Green" FontSize="12" HorizontalOptions="EndAndExpand"/>
                </StackLayout>
              </StackLayout>
            </ViewCell>
          </DataTemplate>
        </ListView.ItemTemplate>
      </ListView>
    </StackLayout>
  </ContentPage.Content>

  <ContentPage.ToolbarItems>
    <ToolbarItem x:Name="btnNuevo" Text="Nuevo" Priority="0" Clicked="btnNuevo_Click" Order="Primary" Icon="agregar.png"/>
  </ContentPage.ToolbarItems>
</ContentPage>

Explicación: En esta página, el contenedor principal es un StackLayout que muestra 2 controles apilados (uno debajo del otro):

  • Label. Simplemente muestra el texto Empleados centrado en la parte superior a manera de título.
  • ListView. Mostrará cada registro de la tabla y se podrá interactuar con cada elemento mediante el evento ItemSelected. Esta lista tiene un ItemTemplate, que define la presentación, es decir la información que se mostrará por cada registro. Para este caso, se muestra el nombre y el salario del empleado en un StackLayout (uno debajo del otro), pero se puede personalizar esta parte para mostrar más información si se desea.


Adicionalmente, esta página incluye una barra de herramientas (ToolbarItems) con un elemento (ToolbarItem) y que responde al evento Clicked.

Para la funcionalidad de esta página (carga de información y manejo de los eventos ItemSelected y Clicked), se agrega código de C#, el cual se muestra a continuación:

using System;
using Xamarin.Forms;
using XamarinSQL.Clases;

namespace XamarinSQL.Paginas
{
 public partial class PaginaListaEmpleados : ContentPage
 {
  public PaginaListaEmpleados ()
  {
   InitializeComponent ();
  }

  protected override void OnAppearing()
  {
   base.OnAppearing();
   lsvEmpleados.ItemsSource = BaseDatos.ObtenerEmpleados();
  }

  private void lsvEmpleados_ItemSelected(object sender, SelectedItemChangedEventArgs e)
  {
   if (e.SelectedItem != null)
    NavegarEmpleado(e.SelectedItem as Empleados);
  }

  void btnNuevo_Click(object sender, EventArgs a)
  {
   NavegarEmpleado(new Empleados());
  }

  void NavegarEmpleado(Empleados empleado)
  {
   PaginaEmpleado pagina = new PaginaEmpleado();
   pagina.Empleado = empleado;
   Navigation.PushAsync(pagina);
  }
 }
}

Explicación:

  • Cuando se carga la página (método OnAppearing), se asigna la propiedad ItemsSource del Listview lsvEmpleados para cargar los datos obtenidos al llamar al método ObtenerEmpleados.
  • Cuando se selecciona un empleado (ItemSelected), se pasa de parámetro al método NavegarEmpleado el elemento seleccionado.
  • Cuando se da clic en el botón de la barra de herramientas, se pasa de parámetro al método NavegarEmpleado un objeto Empleado vacío.
  • El método NavegarEmpleado navega hacia una instancia de la página PaginaEmpleado (la crearás en el siguiente paso), enviándole además de parámetro un objeto Empleados.

Ahora, crea otro Forms Xaml Page en la misma carpeta Paginas. El nombre de este nuevo elemento es PaginaEmpleado:


El código XAML de esta página es el siguiente:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinSQL.Paginas.PaginaEmpleado">
  <ContentPage.Content>
    <StackLayout Spacing="20" Padding="20">
      <Entry x:Name="txtNombre" Text="{Binding Nombre, Mode=TwoWay}" Placeholder="Nombre" />
      <Entry x:Name="txtSalario" Text="{Binding Salario, Mode=TwoWay}" Placeholder="Salario" Keyboard="Numeric" />
    </StackLayout>
  </ContentPage.Content>

  <ContentPage.ToolbarItems>
    <ToolbarItem x:Name="btnGuardar" Text="Guardar" Priority="0" Clicked="btnGuardar_Click" Order="Primary" Icon="guardar.png"/>
    <ToolbarItem x:Name="btnEliminar" Text="Eliminar" Priority="1" Clicked="btnEliminar_Click" Order="Primary" Icon="eliminar.png"/>
  </ContentPage.ToolbarItems>

</ContentPage>

El código anterior contiene un StackLayout como contenedor principal. Dentro de este control tenemos 2 controles Entry, que permitirán al usuario ingresar el nombre y salario del empleado. Finalmente, se incluye una Toolbar con 2 botones: uno para Guardar y otro para Eliminar

Observa también que en los 2 controles Entry se hace uso del Binding. Esto significa que un objeto de la clase Empleados es enlazado a los controles de la página. Una modificación en la información de las cajas de texto automáticamente modificará el valor de sus propiedades (es decir, no necesitamos escribir código de C# parecido a txtNombre.Text = Empleado.Nombre o viceversa). 

El código C# que implementa la funcionalidad de esta página es el siguiente:

using System;

using Xamarin.Forms;
using XamarinSQL.Clases;

namespace XamarinSQL.Paginas
{
 public partial class PaginaEmpleado : ContentPage
 {
  public Empleados Empleado;

  public PaginaEmpleado ()
  {
   InitializeComponent ();
  }

  protected override void OnAppearing()
  {
   base.OnAppearing();

   BindingContext = this.Empleado;
  }

  void btnGuardar_Click(object sender, EventArgs a)
  {
   if (Empleado.ID == 0)
    BaseDatos.AgregarEmpleado(Empleado);
   else
    BaseDatos.ModificarEmpleado(Empleado);

   Navigation.PopAsync();
  }

  void btnEliminar_Click(object sender, EventArgs a)
  {
   if (Empleado.ID != 0)
   {
    BaseDatos.EliminarEmpleado(Empleado);
    Navigation.PopAsync();
   }
  }
 }
}


Explicación del código anterior:

  • A nivel de clase existe un objeto Empleado de la clase Empleados.
  • Este objeto se asigna al BindingContext de la página en el método OnAppearing. Esto hace posible utilizar el Binding en el XAML previamente mostrado.
  • Los eventos Click de los botones (btnGuardar_Click y btnEliminar_Click) llaman a las funciones respectivas para realizar operaciones sobre la tabla Empleados: AgregarEmpleado, ModificarEmpleado o EliminarEmpleado. Existen algunas condiciones, por ejemplo si el ID es diferente de cero significa que se seleccionó un empleado en la página anterior y solo las operaciones Modificar y Eliminar estarán disponibles. AgregarEmpleado solo está disponible si se presionó el botón Nuevo en PaginaListaEmpleados.


Ahora abre el archivo App.cs y modifica el constructor de la clase. MainPage será asignado a una instancia de NavigationPage, mandando llamar una nueva instancia de PaginaListaEmpleados:

using Xamarin.Forms;
using XamarinSQL.Paginas;

namespace XamarinSQL
{
    public class App : Application
    {
        public App ()
        {
            MainPage = new NavigationPage(new PaginaListaEmpleados());
        }
//...
    }
//...
}

Para finalizar, asigna el permiso Internet al AndroidManifest. Para ello, da clic derecho en el nombre del proyecto y selecciona Propiedades:


Selecciona Android Manifest y marca el permiso INTERNET. Guarda los cambios.


¡Listo! Compila y ejecuta, verificando que la aplicación se conecta a tu base de datos, mostrando los datos de la tabla Empleados y haciendo posible las operaciones de inserción, modificación y borrado. A continuación te comparto algunas imágenes de la aplicación funcionando en un dispositivo real.

Inicio:


Agregando un nuevo empleado:


Resultado:


Vista de la base de datos:



El código fuente lo puedes descargar desde mi repo en GitHub.

Espero que esta aportación te haya sido útil. Si así ha sido, dale like o compártela con tus amigos. Si llegas a realizar esta práctica, compárteme tus resultados, me agradará saber que alguien realizó la práctica :-) Si tienes algún problema, coméntalo y a la brevedad te responderé.

Gracias por tu tiempo y hasta la próxima.

40 comentarios:

  1. I was researching content for our social media strategy and came across your fantastic blog. I just wanted to reach out and make an introduction. My name is Elizabeth Britton, and I’m a Marketing Coordinator with Syncfusion. Your blog posts reflect your excellent knowledge of coding. Please let me know if you have any great posts you would possibly want mentioned in our social media content. Keep up the great work on your blog!

    ResponderEliminar
  2. Hola, como solventas los errores que hay en la clase BaseDatos.cs, por ejemplo:
    - System.Data not available (Windows, Windows Phone)
    - System.Data.SqlClient not available (UWP, Windows, Windows Phone)
    - System.Data.sqlConnection not available (UWP, Windows, Windows Phone)
    - System.Data.CommandType not available (Windows, Windows Phone)
    - System.Data.SqlDbType not available (UWP, Windows, Windows Phone)

    ResponderEliminar
    Respuestas
    1. Tienes que agregar la librería System.Data en cada proyecto específico (Windows, WindowsPhone, Android, iOS, UWP) donde vayas a implementar la aplicación.

      Eliminar
  3. Hola y primero que todo, gracias por semejante paso a paso. Ahora te comento mi duda resulta que seguí al pie de la letra y vaya que tuve errores ... hasta ir solucionándolos casi todos. No sé cuantas veces he hecho este proyecto sin embargo no puedo realizar la conexion a la base de datos. Ejecuté todo lo que ud hizo desde las reglas en el Firewall hasta la conexión a la BD no obstante cuando ejecuto el xamarin me dice q no encuentra la base de datos y la he probado con proyectos web y entra sin problemas. Mi gran drama es q no logra hacer la conexión y se cae en con.Open()... imagino que el tema debe ser la BD y los privilegios pero he creado hasta más usuarios con el fin de poder conectarme pero aún hasta la fecha no hay caso. Ojalá y me puedas brindar una mano (por cierto el Sql agent debe estár iniciado o ese no es necesario?)

    ResponderEliminar
    Respuestas
    1. Hola que tal. Claro que te ayudo, específicamente qué mensaje de error te marca? Si gustas envíame un correo a luis.beltran arroba itcelaya punto edu punto mx y por ahí me compartes imágenes de qué mensaje de error te aparece para darle seguimiento. SQL Agent no es necesario para este proyecto. Por cierto, la prueba la estás haciendo con un dispositivo, cierto? El dispositivo debe ser capaz de comunicarse con el servidor, por lo que supongo que están en la misma red. Como recomiendo al inicio, por cuestiones de seguridad lo ideal sería crear un servicio web y evitar la conexión directa a la base de datos, pero eso ya corresponde a cada desarrollador decidirlo :) Envíame un correo y lo checamos, sale? Buen día

      Eliminar
    2. Ante todo, muy bueno el trabajo desarrollado; tengo el mismo error en el con.Open(), lograron encontrar alguna solución?

      Eliminar
    3. Estimado Luis, muy buena explicación muy claro. El único blog que encontré que explica esto de manera sencilla. Serías tan amable de agregar el ejemplo con un web service, porque claro en red local funciona de maravilla, pero la idea es que el servicio sea consumido desde el exterior. Muchas gracias nuevamente!

      Eliminar
  4. Hola, he seguido su paso a paso, agregó el System.Data en el proyecto androide, pero cuando creo un BaseDatos clase y voy a declarar que no reconoce la System.Data, lo que podría ser? Estoy utilizando la versión más reciente de Xamarin.

    ResponderEliminar
    Respuestas
    1. ¿Cual es el mensaje exacto de error? Te sugiero agregar la versión mostrada (2.0.5.0) al proyecto Android.

      Eliminar

    2. Error CS0234 El tipo o nombre de espacio de nombres 'Datos' no existe en el espacio de nombres 'Sistema' (le falta una referencia de ensamblado?) Hice que ni paso a paso

      Eliminar
    3. Luiz, gracias! Tuve que modificar mi proyecto, pero ahora tiene la conexión correcta.

      Eliminar
    4. De acuerdo :) ¡Felicidades por completar el tutorial!

      Eliminar
    5. CronoData como hiciste para que reconociera el System.Data?

      Eliminar
    6. CronoData ¿Cómo lo resolviste? También tengo ese problema, ya agregue las librerías en el using y en las referencias pero no me llega a reconocer. Ya me reconoció la "Data" pero aún no me reconoce el "SqlClient" y solo eso me faltaría, ayúdenme.

      Eliminar
  5. Luiz, soy incapaz de cargar el ListView la aplicación se detiene.

    ResponderEliminar
    Respuestas
    1. ¿Te devuelve alguna excepción?

      Eliminar
    2. Si, está: [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: ExecuteReader requires an open connection to continue. This connection is closed.

      Eliminar
    3. Revisa los parámetros de cadenaConexion y también si la conexión realmente se pudo realizar. Sugiero que depures paso a paso en el método ObtenerEmpleados para ver si el objeto con tiene algún valor (State = Open o algo así). Mándame un correo a luis.beltran arroba itcelaya punto edu punto mx con imágenes de la línea donde te da error, detalles, etc para darle seguimiento.

      Eliminar
    4. El error pareciera que la conexión se ha cerrado o no está abierta realmente, por eso sugiero que revises paso a paso.

      Eliminar
    5. Luis trabajó era un parámetro que estaba equivocado. Fix y funcionó.

      Eliminar
    6. Excelente, que bien que ya funcione :) ¡Saludos!

      Eliminar
    7. Luiz, que podría explicar el código de (ObtenerEmpleados), mi no volver estos datos se muestran como propiedades, más la cantidad de líneas es correcta.

      Eliminar
    8. Estoy más dudas sobre esta línea (List ObtenerEmpleados) en pequeñas empreados cuando declaro este error dar y cuando pongo en mayúsculas más aceptada no muestra nada.

      Eliminar
    9. Luiz, gracias. El problema era que en mi plantilla, felicitaciones por el tutorial

      Eliminar
  6. Luis, es que puse dos ItemsSource una vista de lista?

    ResponderEliminar
  7. Muy master, felicitaciones

    ResponderEliminar
  8. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  9. hola me da este error y no se como solventarlo alguna idea. Error CS7069 Reference to type 'Component' claims it is defined in 'System', but it could not be found. App.UWP, App.Windows

    ResponderEliminar
  10. Hay alguna manera de obtener el ID del Empleado al crear un nuevo registro?

    ResponderEliminar
  11. Tengo el mismo problema con un Error CS7069, a que se debe esto?

    ResponderEliminar
  12. Excelente me ha funcionado para xamarin forms en android y ios :), Gracias por compartir tus conocimientos

    ResponderEliminar
  13. Hola Luis, tengo este error

    CS0051 Inconsistent accessibility: parameter type 'Empleados' is less accessible than method 'BaseDatos.AgregarEmpleado(Empleados)' este error me aparece para los metodos de modificar, eliminar y obtenerEmpleados.

    tengo visual studio 2017

    ResponderEliminar
  14. Para todos aquellos que le salen el error "CS0031" u otro CS, solo descarguen los emuladores que le falten, eso lo pueden conseguir en "Herramientas/Android/AndroidSDKManager..." y ahí pueden descargar los emuladores que les faltan.

    ResponderEliminar
  15. Hello can you help me with this im currently trying this one in Xamarin Android but i couldn't get the same result as you

    ResponderEliminar
  16. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  17. Hi! Sorry for bothering You but could You maybe Please assist me with a problem I have in the code...In the PaginaListaEmpleados.xaml.cs file the code public the Initilaze Component and the lsvEmpleados is glowing red and I can't seem to resolve it, I would really appreciate it if You could help me fix this because I don't know if it will work with that red "error" showing in the debugger. Thank You.

    ResponderEliminar
  18. Como podria hacer lo mismo pero conectando a Azure SQL? como seria la parte del DataSource?

    ResponderEliminar
  19. Otra pregunta, en el dataSource si pongo una db sqlite y la guardo en donde corresponde en sus respectivos proyectos, me funciona correctamente?

    ResponderEliminar