C# - Login com Entity Framework 6.1


 Este artigo mostra como usar os recursos do Entity Framework 6.1 para criar um formulário de login usando a abordagem DataBase First.

Já estamos na versão 6.1 do Entity Framework e muita coisa evoluiu desde a sua primeira versão.

O Entity Framework é uma ferramenta OR/M que realiza o mapeamento objeto relacional gerando entidades e mapeando-as para as tabelas do banco de dados.

Para você se situar, na tabela a seguir temos uma apresentação de cada versão do EF e seus principais recursos:

Versão Principais Recursos
EF 3.5 Suporte a O/RM básico com a abordagem Database First.
EF 4.0 Suporte a POCO, Lazy loading, melhoria na testabilidade, geração de código customizada e a abordagem Model First.
EF 4.1 Disponibilizado também via pacote NuGet, API DBContext Simplificada ao invés de ObjectContext, abordagem Code First. (Correção de bugs com a versão EF 4.1.1) 
EF 4.3 Recurso Code First Migrations que permite que um banco de dados criado via Code First ser gradativamente alterado conforme o modelo Code First evoluir. Liberação da versão EF 4.3.1 para correção de bugs do EF 4.3.
EF 5.0 Anunciado EF como Open Source. Apoio a Enum Introduzido, funções com valor de tabela, tipos de dados espaciais, vários diagramas por modelo, coloração de formas na superfície de projeto e importação de lote de procedimentos armazenados, EF Power Tools e várias melhorias de desempenho.
EF 6.0/6.1 Inclui muitos novos recursos relacionadas ao Code-First e ao descritor EF como consulta e persistência assíncrona, resilência da resolução de dependências, etc

Mas não se assuste, o Entity Framework 6.0 é uma evolução, e tudo o que você já aprendeu e já conhece sobre o Entity Framework não esta perdido pois ele permanece o mesmo não havendo uma mudança radical no seu funcionamento mas apenas em alguns recursos.

Veja o site oficial do Entity Framework no Nuget : http://www.nuget.org/packages/EntityFramework

Recursos usados

Objetivos

Aprendizado

Criando a solução no VS 2013

Abra o Visual Studio 2013 Express for Windows Desktop e clique em New Project;

Selecione a linguagem Visual C# e o template Windows Forms Application, informe o nome ef6_Login_CSharp e clique no botão OK;

No formulário form1.cs do projeto Windows inclua os seguintes componentes a partir da ToolBox :

Disponha os controles conforme o leiaute da figura abaixo:

Vamos agora incluir um novo projeto em nossa solução onde iremos criar o nosso Model.

Clique no menu FILE -> Add -> New Project;

Selecione o template Class Library, informe o nome Model e clique no botão OK;

Agora vamos incluir um Entity Data Model em nosso projeto Model usando a abordagem DataBase First.

O Entity Framework e pode ser usada com o seguintes padrões de desenvolvimento:

  • Code First - Criamos classes POCO que são mapeadas para as entidades;

  • Database First - Mapeamos para um Banco de dados que já existe;

  • Model First -  Criamos o Modelo conceitual primeiro e depois é gerado o script para criar o banco de dados;

Nosso modelo de entidades vai se basear no banco de dados Agenda.mdf e na tabela Usuarios que eu criei para o exemplo. A tabela Usuarios possui a seguinte estrutura:

CREATE TABLE [dbo].[Usuarios] (

[UsuarioId] INT IDENTITY (1, 1) NOT NULL,

[UsuarioLogin] NVARCHAR (50) NOT NULL,

[UsuarioSenha] NVARCHAR (100) NULL,

[Nome] NVARCHAR (50) NULL,

[Email] NVARCHAR (80) NULL,

[Ativo] BIT NOT NULL,

PRIMARY KEY CLUSTERED ([UsuarioId] ASC)

);

Clique no menu PROJECT -> Add New Item ;

Selecione Data -> ADO .NET Entity Data Model e informe o nome Agenda.emdx;

A seguir clique em Generate from database;

Selecione a conexão com banco de dados Agenda.mdf e aceite o nome da entity connection: AgendaEntities e clique em Next>;

Agora marque a opção para usar o Entity Framework 6.0 e clique em Next>;

Selecione a tabela Usuarios e clique no botão Finish;

Ao final teremos o Entity Data Model e a entidade Usuarios criados conforme a figura a seguir:

Nota: Se desejar pode alterar o nome da entidade de Usuarios para Usuario.

Agora vamos definir uma interface no projeto Model e definir os métodos que iremos usar em nossa aplicação;

