ASP .NET 4.5 Web Forms - Criando a área de Administração - VII


Neste tutorial vamos atualizar a nossa aplicação ASP .NET Web Forms para adicionar uma função de administrador e usar associação usando o recurso membership da ASP.NET. Ele também mostra como implementar uma página de administração a partir do qual o administrador pode adicionar e remover os produtos do site.

Obs: Acompanhe todas as partes do curso neste link: http://www.macoratti.net/Cursos/aspn_450.htm

A ASP.NET Web Forms fornece nativamente capacidades de membership. Ao usar o modelo padrão, temos uma funcionalidade pronta que podemos usar imediatamente quando o aplicativo é executado. Este tutorial mostra como usar o recurso membership da ASP.NET para adicionar uma função de administrador e atribuir um usuário a esse papel. Vamos aprender como restringir o acesso na pasta de administração, e vamos adicionar uma página para a pasta de administração que permite ao administrador adicionar e remover produtos e também visualizar um produto depois que ele foi adicionado.

O que você vai aprender:

Neste tutorial iremos usar os seguintes recursos:

Este artigo foi integralmente baseado no artigo original : http://www.asp.net/web-forms/tutorials/aspnet-45/getting-started-with-aspnet-45-web-forms/membership-and-administration(com algumas alterações e portado para a linguagem VB .NET)

Incluindo um usuário com perfil de administrador

Usando o recurso membership da ASP.NET, é fácil adicionar uma função de administrador e atribuir um usuário a esse papel usando via código.

Vamos começar verificando se os perfis (roles) estão habilitados. Na janela Solution Explorer, localize e abra o arquivo Web.config na raiz da aplicação web.

Vamos localizar o nó roleManager e incluir o atributo enabled= true de forma a ativar este recurso. O código deverá ficar conforme abaixo:

<roleManager enabled="true" defaultProvider="DefaultRoleProvider">

Agora vamos abrir o arquivo Global.asax.cs e adicionar o código destacado abaixo para evento Application_Start :

Dessa forma na próxima vez que a aplicação for executada será criado um usuário Admin, com senha 123&$#, como administrador da nossa aplicação.

Restringindo o acesso à área e à página de administração

Nossa aplicação permite que usuários anônimos e registrados acessem o site, visualizem os produtos e realizem compras. O usuário administrador que acabamos de definir, quando autenticado, deverá ter acesso a uma área restrita para poder incluir e remover produtos.

Vamos incluir uma nova pasta chamada Admin na aplicação que será a nossa área restrita com acesso exclusivo do administrador e vamos incluir nesta pasta a página AdminPage.aspx;

Clique com o botão direito sobre o nome do projeto e selecione a opção Add -> New Folder e informe o nome Admin;

Agora selecione a pasta Admin e clique com o botão direito do mouse sobre ele e clique em Add -> New Item;

Selecione o template Visual Basic->Web e a seguir Web Form using Master Page e informe o nome AdminPage.aspx e clique no botão Add;

Selecione a master page Site.Master e clique em OK;

Agora vamos incluir na pasta Admin um novo arquivo web.config de forma a restringir o acesso às páginas contidas nesta pasta;

Selecione a pasta Admin e no menu Project clique em Add New Item;

Selecione Visual Basic -> Web e o template Web Configuration File. Aceite o nome Web.Config e clique no botão Add;

Substitua o código do arquivo Web.Config incluindo o código a seguir neste arquivo:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <authorization>
      <allow roles="Administrator"/>
      <deny users="*"/>
    </authorization>
  </system.web>
</configuration>.

Este código faz com que somente os usuários com perfil de administrador poderão acessar a pasta Admin.

Incluindo a navegação do administrador

Para permitir ao administrador navegar para a área de administração da aplicação, vamos adicionar um link na página Site.Master. Apenas os usuários que pertencem à função de administrador serão capaz de ver o link do administrador e acessar a seção de administração.

Para criar um link para administradores abra o arquivo Site.master e , adicione a marcação em destaque ao elemento nav, conforme abaixo:

Agora abra o arquivo Site.Master.vb adicione o código a seguir no evento Load para fazer o link Admin visível apenas para administradores:

