Saltar al contenido

#Login, Iniciar Sesión, Cerrar Sesión y Mostrar datos del usuario con C#, MySQL, WinForm- POO, Arquitectura en Capas- Nivel Intermedio

INTRODUCCIÓN:

En este tutorial aprenderá: Como validar el usuario y contraseña del usuario al iniciar sesión, mostrar los datos del usuario en el formulario de menú principal o en cualquier otro, crearemos la opción de cerrar sesión y cambiar de usuario, con C-Sharp, SQL Server, WinForms, Programación Orientada a Objetos (POO) y Arquitectura en Capas, con buenas prácticas y estrategias (Nivel intermedio).

Puede ver este tutorial en Youtube.

En .NET, no hay diferencia en la sintaxis, ya sea SQL Server o MySQL. Lo único que cambia es SQL por MySQL. Ejemplo:
-SqlCommand <->MySqlCommand
-SqlConnection <->MySqlConnection
-SqlDataReader <-> MySqlDataReader
«Tanto para MySQLConnector Net o MySQL.Data, para ODBC ocurre lo mismo»

    // SQL Client'
    SqlCommand command = new SqlCommand();
    command.CommandText = "select *from users";
    SqlDataReader reader = command.ExecuteReader();

    // MySQL Client'
    MySqlCommand command = new MySqlCommand();
    command.CommandText = "select *from users";
    MySqlDataReader reader = command.ExecuteReader();

    // Data Odbc'
    OdbcCommand command = new OdbcCommand();
    command.CommandText = "select *from users";
    OdbcDataReader reader = command.ExecuteReader();

Por lo tanto puedes seguir todos los tutoriales del proyecto login completo ya sea con C# , VB.Net y SQL Server.

Puede ver todos los capítulos en los siguientes enlaces:

TUTORIAL:

Paso 1: Crear base de datos

  • Crearemos una base de datos de nombre mi compañía, una tabla de usuario y unos cuantos registros para verificar desde nuestra aplicación si existe el nombre de usuario y la contraseña. Puedes crear por cmd, mysql workbench o phpMyAdmin, yo crearé mediante phpMyAdmin en Xampp.
create database MyCompany;
 
use MyCompany;
create table Users(
UserID int auto_increment primary key,
LoginName varchar (100) unique not null,
Password varchar (100) not null,
FirstName varchar(100) not null,
LastName varchar(100) not null,
Position varchar (100) not null,
Email varchar(150)not null
); 
insert into Users values (null,'admin','admin','Jackson','Collins','Administrator','Support@SystemAll.biz');
insert into Users values (null,'Ben','abc123456','Benjamin','Thompson','Receptionist','BenThompson@MyCompany.com');
insert into Users values (null,'Kathy','abc123456','Kathrine','Smith','Accounting','KathySmith@MyCompany.com');

Paso 2: Crear Solución vacío, capas de aplicación y soporte

  • Creamos una solución en blanco de Visual Studio 
  • Agregamos un proyecto nuevo de tipo Aplicación de Windows Forms para la Capa de Presentación.
  • Agregamos un proyecto nuevo de tipo Biblioteca de Clases para la Capa de Dominio o Negocio.
  • Agregamos un proyecto nuevo de tipo Biblioteca de Clases para la Capa de Acceso a Datos o Persistencia.
  • Una vez agregadas las 3 capas de aplicación, finalmente agregamos la Capa de Soporte, también conocida como capa común o capa de corte transversal.

Paso 3: Agregar referencias entre capas (Dependecias)

  • Agregamos las referencias entre capas según la arquitectura tradicional en capas, donde una capa superior sólo conoce la capa inmediatamente debajo de ella, y todas las capas tienen acceso a la Capa Común de Soporte.
  • En Capa de Presentación: Referenciamos a la Capa de Dominio y Capa Común.
  • En Capa de Dominio: Referenciamos a la Capa de Acceso a Datos y Capa Común.
  • En Capa de Acceso a Datos: Referenciamos a la Capa Común.

Una vez que tenemos esquematizada la solución de nuestro proyecto, es el momento de codificarla.

Paso 4: Codificar- Capa Común de Soporte

  • En capa común, agregamos una nueva carpeta de nombre Cache.
  • En la carpeta creada, agregamos un clase estática de nombre Cache de Usuario (UserCache.cs), este clase será responsable de almacenar los datos del usuario que inicia sesión, es muy útil para muchos objetivos, principalmente para aplicar seguridad y privilegios de usuario, mostrar los datos del usuario en la interfaz gráfica, notificaciones, guardar acciones,
  • Una vez creada la clase, declara campos para los datos del usuario que necesites almacenar, de la siguiente manera:

