none
No me funciona el Login RRS feed

  • Pregunta

  • Me esta mostrando un comando un comando de error que me dice que no existe ningun dato een la posicion 0 
    SqlConnection SqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["WSPCCon"].ConnectionString);
                SqlCommand SqlCmd = new SqlCommand("SELECT * FROM TablaAdministradores WHERE Nombre = '" + txt_Usuario + "' and PWDCOMPARE('" + txt_Contrasena + "', Contrasena)= '1'", SqlCon);
                DataTable dt = new DataTable();
                SqlDataAdapter da = new SqlDataAdapter(SqlCmd);
                da.Fill(dt);
                if (dt.Rows[0][0].ToString()=="1")
                {
                    MessageBox.Show("Error al ingresar los datos, favor revisar");
                    txt_Contrasena.Clear();
                    txt_Usuario.Clear();
                    txt_Usuario.Focus();
                }
                else
                {
                    loadInfo();
                    VentEsc.Show();
                    this.Hide();
                }
                SqlCon.Close();

    lunes, 21 de agosto de 2017 0:18

Respuestas

  • No, lo que te dice es que esta fuera de rango ese Rown no existe, por otro lado si lo que buscas es saber si tiene datos sería  en el if   dt.Rows.count == 0   o dt.Rows.count < 0 

    • Editado Marcelo PF lunes, 21 de agosto de 2017 0:28
    • Marcado como respuesta Alex Alfonso lunes, 21 de agosto de 2017 1:27
    lunes, 21 de agosto de 2017 0:27