No menu PROJECT clique em Add New Item e selecione a seguir selecione o template Interface, informe o nome IAcessoDB.cs e clique em Add;

Agora digite o código a seguir neste arquivo:

using System.Collections.Generic;
namespace Model
{
    public interface IAcessoDB<T>
    {
        bool SalvarUsuario(T registro);
        List<T> GetUsuarios();
        T GetUsuarioPorLoginSenha(T registro);
        T GetUsuarioPorCodigo(int codigo);
    }
}

O código acima define 4 métodos :

  1. SalvarUsuario() - Usado para persistir uma Entidade Usuario no banco de dados;

  2. GetUsuarios() - Usado para retornar lista dos usuários do banco de dados;

  3. GetUsuarioPorLoginSenha() - Usado para retornar um objeto Usuario conforme o nome e senha fornecidos;

  4. GetUsuarioPorCodigo() - Usado para retornar um objeto Usuario pelo código indicado;

Para implementar os métodos dessa interface vamos criar a classe UsuarioDAL.

No menu PROJECT clique em Add New Item e selecione a seguir selecione o template Class, informe o nome UsuarioDAL.cs e clique em Add;

A seguir digite o código abaixo neste arquivo:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Model
{
    public class UsuarioDAL
    {
        public bool SalvarUsuario(Usuario registro)
        {
            using (var agenda = new AgendaEntities())
            {
                agenda.Usuarios.Add(registro);
                var usuarioSalvo = agenda.SaveChanges();
                return usuarioSalvo >= 1;
            }
        }
        public Usuario GetUsuarioPorCodigo(int codigo)
        {
            using (var agenda = new AgendaEntities())
            {
                return agenda.Usuarios.FirstOrDefault(u => u.UsuarioId == codigo);
            }
        }
        public List<Usuario> GetUsuarios()
        {
            try
            {
                using (var agenda = new AgendaEntities())
                {
                    return agenda.Usuarios.ToList();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public Usuario GetUsuarioPorLoginSenha(Usuario registro)
        {
            using (var agenda = new AgendaEntities())
            {
                return agenda.Usuarios.FirstOrDefault(u => u.UsuarioLogin == registro.UsuarioLogin && u.UsuarioSenha == registro.UsuarioSenha);
            }
        }

        public string Cifrar(string textoPuro)
        {
            string chaveCifragem = "MACVS2014XYW";
            byte[] bytesLimpos = Encoding.Unicode.GetBytes(textoPuro);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(chaveCifragem, new byte[]
 { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesLimpos, 0, bytesLimpos.Length);
                        cs.Close();
                    }
                    textoPuro = Convert.ToBase64String(ms.ToArray());
                }
            }
            return textoPuro;
        }
        public string Decifrar(string textoCifrado)
        {
            string chaveCifragem = "MACVS2014XYW";
            byte[] bytesCifrados = Convert.FromBase64String(textoCifrado);
            using (Aes encryptor = Aes.Create())
            {
                Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(chaveCifragem, new byte[] 
{ 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesCifrados, 0, bytesCifrados.Length);
                        cs.Close();
                    }
                    textoCifrado = Encoding.Unicode.GetString(ms.ToArray());
                }
            }
            return textoCifrado;
        }
    }
}

A classe UsuarioDAL implementa a interface IAcessoDB e também possui dois métodos para cifrar e decifrar a senha do usuário.

Nota: A classe UsuarioDAL não deveria conter os métodos para cifrar e decifrar pois isso fere o princípio da responsabilidade única. O ideal seria criamos outro projeto ou outra classe que teria a responsabilidade para realizar essa tarefa.

O SRP - Single Responsability Principle ou princípio da responsabilidade única também conhecido como Coesão(Cohesion).

O princípio da responsabilidade única é um princípio fundamental no desenho de software que reza o seguinte :
"Deve existir um e somente UM MOTIVO para que uma classe mude"

Portanto uma classe deve ser implementada tendo apenas um único objetivo.

Pronto ! já temos toda a infraestrutura pronta para usar os recursos do Entity Framework 6.1 em nosso projeto e acessar o banco de dados Agenda e a tabela Usuarios.

Vamos voltar para o nosso projeto Windows Forms e incluir uma referência nesse projeto ao projeto Model para podermos acessar as classes desse projeto.

Clique com o botão direito do mouse sobre o projeto Windows ef6_Login_CSharp e selecione Add -> Reference ;

A seguir selecione a guia Solution e marque o projeto Model clicando no botão OK;

Vamos alterar o arquivo App.Config do projeto Windows Forms de forma que tenha o seguinte código. (Se desejar pode copiar o arquivo App.Config do projeto Model)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, _ 
PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
  <connectionStrings>
    <add name="AgendaEntities" connectionString="metadata=res://*/Agenda.csdl|res://*/Agenda.ssdl|res://*/Agenda.msl;provider=System.Data.SqlClient; _ 
provider connection string=&quot;data source=(LocalDB)\v11.0;initial catalog=Agenda;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;"
 providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

 

Agora vamos ao código do formulário form1.cs.

Declare os seguintes namespaces no formulário:

using System;

using System.Windows.Forms;

using Model;

Após a declaração do formulário defina a variável dal como do tipo UsuarioDAL que será usada no formulário:

UsuarioDAL dal = new UsuarioDAL();

No evento Click do botão de comando Login inclua o seguinte código:

  private void btnLogin_Click(object sender, EventArgs e)
  {
            if (txtUsuario.Text == "" || txtSenha.Text == "")
            {
                MessageBox.Show("Informe o login e a senha.");
                return;
            }
            try
            {
                Usuario usuario = new Usuario();
                usuario.UsuarioLogin = txtUsuario.Text;
                string cifra = dal.Cifrar(txtSenha.Text);
                usuario.UsuarioSenha = dal.Cifrar(txtSenha.Text);
                if (dal.GetUsuarioPorLoginSenha(usuario) != null)
                {
                    MessageBox.Show("BemVindo");
                }
                else
                {
                    MessageBox.Show("Erro");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Erro " + ex.Message);
            }
  }

O código acima verifica se um nome e senha forma informados e a seguir cria uma instância da classe Usuario atribuindo em seguida os valores informados no formulário às propriedades da classe Usuario.

A seguir usamos o método Cifrar da classe UsuarioDAL para cifrar a senha informada.

Depois usamos o método GetUsuarioPorLoginSenha() passando a entidade Usuario e verificamos se o retorno é null. Se não for null o login foi feito com sucesso.

Na opção - Exibir Usuários - do menu, no evento Click, inclua o código abaixo:

  private void exibirUsuáriosToolStripMenuItem_Click(object sender, EventArgs e)
  {
            try
            {
                exibeUsuarios();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Erro " + ex.Message);
            }
   }

Esse código chama a rotina exibeUsuarios() que vemos a seguir:

   private void exibeUsuarios()
        {
            this.Width = 569;
            this.Height = 522;
            dgvUsuarios.DataSource = dal.GetUsuarios();
        }

 

O código acima chama o método GetUsuarios() que retorna uma lista de usuários do banco de dados e os exibe no controle DataGridView:

Executando o projeto iremos obter o seguinte resultado:

No primeiro momento você poderá obter o seguinte erro quando tentar executar o projeto: (O erro ocorre mesmo não havendo nenhuma indicação de erro durante a compilação)

O erro informa que os provedores System.Data.Entity.SqlServer.SqlProviderServices e  EntityFramework.SqlServer registrados no arquivo App.Config não puderam ser carregados.

A mensagem indica que os respectivos arquivos não foram copiados para o local de saída esperado. Isso ocorre quando não existe uma referência aos tipos no projeto visto que somente serão carregados os recursos que são declarados.

Não deveria ocorrer mas ocorre, Então para resolver o problema consultei os seguintes links:

E bingo !

Basta fazer uma declaração a System.Data.Entity.SqlServer.SqlProviderServices.Instance; no arquivo Agenda.Content.cs para forçar que o arquivo seja copiado:

// <auto-generated>
//     This code was generated from a template.
//
//     Manual changes to this file may cause unexpected behavior in your application.
//     Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Model
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    public partial class AgendaEntities : DbContext
    {
        public AgendaEntities()
            : base("name=AgendaEntities")
        {
        }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }
        public void FixEfProviderServicesProblem()
        {
            //The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer'
            //for the 'System.Data.SqlClient' ADO.NET provider could not be loaded. 
            //Make sure the provider assembly is available to the running application. 
            //See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
            var instance = System.Data.Entity.SqlServer.SqlProviderServices.Instance;
        }
        public virtual DbSet<Usuario> Usuarios { get; set; }
    }
}

Pronto ! o erro desaparece. (Provavelmente isso deve ser corrigido em breve.)

Pegue o projeto completo aqui: ef6_Login_CSharp.zip

João 3:17 Porque Deus enviou o seu Filho ao mundo, não para que julgasse o mundo, mas para que o mundo fosse salvo por ele.

João 3:18 Quem crê nele não é julgado; mas quem não crê, já está julgado; porquanto não crê no nome do unigênito Filho de Deus.

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

 

             Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter
 

Referências:


José Carlos Macoratti