martes, 20 de septiembre de 2016

Conectando una app de Xamarin con SQL Server

ACTUALIZACIÓN: Esta publicación NO es la forma recomendada de comunicar una app móvil con una base de datos. El esquema ideal es crear un Web Api que se conecta a tu base de datos, exponiendo métodos que serán accesibles para tu aplicación móvil. Dicho lo anterior, esta publicación es un mero ejercicio ilustrativo y NO se recomienda para producción sobre todo por esquemas de seguridad.

Aquí tienes un ejemplo de cómo hacerlo con SQL Server (solo quedaría publicarlo y accederlo desde Xamarin) y aquí va otro ejemplo con MySQL

---------------------------------------
De verdad, de verdad...

---------------------------------------

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

103 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
    2. hola puedo agregar mas campos de consultas? por ejemplo el correo

      Eliminar
    3. Hola amigo puedo agregar mas campos de consutas por ejemplo el correo?

      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
  20. Excelente trabajo amigo me ha servido mucho.

    Tengo una duda, si mi base de datos también cuenta con imágenes, ¿Cómo hago para mostrar la imagen?
    He estado intentando con variables tipo image y arrglo de bits ( byte[] ) y al momento de usar la clase Read, no sé que función implementar para el campo de la imagen.

    public string Correo { get; set; }
    public string Telefono { get; set; }
    public Image Foto { get; set; }

    Correo = reader.GetString(3),
    Telefono = reader.GetString(4),
    //Foto(5)...

    Saludos.

    ResponderEliminar
  21. Como podria hacer lo mismo pero en Xamarin forms PCL?

    ResponderEliminar
  22. Donde ingreso el data a mi database si no quiero usar el binding?

    ResponderEliminar
  23. Gracias por el aporte,estaba preguntándome si es posible hacerlo y como y vos nos das todos los pasos a seguir. Gracias

    ResponderEliminar
  24. Hola, Luis.
    Muchas gracias por tu aporte.
    Solo tengo una pequeña duda.
    Es indispensable seleccionar las tres casillas al dar de alta una regla en el Firewall?
    Mi base de datos estaría almacenada en un dominio.

    ResponderEliminar
  25. a mi no me funciona nada,todo son errores, lo he hecho 2 veces y nada.
    Ayuda

    ResponderEliminar
  26. System.NullReferenceException: Object reference not set to an instance of an object

    help

    pantalla en blanco

    ResponderEliminar
  27. Hola luis.

    Gracias por este ejemplo paso por paso esta excelente.

    Pero en mi caso como en comentarios anteriores mi erro es que no abre la conexión, ya verifique la conexión de red mediante una conexión con PHP y fue exitosa, de igual forma pase la consulta de Empleados a una aplicación de consola y de igual forma fue exitosa.Pero me señala que el browse de Sql debe estar corriendo, lo cual ya esta, no se si puedas ayudarme con este problema.

    Gracias.

    ResponderEliminar
  28. Saludos por favor me puedes ayudar con este error?

    Error CS0012 El tipo 'Component' está definido en un ensamblado al que no se hace referencia. Debe agregar una referencia al ensamblado 'System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'.

    ResponderEliminar
  29. if we have to install create APK file in External Device Than its DIsplay Unfortunately Stopped ,,, Please give ma Solution as Possible fast

    ResponderEliminar
  30. hola, eres un maestro en esto , busque por todos lados, vídeos así como cursos en linea como udemy o platzi y tu método es el mas facil y efectivo, solo tengo un error , no puedo mostrar los contactos en la pagina principal, me marca error en el "Isv" y no lo tiene ios , estoy elaborando algo parecido para mi tesis de la maestría, crees que me podrías ayudar, con mucho gusto te apoyaría con tus honorarios por el conocimiento, te dejo mi correo y whats
    angel__ak@hotmail.com y 22 23 65 22 67

    soy de Puebla Mex.

    ResponderEliminar
  31. Hola, no se porque me marca el siguiente error (me lo marca en BaseDatos.cs)
    Exepcion no controlada
    System.Data.SqlClient.SqlException: Snix_Connect (provider: SNI_PN7, error: 40 - SNI_ERROR_40)
    Snix_Connect (provider: SNI_PN7, error: 40 - SNI_ERROR_40)

    ResponderEliminar
  32. Cuando género el apk para instalarlo en otro teléfono no funciona no logra iniciar la aplicación y tira un msj de que se detuvo la aplicación pero esto funciona bien en modo debug en todos los dispositivos que pruebo. Cual seria el problema?

    ResponderEliminar
  33. Buenas tardes, me podrían ayudar con el siguiente error, (System.Exception: Cannot connect to SQL Server Browser. Ensure SQL Server Browser has been started.)
    Parámetros correctos,
    SQL Server Browser en ejecución,
    Sql Server Configuracion Manager habilitados.
    Cual podría ser el problema en este caso?

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

    ResponderEliminar
  35. Solo comento para felicitarte por el buen aporte, esta todo muy bien explicado y funciona de maravilla. Lo utilice con un servidor que tengo montado en mi trabajo.

    Gracias!

    ResponderEliminar
  36. Hola Luis por favor necesito tu ayuda. No logro conectarme con la base datos.Tengo el 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 de todo.

    ResponderEliminar
  37. Hola Luis, estoy buscando una forma de poder conectar, una aplicación móvil desarrollada desde (XAMARIN) con un servidor SQL
    Me gustaría poderme conectar desde cualquier lado, no solo localmente, probé lo que hiciste en tu blog, pero me da un error al momento de querer hacer la conexión.

    No se si puedas ayudarme un poco aserca de este error lo adjunto.

    Unhandled Exception:

    System.Data.SqlClient.SqlException: Snix_Connect (provider: SNI_PN7, error: 35 - SNI_ERROR_35)
    Snix_Connect (provider: SNI_PN7, error: 35 - SNI_ERROR_35)

    También, puedes darme alguna idea de como hacer la conexión Xamarin con sql desde cualquier red (lugar).
    Saludos desde mexico

    ResponderEliminar
  38. que tal, pude correr la aplicacion en el emulado, me deja crear datos en la BD, pero al momento de pasarlo a la tablet no, conecta y se cierra, ya revise el firewall del sevidor y esta igual como lo mencionas en tu explicacion. alguna idea porque no conecta?

    ResponderEliminar
  39. Muchas gracias por esta gran aportación para gente como yo que estamos comenzando.
    Está muy bien explicado.
    Un saludo

    ResponderEliminar
  40. Hola buenos días, pero la clase de conexión BadeDatos no me deja usar System.Data, como lo puedo hacer?

    ResponderEliminar
    Respuestas
    1. Hola, al inicio de la publicación (antes del meme) tienes la forma apropiada de resolverlo

      Eliminar
    2. Hola Luis, disculpa la molestia, entiendo lo de Web API, pero igual me gustaria ver la forma de verlo aunque sea para el proyecto Android, saludos desde Chile

      Eliminar
    3. La única forma de hacerlo funcionar entonces es que uses una versión vieja de Xamarin, creo que en ese entonces sería la 2.3 o similar

      Eliminar
  41. hola cuando corro la app en el emulador hace los cambios a la BD pero en el telefono conectado a la red local donde el servidor esta conectado no altera mi bd me ayudas

    ResponderEliminar
    Respuestas
    1. Mejor házlo por web api como lo recomiendo en el párrafo inicial de esta publicación. No es complicado, de verdad!

      Eliminar



  42. System.Data.SqlClient.SqlException: 'A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: TCP Provider, error: 35 - An internal exception was caught) que puede ser el problema

    ResponderEliminar
  43. ing buenas tardes, en mode debug todo funciona sin problemas, y en mode release no muestra los datos sabe que puede ser

    ResponderEliminar
  44. ing buenas tardes, en mode debug todo funciona sin problemas, y en mode release no muestra los datos sabe que puede ser....

    tengo el mismo problema .. al momento de cargar el código de conexión de la base se cierra la app

    ResponderEliminar
    Respuestas
    1. El problema es que estás usando la librería, pero es mejor si desarrollas el API, de esa manera no tendrás errores ni en Debug ni en Release :D

      Eliminar
    2. Luis Beltran como esta talves algun ejemplo de como generar esta api que nos pueda ayudar

      Eliminar
    3. Hola. Justo hoy hubo webinar para crear el API: https://www.youtube.com/watch?v=WOZYmkM-6oo

      Solo faltaria publicar en IIS/Azure, eso luego lo podemos ver, pero empieza por este video para conocer cómo crear el API

      Eliminar
  45. Buen día, al compilar en debug el proyecto funciona correctamente pero en release no hace la conexión con la base de datos, la probe en un movil dentro de la misma red y no funciona, podrías ayudarme ?

    ResponderEliminar
    Respuestas
    1. Sí claro, la sugerencia es que hagas un API como lo digo justo al inicio de la publicación, eso te dará los mejores resultados tanto en Debug como en Release :D

      ¡Saludos!

      Eliminar
  46. Este comentario ha sido eliminado por el autor.

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

    ResponderEliminar
  48. I get this error at connectionString: Keyword not supported: 'data source....' Can someone help me?

    ResponderEliminar
  49. Hi, I managed to run this project successfully but when i connect my phone to a different network (wi-fi) the app doesn't work. how to you configure it to work remotely or access the database outside the network.

    ResponderEliminar
    Respuestas
    1. You should create an API. Direct conecction between Xamarin and SQL Server is both limited and insecure.

      Eliminar
  50. Luis Beltran como esta talves una ayuda de como generar la api para que corra la base de datos al generar el archivo apk

    ResponderEliminar
    Respuestas
    1. Hola. Justo hoy hubo webinar para crear el API: https://www.youtube.com/watch?v=WOZYmkM-6oo

      Solo faltaria publicar en IIS/Azure, eso luego lo podemos ver, pero empieza por este video para conocer cómo crear el API

      Eliminar
  51. Excelente explicación, muy buen tutorial!!! Mil gracias!!

    ResponderEliminar
  52. 'Encoding 1252 data could not be found. Make sure you have correct international codeset assembly installed and enabled.'


    Sabe alguien porque da ese error? gracias

    ResponderEliminar
    Respuestas
    1. Al final viene que configuracion necesitas

      https://stackoverflow.com/questions/50586466/xamarin-encoding-error-1252-data-could-not-be-found

      Eliminar
  53. Al usar los datos del movil no me da acceso a la conexion pero si uso el WIFI si me deja consumir mis metodos que conectan a la BD alguien sabe que onda con eso

    ResponderEliminar
    Respuestas
    1. Intenta reemplazar todo por un web api en lugar de conectar directamente, seguro que así te funciona :)

      Eliminar
    2. Ingeniero, gracias, algun tutorial de como crear y consumir API con Xamarin Forms, soy super nuevo en este rollo

      Eliminar
  54. disculpa, no me deja usar itemsSource en el lsvEmpleados, me dice que no es accesible, como soluciono eso?

    ResponderEliminar
    Respuestas
    1. Te recomiendo que generes un WebApi, así podrás monitorear si tu lista está vacía o sí trae datos.

      Salu2

      Eliminar
  55. Buenas tardes,
    Se puede hacer esto mismo y que funcione sin internet? Tengo hecha una aplicación en xamarin forms, mi conexión a la BD es con este método, pero cuando se cae internet, la app pierde la conexión a la BD.
    Hay alguna forma de que se conecte a un SQL sin internet, que la conexión sea por una intranet.
    Saludos

    ResponderEliminar
    Respuestas
    1. Sí claro, crea un Api REST (como menciona al inicio del post, por ejemplo un Web API de ASP .NET Core) y luego publícalo -por ejemplo en IIS de tu servidor local- y podrás conectarte a la IP/nombre del servidor que está en tu intranet :D

      Eliminar
  56. Saludos, antes que nada quiero agradecerte por este tutorial, esta muy completo y explicas todo a detalle, conseguí terminar mi aplicación y durante las pruebas debug, todo salió bien, pero una vez que pongo mi app en producción, me tira este error:
    snix_connect (provider: sni_pn7, error: 40 - sni_error_40) y no estoy seguro de Por que :(

    ResponderEliminar
  57. https://www.uwptutorials.com/uwpmssql.html

    ResponderEliminar