Todas las respuestas

  • No, lo que te dice es que esta fuera de rango ese Rown no existe, por otro lado si lo que buscas es saber si tiene datos sería  en el if   dt.Rows.count == 0   o dt.Rows.count < 0 

    • Editado Marcelo PF lunes, 21 de agosto de 2017 0:28
    • Marcado como respuesta Alex Alfonso lunes, 21 de agosto de 2017 1:27
    lunes, 21 de agosto de 2017 0:27
  • Si la consulta sql retorna cero filas la variable 'dt' va a referenciar a una instancia de tipo DataTable con cero filas, en consecuencia el índice 0 de la colección Rows no va a existir y de ahí que obtengas la excepción de tipo 'IndexOutOfRangeException'. Sin embargo, para validar la existencia de una fila no necesitas crear una instancia de la clase DataTable, basta con llamar al método ExecuteScalar() para obtener un valor, por ejemplo la cuenta de las coincidencias encontradas:

    using (SqlConnection SqlCon = new SqlConnection("Cadena de conexión"))
    {
    	SqlCommand SqlCmd = new SqlCommand(@"SELECT COUNT(*) FROM TablaAdministradores 
    		WHERE Nombre = @Nombre AND PWDCOMPARE(@Contrasena, Contrasena) = 1", SqlCon);
    
    	SqlCmd.Parameters.AddWithValue("@Nombre", txt_Usuario.Text);
    	SqlCmd.Parameters.AddWithValue("@Contrasena", txt_Contrasena.Text);
    
    	if (Convert.ToInt32(SqlCmd.ExecuteScalar()) == 0)
    	{
    		MessageBox.Show("Error al ingresar los datos, favor revisar");
    		//...
    	}
    	else
    	{
    		loadInfo();
    		//...
    	}
    }


    Nuestra profesión exige tener pasión por resolver problemas de una manera óptima y eficiente.
    • Propuesto como respuesta Marcelo PF lunes, 21 de agosto de 2017 3:01
    lunes, 21 de agosto de 2017 1:08
  • Hola Alex:

     Con independencia de que hayas resuelto el origen de tu pregunta, me siento con la obligación de hacer algunas anotaciones sobre el código que presentas para hacer el Login a tu sistema.

    1. El uso del Archivo de configuraciones lo haces bien, es la mejor forma que existe actualmente para almacenar y leer la cadena de conexión, solamente agregaría que debes de contener la cadena dentro de un bloque using con el uso de la instrucción using aseguras que los recursos utilizados dentro de el estén disponibles para su destrucción, en caso de ocurrir alguna excepción, asegura que tu conexión a la base de datos se cierre correctamente.

    using (SqlConnection cnx = new SqlConnection(ConfigurationManager.ConnectionStrings["WSPCCon"].ToString()))
    {
    	//resto de codigo
    }

    2. El echo de concatenar cadenas dentro de una instrucción SQL es una falta grave a la seguridad de la Bd, ya que al concatenar cadenas dejas una puerta abierta a posibles ataques de inyección de código SQL: 

    Inyección SQL 

     SQL Injection

     
    const string sqlAction = "SELECT COUNT(*) FROM Usuarios WHERE Nombre = @nombre AND Password = @pass";
    SqlCommand cmd = new SqlCommand(sqlAction, SqlCon)
    //
    //Asignamos valores a la coleccion de parametros
    //
    cmd.Parameters.AddWithValue("@nombre", usuario);
    cmd.Parameters.AddWithValue("@pass", password);

     3. La llamada del formulario Login, deberá de hacerse desde la clase Program, para que dependiendo del resultado de este, puedas decidir entrar o no al menú principal:

    Te dejo un ejemplo de como debes de trabajar en la clase program y como podria ser tu formulario Login:

    Clase Program:

        static class Program
        {
            /// <summary>
            /// Punto de entrada principal para la aplicación.
            /// </summary>
            [STAThread]
            static void Main()
            {
                //Application.EnableVisualStyles();
                //Application.SetCompatibleTextRenderingDefault(false);
                //Application.Run(new Form1());
    
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                Login frm = new Login();
                frm.ShowDialog();
    
                if (frm.DialogResult == DialogResult.OK)
                    Application.Run(new Form1());
            }
        }

     Observa como antes de llamar al menú principal llamas primero al formulario Login, dentro del Login podrías hacer la validación que deseas:

    public partial class Login : Form
    {
        public Login()
        {
            InitializeComponent();
        }
    
        private void btnaceptar_Click(object sender, EventArgs e)
        {
            try
            {
    
                //Mandamos a llamar a la funcion Autenticar mandandole los parametros requeridos
                if (Autenticar(txtusuario.Text.Trim(), txtpassword.Text.Trim()))
                {
                    //Si el resultado de la funcion es True entonces enviamos como resultado un DialogResult.OK
                    DialogResult = DialogResult.OK;
                }
                else
                {
                    //Si la funcion autenticar envio un False entonces mostramos el mensaje y mandamos un DialogResult.Abort
                    MessageBox.Show("Usuario o Password no validos");
                    DialogResult = DialogResult.Abort;
                }
    
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Error : {0}", ex.Message), "Error inesperado", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    
        public static bool Autenticar(string usuario, string password)
        {
            //Utilizamos el Bloque Using...end Using para administrar la conexion
            //este se encarga de cerrar la conexion y destruir todos los objetos encerrados en el
            using (SqlConnection cnx = new SqlConnection(ConfigurationManager.ConnectionStrings["UserConnectionString"].ToString()))
            {
                //
                //Abrimos la conexion a la Bd
                //
                cnx.Open();
                //
                //Creamos la Consulta SQl utilizando parametros
                //
                const string sqlAction = "SELECT COUNT(*) FROM Usuarios WHERE Usuario = @username AND Password = @pass";
                //
                //Creamos el objento Command
                //
                SqlCommand cmd = new SqlCommand(sqlAction, cnx);
                //
                //Asignamos valores a la coleccion de parametros
                //
                cmd.Parameters.AddWithValue("@username", usuario);
                cmd.Parameters.AddWithValue("@pass", password);
                //
                //Recuperamos la cantidad de registros coincidentes con el Usuario y Password por logica
                //solo podremos recuperar un solo registro
                //
                int tipoUsuario = Convert.ToInt32(cmd.ExecuteScalar());
                //
                //Si el tipodeusuario es Mayor a cero significa que la Validacion fue cumplida
                //
                if (tipoUsuario > 0)
                {
                    //retornamos True ya que la validacion a sido Exitosa
                    //
                    return true;
                }
            }
            //
            //Si la validacion no fue cumplica retornamos False para evitar continuar con el proceso
            //
            return false;
        }
    
        private void btncancelar_Click(object sender, EventArgs e)
        {
            Close();
        }
    
    }

     Observa.

    • Como la función Autenticar realiza una sola acción, validar que el usuario y el password proporcionados existan en la Bd
    • Retorna un solo valor, true o false, dependiendo del resultado de la ejecución de la consulta
    • Como la función Autenticar no interactivo en ningún momento con ningún control, solo recibe datos y regresa una respuesta
    • Como la clase Program, se encarga de validar la respuesta de Login para permitir o no el acceso

     Otro punto que no estamos considerando es la encryptacion de la contraseña mínimo con un HASH para aumentar un poco la seguridad de la aplicación, pero creo que por el momento con estas sugerencias y comentarios te bastara para tener un mejor comienzo en tu aplicación.

     solo como dato cultural:

    Desmitificando la Encriptación (Parte I)

    Espero que la información te sea de utilidad.


    Saludos desde Monterrey, Nuevo León, México!!!

    • Propuesto como respuesta Pedro Ávila lunes, 21 de agosto de 2017 8:57
    lunes, 21 de agosto de 2017 4:42