UserCache.cs

   public static class UserCache
    {
        public static int IdUser { get; set; }
        public static string LoginName { get; set; }
        public static string Password { get; set; }
        public static string FirstName { get; set; }
        public static string LastName { get; set; }
        public static string Position { get; set; }
        public static string Email { get; set; }
    }

Paso 5: Codificar- Capa de Acceso a Datos/ Persistencia

  • Si eres experimentado (Intermedio), debes saber que para conectar una aplicación de .NET a una base de datos MySQL o MariaDB, es necesario instalar MySQL Conector-NET o instalar MySql.Data de los paquetes de NuGet, también puedes hacerlo mediante ODBC, en mi opinión personal te recomiendo descargar MySql.Data de los paquetes de NuGet, ya que es el conector mas oficial de oracle para .NET, las actualizaciones y mantenimiento es constante.
  • Dicho lo anterior; instalamos MySql.Data desde Nuget (Clic derecho en Capa de acceso a datos->Administrar paquetes NuGet->Examinar->busca MySql.Data-> Instalar).
  • Agregamos una clase para la conexión a MySQL (ConnectionToMySql.cs), convertimos a Clase Abstracta (Clase base).
  • Importamos la librería  MySql.Data.MySqlClient , creamos la cadena de conexión y un método para obtener la conexión.
using MySql.Data.MySqlClient;

ConnectionToMySql.cs

public abstract  class ConnectionToMySql
{
	private readonly string connectionString;

	public ConnectionToMySql() {
		connectionString = "Server=localhost; Database=MyCompany; User=root; port=3306; password=;";
	}
	protected MySqlConnection GetConnection() {
		return new MySqlConnection(connectionString);
	}
}

El propósito de una clase Abstracta (también conocida como una clase base ) es definir la funcionalidad que es común a todas las clases que deriven de ella. Esto evita que las clases derivadas tengan que redefinir los elementos comunes. En algunos casos, esta funcionalidad común no es lo suficientemente completa para hacer un objeto utilizable, y cada clase derivada define la funcionalidad que falta. En tal caso, desea que el código consumidor cree objetos solo a partir de las clases derivadas. Usted utiliza Abstracten la clase base para hacer cumplir esto.

  • Agregamos otra clase para el objeto de acceso a datos del Usuario (UserDao.cs), es decir, esta clase es responsable de las consultas a la base de datos, referentes al Usuario, como realizar las 4 operaciones CRUD.
  • Importamos la librería Data y MySql.Data.MySqlClient .
  • Importamos la Capa Común y la carpeta cache para almacenar los datos del datos del usuario que inicia sesión.
using System.Data;
using MySql.Data.MySqlClient;
using Common.Cache;
  • Indicamos que la clase hereda de la clase conexión (ConnectionToMySql.cs).
  • Finalmente creamos el método login, para validar el usuario y contraseña al iniciar sesión.

UserDao.cs

public class UserDao : ConnectionToMySql
{
	public bool Login(string user, string pass)
	{
		using (var connection = GetConnection())
		{
			connection.Open();
			using (var command = new MySqlCommand())
			{
				command.Connection = connection;
				command.CommandText = "select *from users where (loginName=@user and password=@pass) or (Email=@user and password=@pass)";
				command.Parameters.AddWithValue("@user", user);
				command.Parameters.AddWithValue("@pass", pass);
				command.CommandType = CommandType.Text;
				MySqlDataReader reader = command.ExecuteReader();
				if (reader.HasRows)
				{
					while (reader.Read())//Obtenemos los datos de la columna y asignamos a los campos de la Cache de Usuario
					{
						UserCache.IdUser = reader.GetInt32(0); 
						UserCache.LoginName = reader.GetString(1);
						UserCache.Password = reader.GetString(2);
						UserCache.FirstName = reader.GetString(3); 
						UserCache.LastName = reader.GetString(4);
						UserCache.Position = reader.GetString(5);
						UserCache.Email = reader.GetString(6);
					}
					return true;
				}
				else
					return false;
			}
		}
	}
}

Ya comenté en algunos videos la importancia de usar USING, La declaración using garantiza que se llame a Dispose una vez termine de ejecutarse los códigos dentro del bloque using, incluso si ocurre una excepción. Para entender mejor, una vez que termine de ejecutarse el método Login, se desechará los objetos sqlConnection y sqlCommand, es por ello que no es necesario, cerrar la conexión o limpiar los parámetros de sqlCommand.

Importante….Tener muy en cuenta