Quando a página for carregada, o código verifica se o usuário logado tem o perfil de administrador e, se o usuário for um administrador, o elemento span com o link para a página AdminPage.aspx (e consequentemente o link dentro do span) ficará visível.

Habilitando a administração de produtos

Criamos um perfil de administrador e acrescentamos um usuário administrador, uma pasta de administração, e uma página de administração. Definimos também os direitos de acesso para a pasta de administração e da página, e adicionamos um link de navegação para o administrador.

Abra a página Adminpage.aspx na pasta Admin e substitua o código pelo código abaixo:

<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site.Master" CodeBehind="AdminPage.aspx.vb" Inherits="WingTipToys.AdminPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="FeaturedContent" runat="server">
    <h1>Administração</h1>
    <hr />
    <h3>Incluir Produto:</h3>
    <table>
        <tr>
            <td><asp:Label ID="LabelAddCategoria" runat="server">Categoria:</asp:Label></td>
            <td>
                <asp:DropDownList ID="DropDownAddCategory" runat="server" 
                    ItemType="WingtipToys.WingtipToys.Models.Categoria" 
                    SelectMethod="GetCategorias" DataTextField="CategoriaNome" 
                    DataValueField="CategoriaID" >
                </asp:DropDownList>
            </td>
        </tr>
        <tr>
            <td><asp:Label ID="LabelAddNome" runat="server">Nome:</asp:Label></td>
            <td>
                <asp:TextBox ID="AddProdutoNome" runat="server" Width="217px"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" Text="* Nome do Produto é obrigatório." ControlToValidate="AddProdutoNome" 
SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
            </td>
        </tr>
        <tr>
            <td><asp:Label ID="LabelAddDescricao" runat="server">Descrição:</asp:Label></td>
            <td>
                <asp:TextBox ID="AddProdutoDescricao" runat="server" Width="213px"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" Text="* Descrição é obrigatória." ControlToValidate="AddProdutoDescricao" 
SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
            </td>
        </tr>
        <tr>
            <td><asp:Label ID="LabelAddPreco" runat="server">Preço:</asp:Label></td>
            <td>
                <asp:TextBox ID="AddProdutoPreco" runat="server" Width="213px"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" Text="* Preço deve ser informado." ControlToValidate="AddProdutoPreco" 
SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
                <asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" Text="* O preço deve ser válido (não use R$)." ControlToValidate="AddProdutoPreco" 
SetFocusOnError="True" Display="Dynamic" ValidationExpression="^[0-9]*(\.)?[0-9]?[0-9]?$"></asp:RegularExpressionValidator>
            </td>
        </tr>
        <tr>
            <td><asp:Label ID="LabelAddImagemArquivo" runat="server">Arq. Imagem:</asp:Label></td>
            <td>
                <asp:FileUpload ID="ProdutoImagem" runat="server" Width="359px" />
                <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server" Text="* Imagem deve ser informada." ControlToValidate="ProdutoImagem" 
SetFocusOnError="true" Display="Dynamic"></asp:RequiredFieldValidator>
            </td>
        </tr>
    </table>
    <br />
    <asp:Button ID="AddProdutoButton" runat="server" Text="Adicionar Produto" OnClick="AddProdutoButton_Click"  CausesValidation="true"/>
    <asp:Label ID="LabelAddStatus" runat="server" Text=""></asp:Label>
    <br />
    <h3>Remover Produto:</h3>
    <table>
        <tr>
            <td><asp:Label ID="LabelRemoveProduct" runat="server">Product:</asp:Label></td>
            <td><asp:DropDownList ID="DropDownRemoveProduto" runat="server" ItemType="WingtipToys.WingtipToys.Models.Produto" 
                    SelectMethod="GetProdutos" AppendDataBoundItems="true" 
                    DataTextField="ProdutoNome" DataValueField="ProdutoID" >
                </asp:DropDownList>
            </td>
        </tr>
    </table>
    <asp:Button ID="RemoveProdutoButton" runat="server" Text="Remover Produto" OnClick="RemoveProdutoButton_Click" CausesValidation="false"/>
    <asp:Label ID="LabelRemoveStatus" runat="server" Text=""></asp:Label>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
</asp:Content>

A seguir abra o arquivo code-behind AdminPage.aspx.vb e adicione o código a seguir neste arquivo:

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports WingTipToys.WingtipToys.Models
Imports WingTipToys.WingtipToys.Logic

Public Class AdminPage
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim produtoAction As String = Request.QueryString("ProdutoAction")
        If produtoAction = "add" Then
            LabelAddStatus.Text = "Produto Incluído!"
        End If

        If produtoAction = "remove" Then
            LabelRemoveStatus.Text = "Produto removido!"
        End If
    End Sub

    Protected Sub AddProductButton_Click(sender As Object, e As EventArgs)
        Dim fileOK As [Boolean] = False
        Dim path As [String] = Server.MapPath("~/Catalog/Images/")
        If ProdutoImagem.HasFile Then
            Dim fileExtension As [String] = System.IO.Path.GetExtension(ProdutoImagem.FileName).ToLower()
            Dim allowedExtensions As [String]() = {".gif", ".png", ".jpeg", ".jpg"}
            For i As Integer = 0 To allowedExtensions.Length - 1
                If fileExtension = allowedExtensions(i) Then
                    fileOK = True
                End If
            Next
        End If

        If fileOK Then
            Try
                ' Salva imagens na pasta.
                ProdutoImagem.PostedFile.SaveAs(path + ProdutoImagem.FileName)
                ' Salva imagens na pasta Images/Thumbs.
                ProdutoImagem.PostedFile.SaveAs(path + "Thumbs/" + ProdutoImagem.FileName)
            Catch ex As Exception
                LabelAddStatus.Text = ex.Message
            End Try

            ' Inclui os produtos no DB.
            Dim produtos As New AddProdutos()
            Dim addSucesso As Boolean = produtos.AddProduto(AddProdutoNome.Text, AddProdutoDescricao.Text, AddProdutoPreco.Text, 
DropDownAddCategory.SelectedValue, ProdutoImagem.FileName)
            If addSucesso Then
                ' recarrega a pagina
                Dim pageUrl As String = Request.Url.AbsoluteUri.Substring(0, Request.Url.AbsoluteUri.Count() - Request.Url.Query.Count())
                Response.Redirect(pageUrl + "?ProdutoAction=add")
            Else
                LabelAddStatus.Text = "Não foi possível incluir um novo produto no banco de dados."
            End If
        Else
            LabelAddStatus.Text = "Não foi possível aceitar o tipo do arquivo."
        End If
    End Sub

    Public Function GetCategorias() As IQueryable
        Dim db = New ProdutoContexto()
        Dim query As IQueryable = db.Categorias
        Return query
    End Function

    Public Function GetProdutos() As IQueryable
        Dim db = New ProdutoContexto()
        Dim query As IQueryable = db.Produtos
        Return query
    End Function

    Protected Sub RemoveProdutoButton_Click(sender As Object, e As EventArgs)
        Dim db = New ProdutoContexto()
        Dim produtoId As Integer = Convert.ToInt16(DropDownRemoveProduto.SelectedValue)
        Dim myItem = (From c In db.Produtos Where c.ProdutoID = produtoId Select c).FirstOrDefault()
        If myItem IsNot Nothing Then
            db.Produtos.Remove(myItem)
            db.SaveChanges()

            ' recarrega a página
            Dim pageUrl As String = Request.Url.AbsoluteUri.Substring(0, Request.Url.AbsoluteUri.Count() - Request.Url.Query.Count())
            Response.Redirect(pageUrl + "?ProdutoAction=remove")
        Else
            LabelRemoveStatus.Text = "Não foi possível localizar o produto."
        End If
    End Sub

End Class

No código que inserimos no arquivo code-behind AdminPage.aspx.vb temos uma classe chamada AddProdutos que faz o trabalho de adicionar produtos à base de dados. Esta classe não existem ainda, vamos então criá-la agora.

Clique com o botão direito do mouse sobre a pasta Logic e selecione Add -> Class;

Selecione Visual Basic e o template Class, informe o nome AddProduto.vb e clique no botão Add;

A seguir inclua o código abaixo no arquivo AddProdutos.vb na classe AddProduto:

Imports System.Collections.Generic
Imports System.Linq
Imports System.Web
Imports WingTipToys.WingtipToys.Models

Namespace WingtipToys.Logic
    Public Class AddProdutos

        Public Function AddProduto(ProdutoNome As String, ProdutoDesc As String, ProdutoPreco As String, 
ProdutoCategoria As String, ProdutoImagemPath As String) As Boolean
            Dim meuProduto = New Produto()
            meuProduto.ProdutoNome = ProdutoNome
            meuProduto.Descricao = ProdutoDesc
            meuProduto.PrecoUnitario = Convert.ToDouble(ProdutoPreco)
            meuProduto.CaminhoImagem = ProdutoImagemPath
            meuProduto.CategoriaID = Convert.ToInt32(ProdutoCategoria)

            ' pega o contexto
            Dim _db As New ProdutoContexto()

            ' Inclui o produto no DB.
            _db.Produtos.Add(meuProduto)
            _db.SaveChanges()

            ' ok
            Return True
        End Function

    End Class
End Namespace

A página AdminPage.aspx permite ao administrador adicionar e remover produtos. Quando um novo produto é adicionado, os detalhes sobre o produto são validados e, em seguida, gravados no banco de dados. Após isso o novo produto está disponível imediatamente para todos os usuários da aplicação.

Validação Discreta(Unobtrusive Validation)

Os detalhes do produto que o usuário fornece na página AdminPage.aspx são validados usando controles de validação (RequiredFieldValidator e RegularExpressionValidator). Esses controles automaticamente usam a validação discreta. A Validação discreta permite que aos controles de validação usar JavaScript para a lógica da validação do lado do cliente, o que significa que a página tem que ir até o servidor para ser validada. Por padrão, a validação discreta está incluída no arquivo Web.config com base na seguinte configuração:

<add key="ValidationSettings:UnobtrusiveValidationMode" value="WebForms" />

Expressões Regulares

O preço do produto na página AdminPage.aspx é validado usando um controle RegularExpressionValidator. Este controle valida se o valor do controle de entrada associado (o TextBox "AddProdutPreco") corresponde ao padrão especificado pela expressão regular. Uma expressão regular é uma notação de correspondência de padrão que permite encontrar rapidamente e combinar padrões de caracteres específicos. O controle RegularExpressionValidator inclui uma propriedade chamada ValidationExpression que contém a expressão regular usada para validar a entrada de preços, como mostrado abaixo:

<asp:RegularExpressionValidator
   ID="RegularExpressionValidator1" runat="server"
   Text="* O preço deve ser válido (não use R$)." ControlToValidate="AddProdutoPreco"
   SetFocusOnError="True" Display="Dynamic"
   ValidationExpression="^[0-9]*(\.)?[0-9]?[0-9]?$">
</asp:RegularExpressionValidator>

Controle FileUpload

Além da entrada e controles de validação, usamos o controle FileUpload na página AdminPage.aspx. Esse controle fornece a capacidade de fazer upload de arquivos. Neste caso, você está apenas permitindo que os arquivos de imagem possam ser carregados. No arquivo code-behind (AdminPage.aspx.vb), quando o botão AddProdutoButton for clicado, o código verifica a propriedade HasFile do controle FileUpload. Se o controle tem um arquivo e se o tipo de arquivo (com base na extensão do arquivo) for permitido, a imagem é guardada na pasta Images na pasta Images/Thumbs da aplicação.

Usando o Model Binding

Nós já usamos o Model Binding para preencher os controles ListView, FormsView, GridView e o controle DetailView. Neste tutorial, vamos usar o modelo de ligação para preencher um controle DropDownList com uma lista de categorias de produtos.

A marcação que você adicionou no arquivo AdminPage.aspx contém um controle DropDownList chamado DropDownAddCategoria:

<asp:DropDownList ID="DropDownAddCategoria" runat="server"
ItemType="WingtipToys.WingtipToys.Models.Categoria"
SelectMethod="GetCategorias" DataTextField="CategoriaNome"
DataValueField="CategoriaID" >
</asp:DropDownList>

Usamos o modelo de ligação para preencher o DropDownList definindo o atributo ItemType e o atributo SelectMethod. O atributo ItemType especifica que vamos usar o tipo Categoria ao preencher o controle. Definimos este tipo no início desta série de tutoriais criando a classe Categoria. A classe Categoria está na pasta Models dentro do arquivo Categoria.vb.

O atributo SelectMethod do controle DropDownList especifica que usamos o método GetCategorias(abaixo), que está incluído no arquivo code-behind (AdminPage.aspx.vb):

Public Function GetCategorias() As IQueryable
    Dim db = New ProdutoContexto()
    Dim query As IQueryable = db.Categorias
    Return query
End Function

Este método especifica que uma interface IQueryable é usada para avaliar uma consulta contra um tipo de categoria. O valor retornado é utilizado para preencher o DropDownList na marcação da página (AdminPage.aspx).

O texto apresentado para cada item da lista é especificado definindo o atributo DataTextField. O atributo DataTextField usa a propriedade CategoriaNome da classe Categoria para mostrar cada categoria no controle DropDownList. O valor real que é passado quando um item é selecionado no controle DropDownList é baseado no atributo DataValueField. O atributo DataValueField está definido para a propriedade CategoriaID como definido na classe categoria.

Como a aplicação vai funcionar

Quando o administrador navegar para a página, pela primeira vez, o controle DropDownList DropDownAddCategoria é preenchido, tal como descrito acima.

O controle DropDownList DropDownRemoveProduto também é preenchido com os produtos usando a mesma abordagem.

O administrador seleciona o tipo de categoria e acrescenta detalhes do produto (nome, descrição, preço e Arquivo de Imagem).

Quando o administrador clicar no botão Adicionar Produto, o manipulador de eventos AddProdutoButton_Click é acionado; esse manipulador localizado no arquivo code-behind AdminPage.aspx.vb, verifica o arquivo de imagem para se certificar de que ele coincide com os tipos de arquivos permitidos (.Gif,. Jpg, .png, ou .Jpeg).

Em seguida, o arquivo de imagem é salvo em uma pasta da aplicação. A seguir, o novo produto é adicionado à base de dados. Para realizar a adição de um novo produto, uma nova instância da classe AddProdutos é criada e nomeada produtos. A classe AddProdutos tem um método chamado AddProduto, e os objetos produtos chama este método para adicionar o produto à base de dados.

Se um novo produto foi adicionado com sucesso ao banco de dados a página é recarregada usando o valor da query string : ProdutoAction=add.

Quando a página é recarregada, a seqüência de consulta está incluída na URL. Ao recarregar a página, o administrador pode ver imediatamente as atualizações nos controles DropDownList na página AdminPage.aspx. Além disso, ao incluir a seqüência de consulta com a URL, a página pode exibir uma mensagem de sucesso para o administrador.

Quando a página AdminPage.aspx for recarregada o evento Load é chamado e então verifica a query string informando se o produto foi incluído com sucesso.

Testando a aplicação

Vamos executar o aplicativo agora para ver como podemos adicionar, excluir e atualizar os itens no carrinho de compras. O total carrinho de compras irá refletir o custo total de todos os itens no carrinho de compras.

Pressione CTRL+F5 para rodar a aplicação

Será apresentada a página Default.aspx:

Clique no link para realizar o Log in;

A página Login.aspx será apresentada. Vamos fazer o login com o perfil de administrador informando o nome de usuário e a senha que criamos para o perfil de administrador;

Ao verificar que o usuário tem o perfil de administrador a página Default.aspx é recarregada exibindo agora o link Admin e o nome do usuário logado:

Clique no link Admin para acessar a área do administrador. A página AdminPage.aspx será apresentada com as opções para adicionar e remover um produto:

Vamos incluir um produto escolhendo uma categoria e fornecendo alguns dados e o arquivo de imagem:

Eu escolhi a categoria Carros e informei os dados para Ford Fiesta e a imagem de um veículo desta marca:

Após isso podemos verificar e constatar que o produto foi realmente incluindo verificando a relação dos produtos para a categoria Carros:

Clique sobre a imagem para exibir os seus detalhes e assim verificarmos se os dados informados foram gravados:

Tudo ok! Assim confirmamos que nossa implementação esta funcionando corretamente.

No próximo tutorial vamos definir o roteamento na nossa aplicação para tornar as url mais amigáveis:  Implementando o suporte ao roteamento via URL - VIII

Referências:


José Carlos Macoratti