Paso 6: Codificar- Capa de Dominio / Negocio

  • Agregamos una clase para el modelo de Usuario, en esta clase puedes realizar toda la lógica de negocio, validaciones y seguridad. En este caso solo creamos un método para el inicio de sesión que invoque y retorne el resultado del método login de capa de acceso a datos, para ello, necesitamos importar la capa de acceso a datos.
using DataAccess;

UserModel.cs

public class UserModel
{
    UserDao userDao = new UserDao();

    public bool LoginUser(string user, string pass) {
        return userDao.Login(user,pass);
    }    
}

Paso 7: Codificar- Capa de Presentación

  • Creamos el Formulario Login y un Formulario de Menú Principal, en este caso, ya diseñamos el formulario de inicio de sesión en el capítulo anterior, por lo que importamos el formulario: Click derecho en Capa Presentacion->Agregar->Elemento existente-> Localizamos el archivo FormLogin.cs o con el nombre que creaste el formulario (FormLogin.designer.cs y FormLogin.resx se importan automáticamente al importar FormLogin.cs). 
    También importaré el formulario de menú principal realizado en este tutorial (en este formulario agregamos 3 label, para mostrar el cargo, nombre de usuario y email del usuario, también un botón para cerrar sesión).
  • En el Formulario Login, agregamos un Label para mostrar los mensajes de errorimportamos la capa de dominio, creamos el evento click del botón iniciar sesión,  instanciamos al modelo del usuario e invocamos el método login, de ser exitosa, mostramos el formulario de menú principal, también creamos un método de cerrar sesión. (Opcional, mostrar un saludo de bienvenida con el nombre y apellido en un MessageBox, para ello, también necesitamos importar la capa común) De la siguiente manera:
using Domain;
using Common.Cache;

FormLogin.cs

public partial class FormLogin : Form
{ 
	private void btnlogin_Click(object sender, EventArgs e)
	{
		if (txtuser.Text != "Username" && txtuser.TextLength>2)
		{
			if (txtpass.Text != "Password")
			{
				UserModel user = new UserModel();
				var validLogin = user.LoginUser(txtuser.Text, txtpass.Text);
				if (validLogin == true)
				{
					FormMainMenu mainMenu = new FormMainMenu();
					MessageBox.Show("Bienvenido "+UserCache.FirstName+", "+UserCache.LastName);
					mainMenu.Show();
					mainMenu.FormClosed += Logout;
					this.Hide();
				}
				else {
					msgError("Incorrect username or password entered. \n   Please try again.");
					txtpass.Text ="Password";
					txtpass.UseSystemPasswordChar = false;
					txtuser.Focus();
				}
			}
			else msgError("Please enter password.");
		}
		else msgError("Please enter username.");
	}
	private void msgError(string msg)
	{
		lblErrorMessage.Text = "    " + msg;
		lblErrorMessage.Visible = true;
	}
	private void Logout(object sender, FormClosedEventArgs e) {
		txtpass.Text = "Password";
		txtpass.UseSystemPasswordChar = false;
		txtuser.Text = "Username";
		lblErrorMessage.Visible = false;
		this.Show();
	}
}
  • En el Formulario de Menú Principal, creamos un método para mostrar el nombre de inicio de sesion del usuario (LoadUserData), asignamos los datos del usuario almacenados en la clase estatica UserCache.cs al texto de las etiquetas (Label), e invocamos el método desde el evento Load del Formulario. También creamos el evento Click del botón Cerrar Sesión, donde cerramos el formulario y volvemos a mostrar el formulario login.
using Common.Cache;

FormMainMenu.cs

    public partial class FormMainMenu : Form
    {
        private void FormPrincipal_Load(object sender, EventArgs e)
        {
            LoadUserData();
        }
        private void LoadUserData()
        {
            lblUsername.Text = UserCache.LoginName;
            lblPosition.Text = UserCache.Position;
            lblEmail.Text = UserCache.Email;
        }
        private void btnLogout_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure to log out?", "Warning",
               MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
                this.Close();
        } 
    }

Eso es todo 🙂

Puede ver este tutorial en Youtube:

DESCARGAS:

Descargar Base de Datos

Descargar Proyecto Login Completo + CRUD (Nivel Avanzado – MySQL)

La descarga del proyecto (No es gratis) incluye las funciones realizadas en los 6 capítulos del proyecto LOGIN COMPLETO EN C# o LOGIN COMPLETO EN VB.NET, sin embargo, el proyecto tiene un código fuente totalmente modernizado y optimizado, además de incluir CRUD completo con manejo de imágenes, validación de datos duplicados, entre otros. Todo ello con MySQL, WinForm, Programación Orientada a Objetos (POO) y Arquitectura en Capas, con buenas prácticas y estrategias. Puedes descargar las versiones de demostración y obtener los proyectos desde lo botones a continuación: