Вы находитесь на странице: 1из 203

TREINAMENTOS

Desenvolvimento Web com ASP.NET MVC 3

Desenvolvimento Web com ASP.NET MVC

22 de junho de 2011

www.k19.com.br

ii

Sumrio
1 Banco de dados 1.1 Sistemas gerenciadores de banco de dados . . . . . . . . . 1.2 SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Bases de dados (Databases) . . . . . . . . . . . . . . . . 1.3.1 Criando uma base de dados no SQL Server Express 1.4 Tabelas . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.1 Criando tabelas no SQL Server Express . . . . . . 1.5 Operaes Bsicas . . . . . . . . . . . . . . . . . . . . . 1.6 Chaves Primria e Estrangeira . . . . . . . . . . . . . . . 1.7 Consultas Avanadas . . . . . . . . . . . . . . . . . . . . 1.8 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . ADO.NET 2.1 Driver . . . . . . . . . . . . . 2.2 ODBC . . . . . . . . . . . . . 2.3 ODBC Manager . . . . . . . . 2.4 Criando uma conexo . . . . . 2.5 Inserindo registros . . . . . . 2.6 Exerccios . . . . . . . . . . . 2.7 SQL Injection . . . . . . . . . 2.8 Exerccios . . . . . . . . . . . 2.9 Listando registros . . . . . . . 2.10 Exerccios . . . . . . . . . . . 2.11 Fbrica de conexes (Factory) 2.12 Exerccios . . . . . . . . . . . 1 1 2 2 2 4 5 8 10 11 11 29 29 30 30 31 32 32 33 34 35 36 37 38 41 41 41 41 42 42 46 47 50 51

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

Entity Framework 4.1 3.1 Mltiplas sintaxes da linguagem SQL . . . . . . . . . . . 3.2 Orientao a Objetos VS Modelo Entidade Relacionamento 3.3 Ferramentas ORM . . . . . . . . . . . . . . . . . . . . . 3.4 Congurao . . . . . . . . . . . . . . . . . . . . . . . . 3.5 Mapeamento . . . . . . . . . . . . . . . . . . . . . . . . 3.6 Gerando o banco . . . . . . . . . . . . . . . . . . . . . . 3.7 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . 3.8 Sobrescrevendo o nome do Banco de Dados . . . . . . . . 3.9 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . iii

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

SUMRIO 3.10 Manipulando entidades 3.10.1 Persistindo . . 3.10.2 Buscando . . . 3.10.3 Removendo . . 3.10.4 Atualizando . . 3.10.5 Listando . . . 3.11 Exerccios . . . . . . . 3.12 Repository . . . . . . . 3.13 Exerccios . . . . . . . 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

SUMRIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 51 51 52 52 52 52 53 54 57 57 57 58 59 59 59 60 60 60 60 61 63 65 65 68 70 74 75 77 80 81 82 83 83 84 84 86 87 87 89 91 93 94 iv

Viso Geral do ASP .NET MVC 4.1 Necessidades de uma aplicao web 4.2 Viso Geral do ASP .NET MVC . . 4.3 Aplicao de exemplo . . . . . . . . 4.3.1 Testando a aplicao . . . . 4.3.2 Trocando a porta do servidor 4.4 Pgina de Saudao . . . . . . . . . 4.5 Exerccios . . . . . . . . . . . . . . 4.6 Alterando a pgina inicial . . . . . . 4.7 Exerccios . . . . . . . . . . . . . . 4.8 Integrando o Banco de Dados . . . . 4.9 Exerccios . . . . . . . . . . . . . . 4.10 Listando entidades . . . . . . . . . 4.11 Exerccios . . . . . . . . . . . . . . 4.12 Inserindo entidades . . . . . . . . . 4.13 Exerccios . . . . . . . . . . . . . . 4.14 Alterando entidades . . . . . . . . . 4.14.1 Link de alterao . . . . . . 4.15 Exerccios . . . . . . . . . . . . . . 4.16 Removendo entidades . . . . . . . . 4.17 Exerccios . . . . . . . . . . . . . . Tratamento de Erros 5.1 Try-Catch . . . . 5.2 Exerccios . . . . 5.3 Custom Errors . . 5.4 Exerccios . . . . 5.5 Erros do HTTP . 5.6 Exerccios . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

Camada de Apresentao (View) 6.1 Inline Code . . . . . . . . . 6.2 Utilizando Inline Code . . . 6.3 ViewData, ViewBag e Model 6.4 HTML Helpers . . . . . . . 6.4.1 ActionLink Helper .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

www.k19.com.br

SUMRIO 6.4.2 Helpers de Formulrios 6.4.3 DropDownList Helper 6.4.4 Editor Helper . . . . . 6.5 Exerccios . . . . . . . . . . . 6.6 Master Pages . . . . . . . . . 6.6.1 Contedo comum . . . 6.6.2 Lacunas . . . . . . . . 6.7 Exerccios . . . . . . . . . . . 6.8 Importao Automtica . . . . 6.9 Exerccios . . . . . . . . . . . 6.10 Dividindo o contedo . . . . . 6.11 Exerccios . . . . . . . . . . . 7 Controle (Controller) 7.1 Actions . . . . . . . . . . 7.2 ActionResult . . . . . . . 7.3 Parmetros . . . . . . . . 7.3.1 Vrios parmetros 7.3.2 Por objeto . . . . . 7.4 Exerccios . . . . . . . . . 7.5 TempData . . . . . . . . . 7.6 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

SUMRIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 97 98 103 106 107 108 112 116 117 117 119 121 121 122 123 123 124 124 125 126 127 128 128 128 131 131 132 134 138 138 139 139 140 140 145 145 145 146 147 148

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

Rotas 8.1 Adicionando uma rota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2 Denindo parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Validao 9.1 Controller . . . . . . . . . . . 9.2 View . . . . . . . . . . . . . . 9.3 Exerccios . . . . . . . . . . . 9.4 Anotaes . . . . . . . . . . . 9.4.1 Required . . . . . . . 9.4.2 Alterando a mensagem 9.4.3 Outros validadores . . 9.5 Validao no lado do Cliente . 9.6 Exerccios . . . . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

10 Sesso 10.1 Sesso . . . . . . . . . . . . . . 10.1.1 Identicando o Usurio . 10.2 Utilizando Session no ASP.NET 10.3 Session Mode . . . . . . . . . . 10.4 Exerccios . . . . . . . . . . . . v

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

K19 Treinamentos

SUMRIO 11 Filtros 11.1 Filtro de Autenticao . 11.2 Exerccios . . . . . . . 11.3 Action Filters . . . . . 11.4 Exerccios . . . . . . .

SUMRIO 157 157 159 159 160 161 161 161 162 162 163 163 164 164 166 166 168 168 170 170 173 173 175 175 178 178 181 181 189 189 191 191 193 193 194 194

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

12 Projeto 12.1 Modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3 Persistncia - Mapeamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.5 Persistncia - Congurao . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.6 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.7 Persistncia - Repositrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.8 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.8.1 Unit of Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.9 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.10Apresentao - Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.11Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.12Cadastrando e Listando Selees . . . . . . . . . . . . . . . . . . . . . . . . . 12.13Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.14Removendo Selees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.15Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.16Cadastrando, Listando e Removendo Jogadores . . . . . . . . . . . . . . . . . 12.17Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.18Removendo Jogadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.19Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.20Membership e Autorizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.21Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.21.1 Adicionando um Usurio Administrador com ASP .NET Conguration 12.22Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.22.1 Autorizao Role-based . . . . . . . . . . . . . . . . . . . . . . . . . 12.23Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.24Controle de Erro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.25Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.26Enviando email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.27Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

www.k19.com.br

vi

Captulo 1 Banco de dados


O nosso objetivo desenvolver aplicaes em C#. Essas aplicaes necessitam armazenar as informaes relacionadas ao seu domnio em algum lugar. Por exemplo, uma aplicao de gerenciamento de uma livraria deve armazenar os dados dos livros que ela comercializa. Uma forma de suprir essa necessidade seria armazenar essas informaes em arquivos. Contudo, alguns fatores importantes nos levam a descartar tal opo. A seguir, apresentamos as principais preocupaes a serem consideradas ao trabalhar com dados: Segurana: As informaes potencialmente condenciais devem ser controladas de forma que apenas usurios e sistemas autorizados tenham acesso a elas. Integridade: Eventuais falhas de software ou hardware no devem corromper os dados. Acesso: As funes de consulta e manipulao dos dados devem ser implementadas. Concorrncia: Usualmente, diversos sistemas e usurios acessaro as informaes de forma concorrente. Apesar disso, os dados no podem ser perdidos ou corrompidos. Considerando todos esses aspectos, conclumos que seria necessria a utilizao de um sistema complexo para manusear as informaes das nossas aplicaes. Felizmente, tal tipo de sistema j existe e conhecido como Sistema Gerenciador de Banco de Dados (SGBD).

1.1

Sistemas gerenciadores de banco de dados

No mercado, h diversas opes de sistemas gerenciadores de banco de dados. A seguir, apresentamos os mais populares: 1

Banco de dados Oracle SQL Server SQL Server Express PostgreSQL

1.2

SQL Server

Neste treinamento, utilizaremos o SQL Server Express, que mantido pela Microsoft. O SQL Server Express pode ser obtido a partir do site: http://www.microsoft.com/express/Database/.

Microsoft SQL Server Management Studio Express


Para interagir com o SQL Server Express, utilizaremos um cliente com interface grca chamado de Microsoft SQL Server Management Studio Express.

1.3

Bases de dados (Databases)

Um sistema gerenciador de banco de dados capaz de gerenciar informaes de diversos sistemas ao mesmo tempo. Por exemplo, as informaes dos clientes de um banco, alm dos produtos de uma loja virtual. Caso os dados fossem mantidos sem nenhuma separao lgica, a organizao caria prejudicada. Alm disso, seria mais difcil implementar regras de segurana referentes ao acesso dos dados. Tais regras criam restries quanto ao contedo acessvel por cada usurio. Determinado usurio, por exemplo, poderia ter permisso de acesso aos dados dos clientes do banco, mas no s informaes dos produtos da loja virtual, ou vice-versa. Ento, por questes de organizao e segurana, os dados devem ser armazenados separadamente no SGBD. Da surge o conceito de base de dados (database). Uma base de dados um agrupamento lgico das informaes de um determinado domnio, como, por exemplo, os dados da nossa livraria.

1.3.1

Criando uma base de dados no SQL Server Express

Para criar uma base de dados no SQL Server Express, utilizamos o comando CREATE DATABASE. www.k19.com.br 2

Banco de dados

K19 Treinamentos

Banco de dados

Repare que alm da base de dados livraria h outras bases. Essas bases foram criadas automaticamente pelo prprio SQL Server Express para teste ou para guardar algumas conguraes. Quando uma base de dados no mais necessria, ela pode ser removida atravs do comando DROP DATABASE.

1.4

Tabelas

Um servidor de banco de dados dividido em bases de dados com o intuito de separar as informaes de sistemas diferentes. Nessa mesma linha de raciocnio, podemos dividir os dados de uma base a m de agrup-los segundo as suas correlaes. Essa separao feita atravs de tabelas. Por exemplo, no sistema de um banco, interessante separar o saldo e o limite de uma conta, do nome e CPF de um cliente. Ento, poderamos criar uma tabela para os dados relacionados s contas e outra para os dados relacionados aos clientes.

Nome Jos Maria

Clientes Idade Cpf 27 31875638735 32 30045667856

Numero 1 2

Contas Saldo 1000 2000

Limite 500 700 4

www.k19.com.br

Banco de dados Uma tabela formada por registros(linhas) e os registros so formados por campos(colunas). Por exemplo, suponha uma tabela para armazenar as informaes dos clientes de um banco. Cada registro dessa tabela armazena em seus campos os dados de um determinado cliente.

1.4.1

Criando tabelas no SQL Server Express

As tabelas no SQL Server Express so criadas atravs do comando CREATE TABLE. Na criao de uma tabela necessrio denir quais so os nomes e os tipos das colunas.

K19 Treinamentos

Banco de dados

www.k19.com.br

Banco de dados

No SQL Server os nomes das tabelas so precedidas pelo ID do usurio que possui a tabela. No caso do usurio sa, o ID dbo. Portanto o nome da tabela Livros ca dbo.Livros. Se uma tabela no for mais desejada ela pode ser removida atravs do comando DROP TABLE. 7 K19 Treinamentos

Banco de dados

1.5

Operaes Bsicas

As operaes bsicas para manipular os dados das tabelas so: inserir, ler, alterar e remover. Essas operaes so realizadas atravs da linguagem de consulta denominada SQL. Esta linguagem oferece quatro comandos bsicos: INSERT, SELECT, UPDATE e DELETE. Estes comandos so utilizados para inserir, ler, alterar e remover registros respectivamente.

www.k19.com.br

Banco de dados

K19 Treinamentos

Banco de dados

1.6

Chaves Primria e Estrangeira

Suponha que os livros da nossa livraria so separados por editoras. Uma editora possui nome e telefone. Para armazenar esses dados, uma nova tabela deve ser criada. Nesse momento, teramos duas tabelas (Livros e Editoras). Eventualmente, ser necessrio www.k19.com.br 10

Banco de dados descobrir qual a editora de um determinado livro ou quais so os livros de uma determinada editora. Para isso, os registros da tabela Editoras devem estar relacionados aos da tabela Livros. Na tabela Livros, poderamos adicionar uma coluna para armazenar o nome da editora a qual ele pertence. Dessa forma, se algum quiser recuperar as informaes da editora de um determinado livro, deve consultar a tabela Livros para obter o nome da editora correspondente. Depois, com esse nome, deve consultar a tabela Editoras para obter as informaes da editora. Porm, h um problema nessa abordagem, a tabela Editoras aceita duas editoras com o mesmo nome. Dessa forma, eventualmente, no conseguiramos descobrir os dados corretos da editora de um determinado livro. Para resolver esse problema, deveramos criar uma restrio na tabela Editoras que proba a insero de editoras com o mesmo nome. Para resolver esse problema no SQL Server Express, poderamos adicionar a propriedade UNIQUE no campo nome da tabela Editoras. Porm ainda teramos mais um problema: na tabela livro poderamos adicionar registros com editoras inexistentes, pois no h nenhum vnculo explcito entre as tabelas. Para solucionar estes problemas, devemos utilizar o conceito de chave primria e chave estrangeira. Toda tabela pode ter uma chave primria, que um conjunto de um ou mais campos que devem ser nicos para cada registro. Normalmente, um campo numrico escolhido para ser a chave primria de uma tabela, pois as consultas podem ser realizadas com melhor desempenho. Ento, poderamos adicionar um campo numrico na tabela Editoras e torn-lo chave primria. Vamos chamar esse campo de Id. Na tabela Livros, podemos adicionar um campo numrico chamado EditoraId que deve ser utilizado para guardar o valor da chave primria da editora correspondente ao livro. Alm disso, o campo EditoraId deve estar explicitamente vinculado com o campo id da tabela Editoras. Para estabelecer esse vnculo o campo EditoraId deve ser uma chave estrangeira associada ao campo Id. Uma chave estrangeira um conjunto de uma ou mais colunas de uma tabela que possuem valores iguais aos da chave primria de outra tabela. Com a denio da chave estrangeira, um livro no pode ser inserido com o valor do campo EditoraId invlido. Caso tentssemos obteramos uma mensagem de erro.

1.7

Consultas Avanadas

Com o conceito de chave estrangeira, podemos fazer consultas complexas envolvendo os registros de duas ou mais tabelas. Por exemplo, descobrir todos os livros de uma determinada editora.

1.8

Exerccios

1. Abra o Microsoft SQL Server Management Studio Express utilizando NOME_DA_MAQUINA SQLEXPRESS como Server Name, SQL Server Authentication como Authentication, sa como Login e sa como Password. 11 K19 Treinamentos

Banco de dados

2. Caso exista uma base de dados chamada Livraria, remova-a conforme a gura abaixo:

www.k19.com.br

12

Banco de dados

3. Crie uma nova base de dados chamada livraria, conforme mostrado na gura abaixo. Voc vai utilizar esta base nos exerccios seguintes. 13 K19 Treinamentos

Banco de dados

www.k19.com.br

14

Banco de dados

4. Crie uma tabela chamada Editoras conforme as guras abaixo. 15 K19 Treinamentos

Banco de dados

Altere os campos para torn-los obrigatrios, NO permitindo que eles quem em branco N U LL. www.k19.com.br 16

Banco de dados

Alm disso o campo Id deve ser uma chave primria. 17 K19 Treinamentos

Banco de dados

O campo Id dever ser incrementado automaticamente. Dena ele com a propriedade Identity segundo a gura abaixo: www.k19.com.br 18

Banco de dados

5. Crie uma tabela chamada Livros conforme as guras abaixo: 19 K19 Treinamentos

Banco de dados

Lembrando de NO marcar a opo ALLOW NULL. Alm disso o campo Id deve ser uma chave primria e automaticamente incrementada.

Voc precisa tornar o campo EditoraId uma chave estrangeira. Clique com o boto direito sobre a coluna EditoraId e selecione a opo Relantioships..., conforme a gura abaixo: www.k19.com.br 20

Banco de dados

Devemos acrescentar o relacionamento entre livro e editora. Clique em Add e posteriormente no boto direita na linha Tables and Columns Specication. 21 K19 Treinamentos

Banco de dados

Devemos informar qual a chave primria que a coluna EditoraId da tabela Livros faz referncia. Para isto, informe a tabela Editoras como Primary Key Table e indique a coluna Id como a chave primria referenciada. Selecione a coluna EditoraId como a coluna que ir fazer referncia a chave primria da tabela Editoras.

6. Adicione alguns registros na tabela Editoras. Veja exemplos na gura abaixo: www.k19.com.br 22

Banco de dados

7. Adicione alguns registros na tabela Livros. Veja exemplos na gura abaixo:

23

K19 Treinamentos

Banco de dados 8. Consulte os registros da tabela Editoras, e em seguida consulte a tabela Livros. Veja exemplos logo abaixo:

9. Altere alguns dos registros da tabela Livros. Veja o exemplo abaixo: www.k19.com.br 24

Banco de dados

10. Altere alguns dos registros da tabela Editoras. Veja o exemplo abaixo:

11. Remova alguns registros da tabela Livros. Veja o exemplo abaixo: 25 K19 Treinamentos

Banco de dados

12. Remova alguns registros da tabela Editoras. Preste ateno para no remover uma editora que tenha algum livro relacionado j adicionado no banco. Veja o exemplo abaixo:

13. Faa uma consulta para buscar todos os livros de uma determinada editora. Veja um exemplo na gura abaixo: www.k19.com.br 26

Banco de dados

27

K19 Treinamentos

Banco de dados

www.k19.com.br

28

Captulo 2 ADO.NET
No captulo anterior, aprendemos que utilizar bancos de dados uma boa soluo para o armazenamento dos dados do estoque de uma loja virtual. Entretanto, voc deve ter percebido que a interface de utilizao do SQL Server Express (e dos outros bancos de dados em geral) no muito amigvel. Ela exige que o usurio conhea a sintaxe do SQL para escrever as consultas. Alm disso, quando o volume de dados muito grande, mais difcil visualizar os resultados. Na prtica uma aplicao com interface simples desenvolvida para permitir que os usurios do sistema possam manipular os dados do banco. De alguma forma, essa aplicao precisa se comunicar com o banco de dados utilizado no sistema. Nesse captulo vamos desenvolver uma aplicao para acessar os dados do estoque da nossa loja virtual.

2.1

Driver

Como a aplicao precisa conversar com o banco de dados, ela deve trocar mensagens com o mesmo. O formato das mensagens precisa ser denido previamente. Por questes de economia de espao, cada bit de uma mensagem tem um signicado diferente. Em outras palavras, o protocolo de comunicao binrio. Mensagens denidas com protocolos binrios so facilmente interpretadas por computadores. Por outro lado, so complexas para um ser humano compreender. Dessa forma, mais trabalhoso e mais suscetvel a erro desenvolver uma aplicao que converse com um banco de dados atravs de mensagens binrias. Para resolver esse problema e facilitar o desenvolvimento de aplicaes que devem se comunicar com bancos de dados, as empresas que so proprietrias desses bancos oferecem os drivers de conexo. Os drivers de conexo atuam como tradutores de comandos escritos em uma determinada linguagem de programao para comandos no protocolo do banco de dados. Do ponto de vista do desenvolvedor da aplicao, no necessrio conhecer o complexo protocolo binrio do banco. Em alguns casos, o protocolo binrio de um determinado banco de dados fechado. Consequentemente, a nica maneira de se comunicar com o banco de dados atravs de um driver de conexo. 29

ADO.NET

2.2

ODBC

Suponha que os proprietrios dos bancos de dados desenvolvessem os drivers de maneira totalmente independente. Consequentemente, cada driver teria sua prpria interface, ou seja, seu prprio conjunto de instrues. Dessa maneira, o desenvolvedor da aplicao precisa conhecer as instrues de cada um dos drivers dos respectivos bancos que ele for utilizar.

Para facilitar o trabalho do desenvolvedor da aplicao, a Microsoft deniu uma especicao chamada ODBC (Open Database Connectivity) para padronizar a interface dos drivers de conexo. Assim, quando uma empresa proprietria de um banco de dados pretende desenvolver um driver, ela segue essa especicao com o intuito de populariz-lo.

Os drivers de conexo que respeitam a especicao ODBC, ou seja, possuem um conjunto de comandos padronizados, so chamados de drivers de conexo ODBC.

2.3

ODBC Manager

Para que drivers ODBC possam ser instalados em uma mquina e as aplicaes consigam utiliz-los necessrio ter o ODBC Manager, que j vem instalado no Windows.

O driver de conexo ODBC j est disponvel para utilizao, podemos consultar o ODBC Manager do Windows. O ODBC Manager pode ser executado atravs do item Ferramentas Administrativas do Painel de Controle. www.k19.com.br 30

ADO.NET

2.4

Criando uma conexo

Com o driver de conexo ODBC instalado na mquina j possvel criar uma conexo com o banco de dados correspondente. O que necessrio para estabelecer uma conexo com o banco de dados? Escolher o driver de conexo; Denir a localizao do banco de dados; Informar o nome da base de dados; Ter um usurio e senha cadastrados no banco de dados. Todas essas informaes so denidas na chamada string de conexo.
1 2 string stringDeConexao = @"driver={SQL Server}; server=MARCELO-PC\SQLEXPRESS;database=livraria;uid=sa;pwd=sa;";

31

K19 Treinamentos

ADO.NET Aps a denio da string de conexo, podemos utilizar a classe do .NET Framework que responsvel por criar conexes ODBC. Esta classe que vamos utilizar a System.Data.Odbc.OdbcConnection.
1 OdbcConnection conexao = new OdbcConnection(stringDeConexao);

2.5

Inserindo registros

Estabelecida a conexo com o banco de dados, j podemos executar comandos. Por exemplo, j podemos inserir registros nas tabelas. O primeiro passo para executar um comando den-lo em linguagem SQL.
1 2 string textoDoComando = @"INSERT INTO Editoras (Nome, Email) VALUES (Abril, abril@email.com);";

Em seguida, devemos criar um objeto da classe System. Data.Odbc.OdbcCommand vinculado ao texto do comando e conexo previamente criada. O comando no executado quando os objetos dessa classe so instanciados.
1 OdbcCommand comando = new OdbcCommand(textoDoComando, conexao);

Por m, o comando pode ser executado atravs do mtodo ExecuteNonQuery. A conexo deve ser aberta antes de executar o comando.
1 2 conexao.Open(); comando.ExecuteNonQuery();

Se a aplicao mantiver as conexes abertas o banco de dados pode deixar de atender outras aplicaes pois h um limite de conexes que o banco pode suportar. Portanto, importante que as conexes sejam fechadas quando no forem mais necessrias.
1 conexao.Close();

2.6

Exerccios

1. Crie um projeto do tipo Console Application no Microsoft Visual C# Express, chamado ODBC. 2. Utilizando o projeto do exerccio anterior, faa um programa para inserir registros na tabela Editoras. www.k19.com.br 32

ADO.NET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 using System.Data.Odbc; namespace Odbc { class InsereEditora { static void Main(string[] args) { string stringDeConexao = @"driver={SQL Server}; server=MARCELO-PC\SQLEXPRESS;database=livraria;uid=sa;pwd=sa;";

using (OdbcConnection conexao = new OdbcConnection(stringDeConexao)) { string textoInsereEditora = "INSERT INTO Editoras (Nome, Email) Values(Abril, abril@email.com)" ; OdbcCommand command = new OdbcCommand(textoInsereEditora, conexao); conexao.Open(); command.ExecuteNonQuery(); // A Conexao eh automaticamente fechada // ao final do bloco Using. } } } }

3. (Opcional) Analogamente, ao exerccio anterior crie um programa para inserir livros.

2.7

SQL Injection

Da maneira que implementamos a insero de categorias, h duas falhas: uma de segurana e outra tcnica. A falha de segurana ocorre quando uma pessoa mal intencionada ao preencher um formulrio, digita propositalmente uma sentena em SQL que provoca um comportamento no previsto. Esse comportamento, pode por vezes, comprometer a segurana, s vezes mostrando pessoa mal intencionada informaes condenciais, em outras pode apagar informaes do banco. Esse tipo de ataque conhecido como SQL Injection.

33

K19 Treinamentos

ADO.NET O problema de SQL Injection pode ser resolvido manualmente. Basta fazer escape dos caracteres especiais, por exemplo: ponto-e-vrgula e apstrofo. No MySQL Server, os caracteres especiais devem ser precedidos pelo caracter \. Ento seria necessrio acrescentar \ em todas as ocorrncias de caracteres especiais nos valores passados pelo usurio. Esse processo, alm de trabalhoso, diferente para cada banco de dados, pois o \ no padronizado e cada banco tem o seu prprio mtodo de escape de caracteres especiais. Tornando mais prtica a comunicao com o banco de dados o prprio driver faz o tratamento das sentenas SQL. Esse processo denominado sanitize.

1 2 3 4 5 6 7 8 9 10 11 12 13 14

// pegando os dados da editora pelo teclado string nome = Console.ReadLine(); string email = Console.ReadLine(); // definindo a sentena SQL com parmetros string textoDoComando = @"INSERT INTO Editoras (Nome, Email) VALUES (?, ?);"; // criando um comando odbc OdbcCommand comando = new OdbcCommand(textoDoComando, conexao); // atribuindo valores aos parmetros comando.Parameters.AddWithValue("@Nome", nome); comando.Parameters.AddWithValue("@Email", email);

Observe que a sentena SQL foi denida com parmetros atravs do caracter ?. Antes de executar o comando, necessrio atribuir valores aos parmetros. Isso feito com o mtodo AddWithValue. Esse mtodo realiza a tarefa de sanitizar os valores enviados pelo usurio.

2.8

Exerccios

4. Tente causar um erro de SQL Injection na classe feita no exerccio de inserir editoras. (Dica: tente entradas com aspas simples)

5. Altere o cdigo para eliminar o problema do SQL Injection. Voc deve deixar a classe com o cdigo abaixo: www.k19.com.br 34

ADO.NET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using System; using System.Data.Odbc;

namespace Odbc { class InsereEditora { static void Main(string[] args) { string stringDeConexao = @"driver={SQL Server}; server=MARCELO-PC\SQLEXPRESS;database=livraria;uid=sa;pwd=sa;";

Console.WriteLine("Abrindo conexao..."); using (OdbcConnection conexao = new OdbcConnection(stringDeConexao)) { string textoInsereEditora = "INSERT INTO Editoras (Nome, Email) Values(?, ?)"; Console.WriteLine("Digite o nome da Editora:"); string nome = Console.ReadLine(); Console.WriteLine("Digite o email da Editora:"); string email = Console.ReadLine(); OdbcCommand command = new OdbcCommand(textoInsereEditora, conexao); command.Parameters.AddWithValue("@Nome", nome); command.Parameters.AddWithValue("@Email", email); conexao.Open(); command.ExecuteNonQuery(); // A Conexao eh automaticamente fechada // ao final do bloco Using. } } } }

6. Agora tente causar novamente o problema de SQL Injection ao inserir novas editoras.

2.9

Listando registros

Depois de inserir alguns registros, interessante consultar os dados das tabelas para conferir se a insero foi realizada com sucesso. O processo para executar um comando de consulta parecido com o de insero. necessrio denir a sentena SQL e criar um objeto da classe OdbcCommand.
1 2 3 4 5 // definindo a sentena SQL string textoDoComando = @"SELECT * FROM Editoras;"; // criando um comando odbc OdbcCommand comando = new OdbcCommand(textoDoComando, conexao);

A diferena que para executar um comando de consulta necessrio utilizar o mtodo ExecuteReader ao invs do ExecuteNonQuery. Esse mtodo devolve um objeto da classe System.Data.Odbc.OdbcDataReader
1 OdbcDataReader resultado = comando.ExecuteReader();

35

K19 Treinamentos

ADO.NET Os dados contidos no OdbcDataReader podem ser acessados atravs de indexers.

1 2

string nome = resultado["Nome"] as string; string email = resultado["Email"] as string;

O cdigo acima mostra como os campos do primeiro registro da consulta so recuperados. Agora, para recuperar os outros registros necessrio avanar o OdbcDataReader atravs do mtodo Read.

1 2 3 4 5 6 7

string nome1 = resultado["nome"] as string; string email1 = resultado["email"] as string; resultado.Read(); string nome2 = resultado["nome"] as string; string email2 = resultado["email"] as string;

O prprio mtodo Read devolve um valor booleano para indicar se o reader conseguiu avanar para o prximo registro. Quando esse mtodo devolver false signica que no h mais registros para serem consultados.

1 2 3 4 5

while(resultado.Read()) { string nome = resultado["nome"] as string; string email = resultado["email"] as string; }

2.10

Exerccios

7. Insira algumas editoras utilizando a classe I NSERE E DITORA que voc criou nos exerccios acima.

8. Adicione uma nova classe ao projeto chamada ListaEditora. O objetivo listar as editoras que foram salvas no banco. Adicione o seguinte cdigo esta classe. www.k19.com.br 36

ADO.NET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using System; using System.Data.Odbc; namespace Odbc { class ListaEditora { static void Main(string[] args) { string stringDeConexao = @"driver={SQL Server}; server=MARCELO-PC\SQLEXPRESS;database=livraria;uid=sa;pwd=sa;";

Console.WriteLine("Abrindo conexao..."); using (OdbcConnection conexao = new OdbcConnection(stringDeConexao)) { string textoListaEditora = "SELECT * FROM Editoras"; OdbcCommand command = new OdbcCommand(textoListaEditora, conexao); conexao.Open(); OdbcDataReader resultado = command.ExecuteReader(); while (resultado.Read()) { long? id = resultado["Id"] as long?; string nome = resultado["Nome"] as string; string email = resultado["Email"] as string; Console.WriteLine("{0} : {1} - {2}\n",id,nome,email); } // A Conexao eh automaticamente fechada // ao final do bloco Using. } } } }

2.11

Fbrica de conexes (Factory)

Voc deve ter percebido que para cada ao executada no banco de dados, ns precisamos criar uma conexo. Isso gera um problema relacionado string de conexo car armazenada em diversos locais. Imagine que o driver do banco foi atualizado e mudamos a sua verso. Isso implicaria fazer diversas alteraes no cdigo em cada ocorrncia da string de conexo, tornando o cdigo mais suscetvel a erros e dicultando a sua manuteno. Para resolver esta situao, ns poderamos criar uma classe responsvel pela criao e distribuio de conexes, mantendo assim uma nica referncia para a string de conexo, e qualquer alterao no modo em que nos conectamos base de dados, s implica mudanas nesta classe. 37 K19 Treinamentos

ADO.NET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 static class FabricaDeConexao { public static OdbcConnection CriaConexao() { string driver = @"SQL Server"; string servidor = @"MARCELO-PC\SQLEXPRESS"; string baseDeDados = @"livraria"; string usuario = @"sa"; string senha = @"sa"; StringBuilder connectionString = new StringBuilder(); connectionString.Append("driver="); connectionString.Append(driver); connectionString.Append(";server="); connectionString.Append(servidor); connectionString.Append(";database="); connectionString.Append(baseDeDados); connectionString.Append(";uid="); connectionString.Append(usuario); connectionString.Append(";pwd="); connectionString.Append(senha); return new OdbcConnection(connectionString.ToString()); } }

Agora podemos obter uma nova conexo apenas chamando FabricaDeConexao.CriaConexao(). O resto do sistema no precisa mais conhecer os detalhes sobre a conexo com o banco de dados, diminuindo o acoplamento da aplicao.

2.12

Exerccios

9. Adicione uma nova classe chamada FABRICA D E C ONEXAO e adicione o seguinte cdigo: www.k19.com.br 38

ADO.NET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 using System; using System.Data.Odbc; using System.Text; namespace Odbc { static class FabricaDeConexao { public static OdbcConnection CriaConexao() { string driver = @"SQL Server"; string servidor = @"MARCELO-PC\SQLEXPRESS"; string baseDeDados = @"livraria"; string usuario = @"sa"; string senha = @"sa"; StringBuilder connectionString = new StringBuilder(); connectionString.Append("driver="); connectionString.Append(driver); connectionString.Append(";server="); connectionString.Append(servidor); connectionString.Append(";database="); connectionString.Append(baseDeDados); connectionString.Append(";uid="); connectionString.Append(usuario); connectionString.Append(";pwd="); connectionString.Append(senha); return new OdbcConnection(connectionString.ToString()); } } }

10. Altere as classes I NSERE E DITORA e L ISTA E DITORA para que elas utilizem a fbrica de conexo. Execute-as novamente. 11. (Opcional) Implemente um teste que remove uma editora pelo id. 12. (Opcional) Implemente um teste que altera os dados de uma editora pelo id.

39

K19 Treinamentos

ADO.NET

www.k19.com.br

40

Captulo 3 Entity Framework 4.1


3.1 Mltiplas sintaxes da linguagem SQL

No captulo anterior, voc aprendeu a utilizar a especicao ODBC para fazer uma aplicao C# interagir com um banco de dados. Essa interao realizada atravs de consultas escritas em SQL. Uma desvantagem dessa abordagem, que a sintaxe da linguagem SQL, apesar de parecida, pode variar conforme o banco de dados que est sendo utilizado. Desse modo, os desenvolvedores teriam que aprender as diferenas entres as sintaxes do SQL correspondentes aos banco de dados que ele utilizar. Seria bom se, ao invs de programar direcionado a um determinado banco de dados, pudssemos programar de uma maneira mais genrica, voltado uma interface ou especicao, assim poderamos escrever o cdigo independente de SQL.

3.2

Orientao a Objetos VS Modelo Entidade Relacionamento

Outro problema na comunicao entre uma aplicao C# e um banco de dados o conito de paradigmas. O banco de dados organizado seguindo o modelo entidade relacionamento, enquanto as aplicaes C#, geralmente, utilizam o paradigma orientado a objetos. A transio de dados entre o modelo entidade relacionamento e o modelo orientado a objetos no simples. Para realizar essa transio, necessrio denir um mapeamento entre os conceitos desses dois paradigmas. Por exemplo, classes podem ser mapeadas para tabelas, objetos para registros, atributos para campos e referncia entre objetos para chaves estrangeiras.

3.3

Ferramentas ORM

Para facilitar a comunicao entre aplicaes C# que seguem o modelo orientado a objetos e os banco de dados que seguem o modelo entidade relacionamento, podemos utilizar ferramentas que automatizam a transio de dados entre as aplicaes e os diferente bancos de dados e que so conhecidas como ferramentas de ORM (Object Relational Mapper). Outra consequncia, ao utilizar uma ferramenta de ORM, que no necessrio escrever consultas em SQL, pois a prpria ferramenta gera as consultas de acordo com a sintaxe da 41

Entity Framework 4.1 linguagem SQL correspondente ao banco que est sendo utilizado. A principal ferramenta ORM para C# o Entity Framework. Mas, existem outras que possuem o mesmo objetivo.

3.4

Congurao

Antes de comear a utilizar o Entity Framework, necessrio baixar no site a verso 4.1: (http://www.microsoft.com/downloads/details.aspx?FamilyID=b41c728e-9b4f

3.5

Mapeamento

Um dos principais objetivos dos frameworks ORM estabelecer o mapeamento entre os conceitos do modelo orientado a objetos e os conceitos do modelo entidade relacionamento. Este mapeamento pode ser denido atravs de xml ou de maneira mais prtica com DbContext. Quando utilizamos DbContext, evitamos a criao de extensos arquivos em xml. Podemos denir as seguintes entidades:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

public class Livro { public int LivroId { get; set; } public string Titulo { get; set; } public decimal Preco { get; set; } public Editora Editora { get; set; } } public class Editora { public int EditoraId { get; set; } public string Nome { get; set; } public string Email { get; set; } public ICollection<Livro> Livros { get; set; } }

Criaremos agora uma classe para ajudar a mapear as entidades para um banco de dados. A classe EditoraContext deriva de DbContext que faz parte da biblioteca Code First:
1 2 3 4 5 public class EditoraContext : DbContext { public DbSet<Editora> Editoras { get; set; } public DbSet<Livro> Livros { get; set; } }

Utilizamos o padro EF4 Code First para permitir a persistncia no banco de dados. Isto signica que as propriedades Editoras e Livros sero mapeadas para tabelas com mesmo nome banco de dados. Cada propriedade denida na entidade Livro e Editora mapeada para colunas das tabelas Livros e Editoras. Abaixo segue a denio da tabela Editoras que foi criada em nosso banco de dados: www.k19.com.br 42

Entity Framework 4.1

Abaixo segue a denio da tabela Livros que foi criada em nosso banco de dados:

Ns no precisamos congurar nada para que a persistncia e o mapeamento fossem feitos com o EF Code First - isto ocorreu simplesmente escrevendo as trs classes acima. No necessrio nenhuma congurao a mais. Podemos utilizar anotaes para sobrescrever a conveno padro. Para utilizar anotao precisamos adicionar como referncia EntityFramework.dll e System.ComponentModel.DataAnnotations.dll ao projeto e acrescentar using para o namespace System.ComponentModel.DataAnnotations. Segue as principais anotaes:

ColumnAttribute Dene o nome e o tipo da coluna no banco de dados da propriedade mapeada.

1 2 3 4 5 6 7 8

public class Livro { public int LivroId { get; set; } [Column("NomeDoLivro",TypeName="varchar")] public string Titulo { get; set; } public decimal Preco { get; set; } public Editora Editora { get; set; } }

DatabaseGeneratedAttribute Utilizado para indicar que o valor do atributo gerado pelo banco de dados. Para denir como o atributo gerado voc utiliza trs constantes do enum DatabaseGenerateOption: DatabaseGeneratedOption.Identity que dene que o valor ser denido na insero e assume que no ser mais alterado. DatabaseGeneratedOption.Computed que lido na insero e a cada atualizao. DatabaseGeneratedOption.None indica que o valor no ser gerado pelo banco de dados.

ForeignKeyAttribute adicionado a propriedade para especicar a propriedade que dene a chave estrangeira do relacionamento. 43 K19 Treinamentos

Entity Framework 4.1


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

public class Livro { public int LivroId { get; set; } public string Titulo { get; set; } public decimal Preco { get; set; } [ForeignKey("Editora")] public int EditoraId { get; set; } public Editora Editora { get; set; } } public class Editora { public int EditoraId { get; set; } public string Nome { get; set; } public string Email { get; set; } public ICollection<Livro> Livros { get; set; } }

InversePropertyAttribute Indica a propriedade que dene o relacionamento. Esta anotao utilizada quando temos mltiplos relacionamentos do mesmo tipo. Por exemplo, suponha que tenhamos uma entidade Pessoa pode ser autor ou revisor de um livro. Uma pessoa pode ter livros publicados e livros revisados, portanto a entidade Pessoa tem dois relacionamentos diferentes com a entidade Livro.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

public class Pessoa { public int Id { get; set; public string Nome { get; public ICollection<Livro> public ICollection<Livro> } public class Livro { public public public public

} set; } LivrosPublicados { get; set; } LivrosRevisados { get; set; }

int LivroId { get; set; } string Titulo { get; set; } decimal Preco { get; set; } Editora Editora { get; set; }

[InverseProperty("LivrosPublicados")] public Pessoa Autor { get; set; } [InverseProperty("LivrosRevisados")] public Pessoa Revisor { get; set; } }

KeyAttribute Dene a propriedades ou propriedades que identicam uma entidade. Se a classe dene propriedades com ID ou Id, ou nome da classe seguido por ID ou Id, esta propriedade tratada como chave primria por conveno. Caso contrrio, podemos denir a nossa chave primria com o KeyAttribute. www.k19.com.br 44

Entity Framework 4.1


1 2 3 4 5 6 7 8 9

public class Pessoa { [Key] public int Identificador { get; set; } public string Nome { get; set; } public ICollection<Livro> LivrosPublicados { get; set; } public ICollection<Livro> LivrosRevisados { get; set; } }

MaxLengthAttribute Dene o tamanho mximo permitido para um array ou string. MinLengthAttribute Dene o tamanho mnimo permitido para um array ou string.
1 2 3 4 5 6 7 8 9 10 public class Pessoa { public int Id { get; set; } [MinLength(10,ErrorMessage="Tamanho minimo: 10")] [MaxLength(255,ErrorMessage="Tamanho mximo: 255")] public string Nome { get; set; } public ICollection<Livro> LivrosPublicados { get; set; } public ICollection<Livro> LivrosRevisados { get; set; } }

StringLengthAttribute Dene o tamanho mnimo e mximo permitido para o campo string.


1 2 3 4 5 6 7 8 9 public class Editora { public int EditoraId { get; set; } [StringLength(255,MinimumLength=10)] public string Nome { get; set; } public string Email { get; set; } public string ExtraInfo { get; set; } public ICollection<Livro> Livros { get; set; } }

NotMappedAttribute Pode ser aplicado em classes ou propriedades. Quando aplicado em classes ou propriedades indica que este no ser includo no momento de denio do banco de dados.
1 2 3 4 5 6 7 8 9 10

public class Editora { public int EditoraId { get; set; } public string Nome { get; set; } public string Email { get; set; } [NotMapped] public string ExtraInfo { get; set; } public ICollection<Livro> Livros { get; set; } }

45

K19 Treinamentos

Entity Framework 4.1 RequiredAttribute Dene que este campo obrigatrio. Este atributo ignorado em propriedades do tipo collection. Quando denido numa referncia, indica que cardinalidade 1 e a propriedade da chave estrangeira no-nula.
1 2 3 4 5 6 7 8 9 10

public class Editora { public int EditoraId { get; set; } [Required] public string Nome { get; set; } public string Email { get; set; } public string ExtraInfo { get; set; } public ICollection<Livro> Livros { get; set; } }

TableAttribute Dene a tabela para o qual a classe mapeada.


1 2 3 4 5 6 7 8 9 10 11

[Table("Livros")] public class Livro { public int LivroId { get; set; } public string Titulo { get; set; } public decimal Preco { get; set; } public Editora Editora { get; set; } public Pessoa Autor { get; set; } public Pessoa Revisor { get; set; } }

3.6

Gerando o banco

Uma das vantagens de utilizar o EF4 Code First, que ele capaz de gerar as tabelas do banco para a nossa aplicao. Ele faz isso de acordo com as anotaes colocadas nas classes e as informaes presentes no D B C ONTEXT. As tabelas so geradas quando criamos uma instncia de DbContext() e o contexto necessita fazer alguma requisio ao banco de dados. Por exemplo, quando adicionamos uma entidade ao contexto.
1 2 3 4

EditoraContext context = new EditoraContext(); // Neste momento ser criado o banco de dados, caso no exista context.Editoras.Add(new Editora{ Nome = "Abril" });

A poltica de criao das tabelas pode ser alterada atravs do mtodo de classe (esttico) System.Data.Entity.Database.SetInitializer<TypeContext>. Neste mtodo devemos passar instncias do tipo System.Data.Entity.IDatabaseInitializer. No EF 4.1 temos 3 classes que denem estratgias para criao do banco de dados: DropCreateDatabaseAlways criar o banco de dados a cada instncia criada do contexto, ideal para ambiente de testes. CreateDatabaseIfNotExists somente criar o banco de dados, caso ele no exista, este a estratgia padro. www.k19.com.br 46

Entity Framework 4.1 DropCreateDatabaseIfModelChanges somente criar o banco de dados caso ele no exista ou caso haja alguma alterao nas suas entidades.
1 2 3 4 5 6 //Alterando a estratgia padro Database.SetInitializer<EditoraContext>(new DropCreateDatabaseIfModelChanges< EditoraContext>()); EditoraContext context = new EditoraContext(); // Neste momento ser criado o banco de dados, caso no exista context.Editoras.Add(new Editora{ Nome = "Abril" });

3.7

Exerccios

1. Crie um projeto do tipo Console Application no Microsoft Visual C# Express, chamado EF4-Code-First.

2. Adicione as seguintes dlls ao projeto: EntityFramework.dll e System.ComponentModel.DataAnnotations

47

K19 Treinamentos

Entity Framework 4.1

www.k19.com.br

48

Entity Framework 4.1

3. Dena uma classe Editora conforme cdigo abaixo:

1 2 3 4 5 6 7 8 9 10 11

namespace EF4_Code_First { public class Editora { public int Id { get; set; } public string Nome { get; set; } public string Email { get; set; } } }

4. Dena uma classe EditoraContext que derivada de DbContext. Nesta classe dena uma propriedade Editoras do tipo genrico DbSet<Editora>. 49 K19 Treinamentos

Entity Framework 4.1


1 2 3 4 5 6 7 8 9 10

using System.Data.Entity; namespace EF4_Code_First { public class EditoraContext : DbContext { public DbSet<Editora> Editoras { get; set; } } }

5. Dena uma classe GeraTabelas conforme cdigo abaixo:


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

namespace EF4_Code_First { class GeraTabelas { static void Main(string[] args) { using (var context = new EditoraContext()) { // Neste momento as tabelas so geradas context.Editoras.Add(new Editora { Nome = "Abril", Email = "abril@email .com" }); } } } }

Atravs do SQL Server Management Express verique se a tabela E DITORAS foi criada corretamente.

3.8

Sobrescrevendo o nome do Banco de Dados

Quando executamos a aplicao, o EF4_Code_First.EditoraContext foi criado. Uma maneira de sobrescrever a conveno do Code First para nome de banco de dados adicionar um arquivo App.cong ou Web.cong que contenha a string de conexo juntamente com a classe do contexto. O arquivo .cong pode ser acrescentado no projeto que contm o assembly tambm. Para adicionar o App.cong ao projeto pelo Microsoft Visual C# Express basta clicar com o boto direito do mouse no projeto e clicar em Add, posteriormente escolher Application Conguration File. Acrescente o connectionStrings ao seu arquivo:
1 2 3 4 5 6 7

<connectionStrings> <add name="EditoraContext" providerName="System.Data.SqlClient" connectionString="Server=.\SQLEXPRESS;Database=livraria; Trusted_Connection=true;Integrated Security=True;MultipleActiveResultSets=True"/> </connectionStrings>

Quando a aplicao for executada, o banco de dados livraria ser criado. Devemos habilitar a opo MultipleActiveResultSets=True para permitir a leitura de objetos relacionados em www.k19.com.br 50

Entity Framework 4.1 blocos foreach do C#, pois o EF tenta criar um novo leitor de dados e ocorrer uma falha de execuo a menos que a opo MultipleActiveResultSets seja true. Uma outra maneira de fazer a leitura dos objetos relacionados dentro do bloco foreach atravs de uma List, que fecha o leitor de dados e permite voc percorrer a coleo e acessar os objetos relacionados.

3.9

Exerccios

6. Remova o banco de dados EF4_Code_First.EditoraContext. 7. Sobrescreva a conveno do Code First para nome de banco de dados. Para isto acrescente ao projeto EF4-Code-First o arquivo App.cong com a denio da string de conexo.

3.10

Manipulando entidades

Para manipular as entidades da nossa aplicao, devemos utilizar uma classe derivada de D B C ONTEXT.
1 2 var context = new EditoraContext();

3.10.1

Persistindo

Para armazenar as informaes de um objeto no banco de dados basta utilizar o mtodo S A do D B C ONTEXT. As entidades com o estado Added so inseridas no banco de dados quando o mtodo S AVE C HANGES () chamado. Utilize o mtodo System.Data.Entity.DbSet.Add. O mtodo Add adiciona a entidade ao contexto com o estado Added.
VE C HANGES ()
1 2 3 4 5 6 7 8 using (var context = new EditoraContext()) { Editora editora = new Editora { Nome = "Abril", Email = "abril@email.com" }; //Adiciona o estado Added context.Editoras.Add(editora); context.SaveChanges(); }//fecha o contexto ao final

3.10.2

Buscando

Para obter um objeto que contenha informaes do banco de dados basta utilizar o mtodo Find do D B S ET.
1 Editora editora = context.Editoras.Find(1);

51

K19 Treinamentos

Entity Framework 4.1

3.10.3

Removendo

As entidades com o estado Deleted so removidas do banco de dados quando o mtodo S AVE C HANGES () chamado. Utilize o mtodo System.Data.Entity.DbSet.Remove. O mtodo Remove remove a entidade do contexto e adiciona a entidade o estado Deleted.
1 2 3 Editora editora = context.Editoras.Find(1); context.Editoras.Remove(editora); context.SaveChanges();

3.10.4

Atualizando

Para alterar os dados de um registro correspondente a um objeto basta utilizar as propriedades. Quando as propriedades de uma entidade do contexto alterada, o estado Modied adicionado a esta entidade. Entidades com o estado Modied so atualizados no banco de dados quando o mtodo SaveChanes chamado.
1 2 3 Editora editora = context.Editoras.Find(1); editora.Nome = "Abril S/A"; context.SaveChanges();

3.10.5

Listando

Para obter uma listagem com todos os objetos referentes aos registros de uma tabela, podemos utilizar o Language Integrated Query LIN Q, que permite os desenvolvedores escreverem a consulta em C#.
1 2 3 4 5 6 7 8 var consulta = from e in context.Editoras where e.Nome.Contains("A") select e; // Equivalente a: SELECT * FROM Editoras e where e.Nome Like A% foreach (var item in consulta) { System.Console.WriteLine("Editora: " + item.Nome); }

3.11

Exerccios

8. Crie um teste para inserir editoras no banco de dados. www.k19.com.br 52

Entity Framework 4.1


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 using System; namespace EF4_Code_First { class InsereEditoraComEF { static void Main(string[] args) { using (var context = new EditoraContext()) { Editora editora = new Editora(); Console.WriteLine("Digite o nome da Editora:"); editora.Nome = Console.ReadLine(); Console.WriteLine("Digite o email da Editora:"); editora.Email = Console.ReadLine(); //Adiciona editora ao contexto //Status: Added context.Editoras.Add(editora); //Persisto editora context.SaveChanges(); } } } }

9. Crie um teste para listar as editoras inseridas no banco de dados.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 using System; using System.Linq; namespace EF4_Code_First { class ListaEditoraComEF { static void Main(string[] args) { using (EditoraContext context = new EditoraContext()) { var consulta = from e in context.Editoras select e; foreach (var item in consulta) { Console.WriteLine("{0}: {1} - {2}", item.Id,item.Nome,item.Email); } } } } }

3.12

Repository

A classe D B C ONTEXT e D B S ET do EF oferece recursos sucientes para que os objetos do domnio sejam recuperados ou persistidos no banco de dados. Porm, em aplicaes com alta complexidade e grande quantidade de cdigo, espalhar as chamadas aos mtodos do D B C ONTEXT e D B S ET pode gerar diculdades na manuteno e no entendimento do sistema. Para melhorar a organizao das nossas aplicaes, diminuindo o custo de manuteno e aumentando a legibilidade do cdigo, podemos aplicar o padro Repository do DDD(Domain 53 K19 Treinamentos

Entity Framework 4.1 Driven Design). Conceitualmente, um repositrio representa o conjunto de todos os objetos de um determinado tipo. Ele deve oferecer mtodos para recuperar e para adicionar elementos. Os repositrios podem trabalhar com objetos prontos na memria ou reconstru-los com dados obtidos de um banco de dados. O acesso ao banco de dados pode ser realizado atravs de ferramenta ORM como o Entity Framework.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 using using using using System; System.Collections.Generic; System.Linq; System.Data.Entity;

namespace EF4_Code_First { public class EditoraRepository { DbContext context; public EditoraRepository(DbContext context) { this.context = context; } public void Adiciona(Editora e) { context.Set<Editora>().Add(e); context.SaveChanges(); } public Editora Busca(int id) { return context.Set<Editora>().Find(id); } public List<Editora> BuscaTodas() { var consulta = from e in context.Set<Editora>() select e; return consulta.ToList(); } } }

1 2 3 4 5 6 7

Database.SetInitializer<EditoraContext>(new DropCreateDatabaseIfModelChanges< EditoraContext>()); var context = new EditoraContext(); EditoraRepository repository = new EditoraRepository(context); List<Editora> editoras = repository.BuscaTodas();

3.13

Exerccios

10. Implemente um repositrio de editoras criando uma nova classe no projeto EF4-CodeFirst. www.k19.com.br 54

Entity Framework 4.1


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class EditoraRepository { DbContext context; public EditoraRepository(DbContext context) { this.context = context; } public void Adiciona(Editora e) { context.Set<Editora>().Add(e); context.SaveChanges(); } public Editora Busca(int id) { return context.Set<Editora>().Find(id); } public List<Editora> BuscaTodas() { var consulta = from e in context.Set<Editora>() select e; return consulta.ToList(); } }

11. Altere a classe InsereEditoraComEF para que ela utilize o repositrio de editoras.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 using System; namespace EF4_Code_First { class InsereEditoraComEF { static void Main(string[] args) { var context = new EditoraContext(); EditoraRepository repository = new EditoraRepository(context); Editora editora = new Editora(); Console.WriteLine("Digite o nome da Editora:"); editora.Nome = Console.ReadLine(); Console.WriteLine("Digite o email da Editora:"); editora.Email = Console.ReadLine(); repository.Adiciona(editora); } } }

12. (Opcional) Altere a classe ListaEditoraComEF para que ela utilize o repositrio de editoras.

55

K19 Treinamentos

Entity Framework 4.1

www.k19.com.br

56

Captulo 4 Viso Geral do ASP .NET MVC


4.1 Necessidades de uma aplicao web

As aplicaes web so acessadas pelos navegadores (browsers). A comunicao entre os navegadores e as aplicaes web realizada atravs de requisies e respostas denidas pelo protocolo HTTP. Portando, ao desenvolver uma aplicao web, devemos estar preparados para receber requisies HTTP e enviar respostas HTTP. Alm disso, na grande maioria dos casos, as aplicaes web devem ser acessadas por diversos usurios simultaneamente. Dessa forma, o desenvolvedor web precisa saber como permitir o acesso simultneo. Outra necessidade das aplicaes web gerar contedo dinmico. Por exemplo, quando um usurio de uma aplicao de email acessa a sua caixa de entrada, ele deseja ver a listagem atualizada dos seus emails. Portanto, fundamental que a listagem dos emails seja gerada no momento da requisio do usurio. O desenvolvedor web precisa utilizar algum mecanismo eciente que permita que o contedo que os usurios requisitam seja gerado dinamicamente. Trabalhar diretamente com as requisies e repostas HTTP e criar um mecanismo eciente para permitir o acesso simultneo e para gerar contedo dinmico no so tarefas simples. Na verdade, extremamente trabalhoso implementar essas caractersticas. Por isso, a plataforma .NET oferece uma soluo para diminuir o trabalho no desenvolvimento de aplicaes web.

4.2

Viso Geral do ASP .NET MVC

O ASP .NET MVC oferece muitos recursos para o desenvolvimento de uma aplicao web .NET. Cada um desses recursos por si s j so sucientemente grandes e podem ser abordados em separado. Porm, no primeiro contato com ASP .NET MVC, interessante ter uma viso geral dos recursos principais e do relacionamento entre eles sem se aprofundar em muito nos detalhes individuais de cada recurso. Portanto, neste captulo, mostraremos de forma sucinta e direta o funcionamento e os conceitos principais do ASP .NET MVC. Nos prximos captulos, discutiremos de maneira mais detalhada as diversas partes do ASP .NET MVC. 57

Viso Geral do ASP .NET MVC

4.3

Aplicao de exemplo

O primeiro passo para construir uma aplicao web utilizando ASP .NET MVC criar um projeto no Visual Web Developer a partir do modelo adequado. No nosso caso, o modelo de projeto que deve ser utilizado o ASP.NET MVC 3 Web Application.

Devemos escolher Empty Project conforme gura abaixo:

O projeto criado j vem com diversas pastas e arquivos. Ao longo dos prximos captulos, a funo de cada pasta e de cada arquivo ser discutida. www.k19.com.br 58

Viso Geral do ASP .NET MVC

4.3.1

Testando a aplicao

Para vericar o funcionamento do projeto, basta execut-lo atravs do menu: Debug -> Start Debugging. Automaticamente um servidor de desenvolvimento inicializado na mquina e a aplicao implantada nesse servidor. Alm disso, uma janela do navegador padro do sistema aberta na url principal da aplicao. O servidor pode ser nalizado atravs do cone ASP.NET Development Server que ca na barra de tarefas do Windows.

4.3.2

Trocando a porta do servidor

Para trocar a porta utilizada pelo servidor de desenvolvimento que o Visual Web Developer utiliza, basta alterar as propriedades do projeto clicando com o boto direito do mouse no projeto e escolhendo o item properties e depois a aba web.

4.4

Pgina de Saudao

Comearemos o desenvolvimento da nossa livraria virtual criando uma pgina de saudao. Essa pgina deve conter uma mensagem diferente de acordo com o horrio atual. Para implementar a pgina de saudao, devemos criar um Controlador que receber as requisies vindas do navegador do usurio e devolver um hipertexto XHTML gerado dinamicamente. A base de todos os controladores System.Web.Mvc.ControllerBase. A implementao padro desta classe abstrata System.Web.Mvc.Controller. Para criar nosso controlador, devemos criar uma classe que seja lha de System.Web.Mvc.Controller e o nome obrigatoriamente deve conter o suxo Controller.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // LivrariaVirtual/Controllers/SaudacaoController.cs using System; using System.Web.Mvc; using System.Web.Routing; namespace LivrariaVirtual.Controllers { public class SaudacaoController : Controller { public string Index() { return "Welcome to ASP.NET MVC!"; } } }

Por padro, a url que deve ser utilizada para enviar uma requisio a um controlador a concatenao da url principal da aplicao seguido do nome do controlador (ex: http: //localhost/Saudacao). Por conveno, o arquivo cs contendo o cdigo da classe do controlador deve ser colocado na pasta Controllers. 59 K19 Treinamentos

Viso Geral do ASP .NET MVC

4.5

Exerccios

1. Crie um projeto do tipo ASP.NET MVC 3 Web Application chamado LivrariaVirtual. Crie um Empty Project. 2. Implemente uma pgina de saudao criando uma classe dentro da pasta Controllers chamada SaudacaoController.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

using System.Web.Mvc; namespace LivrariaVirtual.Controllers { public class SaudacaoController : Controller { // // GET: /Saudacao/ public string Index() { return "Welcome to ASP.NET MVC!"; } } }

4.6

Alterando a pgina inicial

Por padro, as requisies direcionadas a url principal da aplicao so enviadas ao controlador Home. Podemos alterar esse comportamento, modicando o arquivo de rotas da aplicao, o Global.asax. Este cdigo:
1 new { controller = "Home", action = "Index", id = UrlParameter.Optional }

Deve ser substitudo por este:


1 new { controller = "Saudacao", action = "Index", id = UrlParameter.Optional }

4.7

Exerccios

3. Altere a pgina inicial da nossa aplicao para a pgina de saudao criada no exerccio anterior.

4.8

Integrando o Banco de Dados

A nossa aplicao web vai interagir com o banco de dados para recuperar ou armazenar informao. Vimos que a comunicao com uma base de dados pode ser encapsulada atravs www.k19.com.br 60

Viso Geral do ASP .NET MVC do padro Repository. Os Repositorys e as classes que representam as entidades do sistema da livraria virtual devem ser colocadas na pasta Models do projeto web.

4.9

Exerccios

4. Copie as classes Repository e as classes de entidades implementadas no captulo ADO.NET para a pasta Models da nossa aplicao web. Coloque cada classe separada em um arquivo com o mesmo nome da classe.

1 2 3 4 5 6 7 8 9 10 11 12 13

using System.Collections.Generic; namespace LivrariaVirtual.Models { public class Editora { public int Id { get; set; } public string Nome { get; set; } public string Email { get; set; } public virtual ICollection<Livro> Livros { get; set; } } }

1 2 3 4 5 6 7 8 9 10 11 12

namespace LivrariaVirtual.Models { public class Livro { public int Id { get; set; } public string Titulo { get; set; public decimal Preco { get; set; public int EditoraId { get; set; public virtual Editora Editora { } }

} } } get; set; }

1 2 3 4 5 6 7 8 9 10 11

using System.Data.Entity; namespace LivrariaVirtual.Models { public class LivrariaVirtualContext : DbContext { public DbSet<Editora> Editoras { get; set; } public DbSet<Livro> Livros { get; set; } } }

61

K19 Treinamentos

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

using System.Collections.Generic; using System.Linq; namespace LivrariaVirtual.Models { public class LivroRepository { private LivrariaVirtualContext context = new LivrariaVirtualContext(); public void Adiciona(Livro e) { context.Livros.Add(e); context.SaveChanges(); } public Livro Busca(int id) { return context.Livros.Find(id); } public List<Livro> BuscaTodas() { var consulta = from e in context.Livros select e; return consulta.ToList(); } } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

using System.Collections.Generic; using System.Linq; namespace LivrariaVirtual.Models { public class EditoraRepository { private LivrariaVirtualContext context public void Adiciona(Editora e) { context.Editoras.Add(e); context.SaveChanges(); } public Editora Busca(int id) { return context.Editoras.Find(id); } public List<Editora> BuscaTodas() { var consulta = from e in context.Editoras select e; return consulta.ToList(); } } }

= new LivrariaVirtualContext();

www.k19.com.br

62

Viso Geral do ASP .NET MVC

4.10

Listando entidades

Uma funcionalidade bsica que a nossa aplicao web deve oferecer para os usurios a listagem das entidades do sistema (livro e editora). Para cada entidade, ser criado um controlador que car encarregado de montar a lista da entidade correspondente. Vamos construir um exemplo que lista as editoras a partir da URL /Editoras.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 using using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class EditorasController : Controller { // // GET: /Editoras/ public ActionResult Index() { var editoraRepository = new EditoraRepository(); return View(editoraRepository.BuscaTodas()); } } }

Repare que o controlador responsvel pela lista de editoras interage com o repository de Editora. Alm disso, ele envia uma lista de editoras para a pgina atravs do mtodo View. Para listar as editoras que foram passados como parmetro pelo EditorasController devemos criar uma pgina com o mesmo nome da action Index. Alm disso, esta pgina deve ser criada, por conveno, dentro de uma pasta Editoras, pasta com o mesmo nome do nosso controller sem o suxo Controller, dentro da pasta Views.

63

K19 Treinamentos

Viso Geral do ASP .NET MVC

www.k19.com.br

64

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

@model IList<LivrariaVirtual.Models.Editora> @{ ViewBag.Title = "Editoras"; } <h2>Editoras</h2> <table> <tr> <th> Nome </th> <th> Email </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Nome) </td> <td> @Html.DisplayFor(modelItem => item.Email) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.Id }) </td> </tr> } </table>

Para gerar o contedo dinmico de nossa pgina, estamos utilizando Razor que permite acrescentar cdigo de servidor juntamente com cdigo HTML de forma mais clara e concisa. No ASP .NET MVC temos os Helpers que so classes que facilitam a criao de uma pgina e renderizao de elementos HTML. Na nossa pgina Index estamos utilizando a propriedade Html que uma instncia da classe System.Web.Mvc.HtmlHelper que prov mtodos para renderizar elementos como input, select, anchor, form. Veremos com mais detalhes os Helpers e Razor nos captulos posteriores.

4.11

Exerccios

5. Implemente um controlador chamado EditorasController para que liste todas as editoras existentes na base de dados quando a url /Editoras for requisitada. 6. Implemente um controlador chamado LivrosController para que liste todas as editoras existentes na base de dados quando a url /Livros for requisitada.

4.12

Inserindo entidades

Outra funcionalidade fundamental que a aplicao web deve oferecer aos usurios o cadastro de editoras e livros. O primeiro passo, para implementar essa funcionalidade, criar um 65 K19 Treinamentos

Viso Geral do ASP .NET MVC formulrio de cadastro de editora e outro de livro. Por exemplo, suponha que para criar uma editora devemos acessar a url /Editoras/Create. Primeiro devemos criar uma mtodo para action Create no nosso controlador EditorasController que redirecionar para a pgina que contm o formulrio, quando acessarmos a url /Editoras/Create pelo browser atravs de requisio GET. Por conveno, o nome do mtodo o mesmo nome da action.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

using using using using using using

System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class EditorasController : Controller { // // GET: /Editoras/ public ActionResult Index() { var editoraRepository = new EditoraRepository(); return View(editoraRepository.BuscaTodas()); } // // GET: /Editoras/Create public ActionResult Create() { return View(); } } }

Devemos agora criar a pgina que contm o formulrio para inserir uma editora. Por padro, esta pgina dever ser criada na pasta View/Editoras com o mesmo nome da action, portanto deveremos ter um arquivo com o nome Create.cshtml. www.k19.com.br 66

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (@Html.BeginForm()) { <fieldset> <legend>Editora</legend> <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> }

Quando o usurio clicar no boto "submit", uma action dever receber a requisio com os dados preenchidos no formulrio pelo usurio. Os dados sero enviados atravs de uma requisio POST, por padro , e deveremos ter uma action Create que receber os dados de uma requisio POST. Por conveno, deveremos ter no nosso controlador um mtodo com o mesmo nome da action e restringiremos o mtodo para tratar somente requisies POST com a anotao HttpPost. Neste mtodo faremos a insero da editora atravs da classe EditoraRepository. 67 K19 Treinamentos

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 using using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class EditorasController : Controller { private EditoraRepository editoraRepository = new EditoraRepository(); // // GET: /Editoras/ public ActionResult Index() { return View(this.editoraRepository.BuscaTodas()); } // // GET: /Editoras/Create public ActionResult Create() { return View(); } // // POST: /Editoras/Create [HttpPost] public ActionResult Create(Editora editora) { editoraRepository.Adiciona(editora); return RedirectToAction("Index"); } } }

4.13

Exerccios

7. Crie um mtodo para action Create no nosso controlador EditorasController responsvel por apresentar um formulrio de cadastramento de editoras. Este formulrio dever ser acessado atravs de uma URL /Editoras/Create. Ao enviar os dados do formulrio para o servidor atravs de uma requisio POST, dena um mtodo para esta action que receba estes dados enviados pelo usurio e salve na base de dados utilizando a nossa classe EditoraRepository. 8. Crie um mtodo para action Create no nosso controlador LivrosController responsvel por apresentar um formulrio de cadastramento de livros. Este formulrio dever ser acessado atravs de uma URL /Livros/Create. Ao enviar os dados do formulrio para o servidor atravs de uma requisio POST, dena um mtodo para esta action que receba estes dados enviados pelo usurio e salve na base de dados utilizando a nossa classe LivroRepository. www.k19.com.br 68

Viso Geral do ASP .NET MVC Devemos permitir que o usurio possa denir a editora a qual o livro pertence. Para isto, devemos ter uma caixa de seleo com todas as editoras da nossa base de dados. Antes de criar a caixa de seleo, devemos enviar uma lista para a nossa View, atravs da propriedade ViewBag, com todas as editoras da nossa base de dados.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

using using using using using using using using

System; System.Collections.Generic; System.Data; System.Data.Entity; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class LivrosController : Controller { private LivroRepository livroRepository = new LivroRepository(); private EditoraRepository editoraRepository = new EditoraRepository(); // // GET: /Livros/ public ViewResult Index() { return View(livroRepository.BuscaTodas()); } // // GET: /Livros/Create public ActionResult Create() { var consulta = editoraRepository.BuscaTodas().Select(e => new { e.Id, e. Nome}); ViewBag.Editoras = consulta.ToList(); return View(); } // // POST: /Livros/Create [HttpPost] public ActionResult Create(Livro livro) { livroRepository.Adiciona(livro); return RedirectToAction("Index"); }

} }

Para construir a nossa caixa de seleo, podemos utilizar o mtodo DropDownListFor da propriedade Html. 69 K19 Treinamentos

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

@model LivrariaVirtual.Models.Livro @{ ViewBag.Title = "Insere Livro"; } <h2>Insere Livro</h2> @using (Html.BeginForm()) { <fieldset> <legend>Livro</legend> <div class="editor-label"> @Html.LabelFor(model => model.Titulo) </div> <div class="editor-field"> @Html.EditorFor(model => model.Titulo) </div> <div class="editor-label"> @Html.LabelFor(model => model.Preco) </div> <div class="editor-field"> @Html.EditorFor(model => model.Preco) </div> <div class="editor-label"> @Html.LabelFor(model => model.EditoraId) </div> <div class="editor-field"> @Html.DropDownListFor(model => model.EditoraId,new SelectList(@ViewBag. Editoras, "Id", "Nome")) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> }

4.14

Alterando entidades

Normalmente surge a necessidade de atualizar os dados de uma editora ou livro. Por exemplo, uma atualizao dos preos. Portanto, a nossa aplicao deve permitir que o usurio faa alteraes nos livros e nas editoras. Suponha que para alterar as informaes da editora, o usurio precise acessar a URL /Editoras/Edit/1, onde o 1 (um) dene o ID da editora que o usurio deseje alterar as informaes e ser passado como parmetro na nossa action. O primeiro passo denir um mtodo para a action Edit no controlador EditorasController que receber o Id da editora fornecido pelo usurio e encaminhar para o formulrio de edio. www.k19.com.br 70

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

using using using using using using

System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class EditorasController : Controller { private EditoraRepository editoraRepository = new EditoraRepository(); // // GET: /Editoras/ public ActionResult Index() { return View(this.editoraRepository.BuscaTodas()); } // // GET: /Editoras/Create public ActionResult Create() { return View(); } // // POST: /Editoras/Create [HttpPost] public ActionResult Create(Editora editora) { editoraRepository.Adiciona(editora); return RedirectToAction("Index"); } // // GET: /Editoras/Edit/5 public ActionResult Edit(int id) { Editora editora = editoraRepository.Busca(id); return View(editora); }

} }

O formulrio de edio dever vir preenchido com as informaes da editora que o usurio deniu. Para isto, passamos como parmetro editora no mtodo View e acessamos atravs da propriedade Model. 71 K19 Treinamentos

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

@model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { <fieldset> <legend>Editora</legend> @Html.HiddenFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> }

Ao submeter o formulrio, requisio POST por padro, devemos ter um mtodo para esta action que receber os dados enviados e far a alterao em nossa base de dados. www.k19.com.br 72

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

using using using using using using

System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class EditorasController : Controller { private EditoraRepository editoraRepository = new EditoraRepository(); // // GET: /Editoras/ public ActionResult Index() { return View(this.editoraRepository.BuscaTodas()); } // // GET: /Editoras/Create public ActionResult Create() { return View(); } // // POST: /Editoras/Create [HttpPost] public ActionResult Create(Editora editora) { editoraRepository.Adiciona(editora); return RedirectToAction("Index"); } // // GET: /Editoras/Edit/5 public ActionResult Edit(int id) { Editora editora = editoraRepository.Busca(id); return View(editora); } // // POST: /Editoras/Edit/5 [HttpPost] public ActionResult Edit(Editora e) { editoraRepository.Atualiza(e); return RedirectToAction("Index"); } } }

Devemos acrescentar na nossa classe EditoraRepository o mtodo Atualiza. 73 K19 Treinamentos

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

using System.Collections.Generic; using System.Linq; using System.Data; namespace LivrariaVirtual.Models { public class EditoraRepository { private LivrariaContext context public void Adiciona(Editora e) { context.Editoras.Add(e); context.SaveChanges(); } public void Atualiza(Editora e) { context.Entry(e).State = EntityState.Modified; context.SaveChanges(); } public Editora Busca(int id) { return context.Editoras.Find(id); } public List<Editora> BuscaTodas() { var consulta = from e in context.Editoras select e; return consulta.ToList(); } } }

= new LivrariaContext();

4.14.1

Link de alterao

Nas listagens de editoras e livros, podemos acrescentar um link alterao para cada item. Para isso, devemos alterar as pginas de listagem. www.k19.com.br 74

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

@model IList<LivrariaVirtual.Models.Editora> @{ ViewBag.Title = "Editoras"; } <h2>Editoras</h2> <table> <tr> <th> Nome </th> <th> Email </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Nome) </td> <td> @Html.DisplayFor(modelItem => item.Email) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.Id }) </td> </tr> } </table>

4.15

Exerccios

9. Implemente um mtodo para a action Edit no controlador EditorasController que ser responsvel por apresentar um formulrio para a atualizao de uma editora. Ao submeter o formulrio devemos ter um mtodo para esta action que receber os dados enviados e far a alterao em nossa base de dados. No esquea da modicar a pgina que lista as editoras para chamar o formulrio de edio atravs de um link.

10. Implemente um mtodo para a action Edit no controlador LivrosController que ser responsvel por apresentar um formulrio para a atualizao de um livro. Ao submeter o formulrio devemos ter um mtodo para esta action que receber os dados enviados e far a alterao em nossa base de dados. No esquea da modicar a pgina que lista os livros para chamar o formulrio de edio atravs de um link. No LivrosController devemos ter: 75 K19 Treinamentos

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

// // GET: /Livros/Edit/5 public ActionResult Edit(int id) { Livro livro = livroRepository.Busca(id); var consulta = editoraRepository.BuscaTodas().Select(e => new { e.Id, e.Nome }); ViewBag.Editoras = consulta.ToList(); ViewBag.editora = new Editora { Nome = "iuiuiu" }; return View(livro); } // // POST: /Editoras/Edit/5 [HttpPost] public ActionResult Edit(Livro l) { livroRepository.Atualiza(l); return RedirectToAction("Index"); }

Classe LivroRepository:

1 2 3 4 5 6

public void Atualiza(Livro l) { context.Entry(l).State = EntityState.Modified; context.SaveChanges(); }

A pgina Edit.cshtml: www.k19.com.br 76

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

@model LivrariaVirtual.Models.Livro @{ ViewBag.Title = "Edit"; } <h2>Alterar Livro</h2> @using (Html.BeginForm()) { <fieldset> <legend>Livro</legend> @Html.HiddenFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Titulo) </div> <div class="editor-field"> @Html.EditorFor(model => model.Titulo) </div> <div class="editor-label"> @Html.LabelFor(model => model.Preco) </div> <div class="editor-field"> @Html.EditorFor(model => model.Preco) </div> <div class="editor-label"> @Html.LabelFor(model => model.EditoraId) </div> <div class="editor-field"> @Html.DropDownListFor(model => model.EditoraId, new SelectList(ViewBag. Editoras,"Id","Nome")) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> }

4.16

Removendo entidades

Para nalizar nosso conjunto de funcionalidades bsicas, implementaremos a remoo de entidades. Para isso podemos adicionar um link de remover para cada item das listagens de editoras e livros. Assim como zemos com os links de alterao. Segue a listagem de Editoras acrescentando o link de remoo: 77 K19 Treinamentos

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @model IList<LivrariaVirtual.Models.Editora> @{ ViewBag.Title = "Editoras"; } <h2>Editoras</h2> <table> <tr> <th> Nome </th> <th> Email </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Nome) </td> <td> @Html.DisplayFor(modelItem => item.Email) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.Id }) </td> <td> @Html.ActionLink("Delete", "Delete", new { id=item.Id }) </td> </tr> } </table>

Depois de acrescentado o link de remoo nas listas, o prximo passo implementar os mtodos para estas actions nos controladores que faro a remoo atravs das classes Repository. www.k19.com.br 78

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 using using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class EditorasController : Controller { private EditoraRepository editoraRepository = new EditoraRepository(); // // GET: /Editoras/Delete/5 public ActionResult Delete(int id) { Editora editora = editoraRepository.Busca(id); return View(editora); } // // POST: /Editoras/Delete/5 [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { Editora editora = editoraRepository.Busca(id); editoraRepository.Remove(editora); return RedirectToAction("Index"); } } }

Ao enviar uma requisio POST atravs da URL /Editoras/Delete/5, o mtodo que tratar esta action ser o DeleteConrmed. Para isto, renomeamos a action com a anotao ActionName, pois por padro a action contm o mesmo nome do mtodo do controlador. Precisamos tambm denir uma pgina de conrmao da remoo da entidade: 79 K19 Treinamentos

Viso Geral do ASP .NET MVC


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Apagar Editora"; } <h2>Apagar Editora</h2> <h3>Voc tem certeza que deseja apagar esta editora?</h3> <fieldset> <legend>Editora</legend> <div class="display-label">Nome</div> <div class="display-field"> @Html.DisplayFor(model => model.Nome) </div> <div class="display-label">Email</div> <div class="display-field"> @Html.DisplayFor(model => model.Email) </div> </fieldset> @using (Html.BeginForm()) { <p> <input type="submit" value="Delete" /> | @Html.ActionLink("Voltar para listagem de Editoras", "Index") </p> }

4.17

Exerccios

11. Implemente os mtodos para as actions de remoo no EditorasController que sero responsveis por remover uma editora. No se esquea de modicar a pgina de listagem de editoras para incluir o link de remoo. 12. Implemente os mtodos para as actions de remoo no LivrosController que sero responsveis por remover um livro. No se esquea de modicar a pgina de listagem de livros para incluir o link de remoo.

www.k19.com.br

80

Captulo 5

Tratamento de Erros

Inevitavelmente, as aplicaes esto sujeitas a erros de vrias naturezas. Por exemplo, erros gerados pelo preenchimento incorreto do campos de um formulrio. Esse tipo de erro causado por falhas dos usurios. Nesse caso, importante mostrar mensagens informativas com o intuito de fazer o prprio usurio corrigir os valores preenchidos incorretamente.

Por outro lado, h erros que no so causados por falhas dos usurios. Por exemplo, um erro de conexo com o banco de dados. Nesses casos, improvvel que os usurios possam fazer algo que resolva o problema. E mesmo que pudessem, provavelmente, no seria conveniente esperar que eles o zessem.

Quando um erro desse tipo ocorre, o ASP.NET cria uma pgina web com informaes sobre o erro e a envia aos usurios. Para usurios locais, o ASP.NET envia uma pgina web com informaes detalhadas do erro ocorrido. Para usurios remotos, a pgina web enviada no contm informaes detalhadas. 81

Tratamento de Erros

Em geral, no conveniente que os usurios recebam detalhes tcnicos sobre os erros gerados por falhas da aplicao. A primeira justicativa que esses detalhes podem confundir os usurios. A segunda justicativa que esses detalhes podem expor alguma falha de segurana da aplicao deixando a mais vulnervel a ataques.

5.1

Try-Catch

Os erros de aplicao podem ser identicados atravs do comando try-catch que pode ser colocado nos mtodos das actions dos controladores. Ao identicar a ocorrncia de um erro, os controladores podem mostrar uma pgina web com alguma mensagem para o usurio. www.k19.com.br 82

Tratamento de Erros
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [HttpPost] public ActionResult Create(Editora editora) { try { this.editoraRepository.Adiciona(editora); } catch { return View("Error"); } return RedirectToAction("Index"); }

Devemos criar uma pgina Error.cshtml, por padro, na pasta Views/Shared:


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Erro</title> </head> <body> <h2> Servidor com problemas </h2> <p> Houve um problema no nosso servidor.<br/> Por favor tente novamente dentro de alguns instantes. </p> </body> </html>

As pginas de erro que sero mostradas pelos controladores teriam uma mensagem simples informando que houve um erro na aplicao e que no possvel atender a requisio do usurio naquele momento. Inclusive, seria conveniente padronizar a pgina de erro. Em outras palavras, todos os controladores teriam que mostrar a mesma pgina.

5.2

Exerccios

1. Altere o cdigo do mtodo da action Create do controlador EditorasController para capturar erros usando try-catch.

5.3

Custom Errors

Utilizar o comando try-catch nos controladores para lidar com os erros de aplicao no uma boa alternativa pois o cdigo do controlador ca mais complexo. Alm disso, haveria replicao de cdigo nos controladores pois provavelmente a pgina de erro seria padronizada. 83 K19 Treinamentos

Tratamento de Erros Qualquer alterao na pgina de erro implicaria em alteraes em todos os controladores. Por exemplo, se a mensagem tivesse que ser trocada. Para lidar com os erros de aplicao de uma maneira mais prtica e fcil de manter, podemos congurar o ASP.NET para utilizar pginas de erro padro. O primeiro passo alterar o arquivo de congurao Web.cong, acrescentando a tag customErrors dentro da tag system.web.
1 2 <customErrors mode="On"> </customErrors>

O atributo mode da tag customErrors pode assumir trs valores: On: A pgina de erro padro ser enviada para usurios locais ou remotos. Off: A pgina de erro detalhada ser enviada para usurios locais ou remotos. RemoteOnly: A pgina de erro detalhada ser enviada para usurios locais e a padro para os remotos. Por conveno, o ASP .NET MVC mantm uma pgina de erro padro dentro da pasta Views/Shared com o nome Error.cshtml. Vamos alterar este arquivo, o contedo da pgina de erro basicamente XHTML.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Erro</title> </head> <body> <h2> Servidor com problemas </h2> <p> Houve um problema no nosso servidor.<br/> Por favor tente novamente dentro de alguns instantes. </p> </body> </html>

5.4

Exerccios

2. Congure nossa aplicao para utilizar pginas de erro padro. Lembre-se que no vamos mais precisar do comando try-catch colocado no exerccio anterior.

5.5

Erros do HTTP

Um dos erros mais conhecidos do HTTP o 404 que ocorre quando o navegador faz uma requisio por uma url que no existe. Basicamente, esse erro gerado por falhas dos usurios www.k19.com.br 84

Tratamento de Erros ao tentarem digitar diretamente uma url na barra de endereo dos navegadores ou por links ou botes quebrados nas pginas da aplicao. Quando o erro 404 ocorre, o ASP.NET utiliza a pgina padro para erros de aplicao congurada no Web.cong atravs da tag customErrors. Porm, esse erro no deve ser considerado um erro de aplicao pois ele pode ser gerado por falhas dos usurios. Ele tambm no deve ser considerado um erro de usurio pois ele pode ser gerado por falhas da aplicao. Consequentemente, comum tratar o erro 404 de maneira particular criando uma pgina de erro especca para ele.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

@{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Arquivo no encontrado!</title> </head> <body> <h2> Esse arquivo no foi encontrado. Verifique se a url est correta. </h2> </body> </html>

No arquivo de congurao, podemos determinar uma pgina web especca para o erro 404 ou para os outros erros do HTTP.

1 2 3

<customErrors mode="On"> <error statusCode="404" redirect="~/ErrorPages/NotFound"/> </customErrors>

Devemos denir uma controlador com o nome ErrorPages, por padro, alm do mtodo para a action NotFound.

1 2 3 4 5 6 7 8 9 10 11 12 13 14

using System.Web.Mvc; namespace LivrariaVirtual.Controllers { public class ErrorPagesController : Controller { public ActionResult NotFound() { return View(); } } }

85

K19 Treinamentos

Tratamento de Erros

5.6

Exerccios

3. Crie uma pgina de erro e um controlador especco para o erro 404 e modique o arquivo Web.cong para fazer redirecionamento apropriado.

www.k19.com.br

86

Captulo 6 Camada de Apresentao (View)


A responsabilidade da camada de apresentao relativamente simples. Seu principal objetivo gerar o contedo atravs do modelo. No importa como o controlador obteve atravs de servios e lgica de negcios os dados que foram necessrios a construo do objeto do nosso modelo, a camada de apresentao apenas precisa saber como obter o modelo e gerar o contedo HTML atravs dele. Para desenvolver a camada de aplicao necessrio conhecimento de HTML, CSS e JavaScript. A camada de apresentao responsvel por gerar o contedo da nossa aplicao web e este contedo dinmico. Mostraremos neste captulo, como podemos gerar contedo dinmico atravs de funcionalidades do ASP .NET MVC como Inline Code, HTML Helper e Partial Views.

6.1

Inline Code

A maneira mais simples de gerar contedo dinmico atravs de inline code - que so blocos de cdigo inseridos entre tags como (<% ... %>). Tags existentes tambm no PHP, Rails, JSP, que permite voc inserir uma lgica simples para gerar o contedo dinmico. No ASP .NET MVC 3 podemos inserir cdigo C# na View utilizando o Razor ao invs do tradicional ASPX que obriga colocar o cdigo entre <% ... %>. A principal caracterstica do Razor ser conciso e simples, diminuindo o nmero de caracteres e tags scripts na View, pois diferentemente de outras sintaxes, no h necessidade de explicitar no cdigo HTML um bloco de cdigo de servidor. Segue abaixo alguns exemplos cdigo utilizando Razor e o equivalente em ASPX: Bloco de cdigo:
1 2 3 4 5 //Razor @{ int x = 123; string nome = "Marcelo"; }

87

Camada de Apresentao (View)


1 2 3 4 5 //ASPX <% int x = 123; string nome = "Marcelo."; %>

Expresso:
1 2 <!-- Razor --> <span>@model.Nome</span>

1 2

<!-- ASPX --> <span><%= model.Nome %></span>

Texto e HTML
1 2 3 4 <!-- Razor --> @foreach(var item in editoras) { <span>@item.Nome</span> }

1 2 3 4

<!-- ASPX --> <% foreach(var item in editoras) { %> <span><%= item.Nome %></span> <% } %>

Cdigo e texto
1 2 3 4 <!-- Razor --> @if (foo) { @:Plain Text e @editora.Nome }

1 2 3 4

<!-- ASPX --> <% if (foo) { %> Plain Text e <%= editora.Nome %> <% } %>

Comentrios
1 2 3 4 <!-- Razor --> @* Comentrio *@

www.k19.com.br

88

Camada de Apresentao (View)


1 2 3 4 <!-- ASPX --> <%-Comentrio --%>

Alternando expresses e textos

1 2

<!-- Razor --> Livro: @livro.Titulo - R$@livro.Preco.

1 2

<!-- ASPX --> Livro: <%= livro.Titulo %> - R$<%= livro.Preco %>

6.2

Utilizando Inline Code

Suponha que tenhamos uma pgina EditoraDetails.cshtml e queremos mostrar as informaes de um objeto da classe Editora:

1 2 3 4 5 6 7 8

public class Editora { public int Id { get; set; } public string Nome { get; set; } public string Email { get; set; } public virtual ICollection<Livro> Livros { get; set; } }

Para mostrar as informaes da editora, utilizaremos a pgina EditoraDetails.cshtml e a deniremos como strongly typed view (veremos strongly typed views posteriormente) atravs do inline code: @model <seu namespace>.Editora. 89 K19 Treinamentos

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

@model LivrariaVirtual.Models.Editora @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>@Model.Nome </title> </head> <body> <h1>Editora @Model.Nome</h1> <div> Contato: @Model.Email </div> <h3>Livros:</h3> <ul> @foreach(var livro in @Model.Livros) { <li> <b>@livro.Titulo</b> - R$ @livro.Preco </li> } </ul> </body> </html>

Deveremos ter a seguinte tela:

www.k19.com.br

90

Camada de Apresentao (View)

6.3

ViewData, ViewBag e Model

No ASP .NET MVC, o controlador consegue fornecer dados a View atravs de:

Dicionrio: Atravs do ViewDataDictionary podemos fornecer dados atravs de key>value. Key string e value object. Por exemplo: ViewData["livros"] = livroRepository.BuscaTodas();

Propriedade Model: Cada ViewDataDictionary contm um propriedade Model que armazena uma referncia para um objeto qualquer. Podemos acessar este objeto atravs da palavra Model em nossa View, ao invs de ViewData.Model (ambos apontam para o mesmo objeto).

1 2 3 4 5 6 7 8 9 10 11

// // GET: /Livros/Edit/5 public ActionResult Edit(int id) { Livro livro = livroRepository.Busca(id); ViewData["Mensagem"] = "Hora Atual: " + DateTime.Now.ToShortTimeString(); ViewData["Editoras"] = editoraRepository.BuscaTodas(); //Equivalente a: ViewData.Model = livro; return View(livro); }

No ASP .NET MVC 3 podemos utilizar ViewBag ao invs de ViewData. ViewBag uma coleo dinmica que permite o envio de dados do controlador para a View. O suporte a coleo dinmica fruto do suporte a tipos dinmicos do .NET 4. Segue um exemplo de ViewBag:
1 2 3 4 5 6 7 8 9 10 11 // // GET: /Livros/Edit/5 public ActionResult Edit(int id) { Livro livro = livroRepository.Busca(id); ViewBag.Mensagem = "Hora Atual: " + DateTime.Now.ToShortTimeString(); ViewBag.Editoras = editoraRepository.BuscaTodas(); //Equivalente a: ViewData.Model = livro; return View(livro); }

Segue abaixo um exemplo da nossa View strongly-typed (a classe esperada do Model Livro): 91 K19 Treinamentos

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46

@model LivrariaVirtual.Models.Livro @{ ViewBag.Title = "Edit"; } <h2>Alterar Livro</h2> @using (Html.BeginForm()) { <fieldset> <legend>Livro</legend> @Html.HiddenFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Titulo) </div> <div class="editor-field"> @Html.TextBoxFor(model => model.Titulo) </div> <div class="editor-label"> @Html.LabelFor(w => w.Preco) </div> <div class="editor-field"> @Html.EditorFor(model => model.Preco) </div> <div class="editor-label"> @Html.LabelFor(model => model.EditoraId) </div> <div class="editor-field"> @Html.DropDownListFor(model => model.EditoraId, new SelectList(ViewBag. Editoras,"Id","Nome")) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @ViewBag.Mensagem </div>

A combinao do controlador e View acima ir gerar o seguinte response HTML: www.k19.com.br 92

Camada de Apresentao (View)

6.4

HTML Helpers

A funo das pginas .cshtml gerar hipertexto XHTML para enviar aos navegadores dos usurios. Os arquivos .cshtml misturam tags XHTML com scripts de servidor escritos em C# (ou outra linguagem de programao suportada pelo .NET). Essa mistura pode prejudicar a legibilidade do cdigo em alguns casos. Veja o exemplo da listagem de editoras.
1 2 3 4 5 6 7 8 9 10 11 12

<ul> @foreach(var e in Model) { <li> @e.Nome - @e.Email <a href="/Editoras/Edit/@e.Id">alterar</a> <a href="/Editoras/Delete/@e.Id">remover</a> </li> } </ul>

Para aumentar a legibilidade das pginas .cshtml e consequentemente facilitar a manuteno da aplicao, o ASP.NET oferece os chamados HTML Helpers. A funo de um HTML Helper encapsular um cdigo XHTML. Por exemplo, para adicionar um link podemos usar o mtodo ActionLink do objeto Html, ao invs, da tag <a>. 93 K19 Treinamentos

Camada de Apresentao (View)


1 @Html.ActionLink("Veja os Livros", "Index", "Livros")

6.4.1

ActionLink Helper

O helper ActionLink utilizado para gerar os links das pginas web. Esse helper aceita vrios parmetros e a maneira mais simples de utiliz-lo passar a ele dois parmetros: o texto do link e a ao que ser chamada.
1 @Html.ActionLink("TEXTO PARA O USURIO", "ACTION" )

Caso queiramos acrescentar um link para redirecionar para um outro controlador, devemos acrescentar um terceiro parmetro:
1 @Html.ActionLink("TEXTO PARA O USURIO", "ACTION", "CONTROLADOR" )

O ActionLink permite que parmetros sejam adicionados no link gerado. Para isso, basta acrescentar um parmetro.
1 @Html.ActionLink("TEXTO PARA O USURIO", "ACTION", new {controller = "CONTROLADOR", param = "valor"} )

6.4.2

Helpers de Formulrios

Para facilitar a criao dos elementos de entrada de dados, h um conjunto de HTML Helpers. Para criar um formulrio, podemos utilizar o Helper BeginForm. H duas maneiras para criar o formulrio com o BeginForm: Denindo o Html.BeginForm() e Html.EndForm():
1 2 3 4 5 @{Html.BeginForm();} <!-- Elementos de Formulrio --> @{Html.EndForm();}

Utilizando o bloco using:


1 2 3 4 5 @using(Html.BeginForm()) { <!-- Elementos de Formulrio --> }

Caso no especiquemos parmetros na chamada do mtodo BeginForm, o formulrio enviar uma requisio para a mesma URL da requisio atual. www.k19.com.br 94

Camada de Apresentao (View) Ou podemos passar como parmetro a action e o controlador:


1 2 3 4 5 @using(Html.BeginForm("ACTION", "CONTROLADOR")) { <!-- Elementos de Formulrio --> }

Por padro, o formulrio enviar uma requisio POST. Devemos denir no nosso controlador o mtodo que ir receber esta requisio.
1 2 3 4 5 6 7 8 // // POST: /Editoras/Create [HttpPost] public ActionResult Create(Editora editora) { this.editoraRepository.Adiciona(editora); return RedirectToAction("Index"); }

Para denir os campos do nosso formulrio, podemos utilizar os HTML Helpers stringbased: Check Box:
1 2 3 4 5 <!-- Check Box Helper --> @Html.CheckBox("meuCheckBox", false) <!-- Sida: --> <input id="meuCheckBox" name="myCheckbox" type="checkbox" value="true" /> <input name="meuCheckBox" type="hidden" value="false" />

Text Box:
1 2 3 4 <!-- Text Box Helper --> @Html.TextBox("meuTextbox", "valor") <!-- Sida: --> <input id="meuTextbox" name="meuTextbox" type="text" value="valor" />

Text Area:
1 2 3 4 <!-- Text Area Helper --> @Html.TextArea("meuTextarea", "valor") <!-- Sida: --> <textarea cols="20" id="meuTextarea" name="meuTextarea" rows="2">valor</textarea>

Radio Button:
1 2 3 4 <!-- Radio Button Helper --> @Html.RadioButton("meuRadiobutton", "valor", true) <!-- Sida: --> <input checked="checked" id="meuRadiobutton" name="meuRadiobutton" type="radio" value=" valor" />

Hidden Field: 95 K19 Treinamentos

Camada de Apresentao (View)


1 2 3 4 <!-- Hidden Field Helper --> @Html.Hidden("meuHidden", "valor") <!-- Sida: --> <input id="meuHidden" name="meuHidden" type="hidden" value="valor" />

Password Field:
1 2 3 4 <!-- Password Field Helper --> @Html.Password("meuPassword", "valor") <!-- Sida: --> <input id="meuPassword" name="meuPassword" type="password" value="valor" />

Utilizando HTML Helpers strongly typed: Check Box:


1 2 3 4 5 <!-- Check Box Helper --> @Html.CheckBoxFor(x => x.IsAtivo) <!-- Sida: --> <input id="IsAtivo" name="IsAtivo" type="checkbox" value="true" /> <input name="IsAtivo" type="hidden" value="false" />

Text Box:
1 2 3 4 <!-- Text Box Helper --> @Html.TextBoxFor(x => x.Nome) <!-- Sida: --> <input id="Nome" name="Nome" type="text" value="Valor do Nome" />

Text Area:
1 2 3 4 <!-- Text Area Helper --> @Html.TextAreaFor(x => x.Descricao) <!-- Sida: --> <textarea cols="20" id="Descricao" name="Descricao" rows="2">Valor da Descricao</ textarea>

Radio Button:
1 2 3 4 <!-- Radio Button Helper --> @Html.RadioButtonFor(x => x.IsAtivo, "valor") <!-- Sida: --> <input checked="checked" id="IsAtivo" name="IsAtivo" type="radio" value="valor" />

Hidden Field:
1 2 3 4 <!-- Hidden Field Helper --> @Html.HiddenFor(model => model.Id) <!-- Sida: --> <input id="Id" name="Id" type="hidden" value="Valor do Id" />

Password Field: www.k19.com.br 96

Camada de Apresentao (View)


1 2 3 4 <!-- Password Field Helper --> @Html.PasswordFor(x => x.Password) <!-- Sida: --> <input id="Password" name="Password" type="password"/>

Suponha que tenhamos o seguinte exemplo:


1 @Html.TextBox("Nome")

Isto equivalente a:
1 @Html.TextBox("Nome", ViewData.Eval("Nome"))

Caso a key Nome da ViewDataDictionary da pgina no exista, o valor deste elemento ser preenchido com ViewData.Model.Nome. Lembrando que para acessar o value associado a key, podemos utilizar, por exemplo, ViewBag.Nome, equivalente a ViewData["Nome"]. No caso de Helpers HTML strongly typed, o valor do elemento ser sempre associado a propriedade ViewData.Model da pgina.

6.4.3

DropDownList Helper

No cadastramento dos livros, os usurios podem escolher uma editora. A editora selecionada atravs de um drop down list. Para criar um drop down list, podemos utilizar um HTML Helper. O primeiro passo para utilizar o DropDownList criar uma SelectList no controlador.
1 2 3 4 5 6 7 8 9 // // GET: /Livros/Edit/5 public ActionResult Edit(int id) { Livro livro = livroRepository.Busca(id); List<Editora> editoras = editoraRepository.BuscaTodas(); ViewBag.EditoraId = new SelectList(editoras,"Id","Nome"); return View(livro); }

O segundo passo adicionar o drop down list na pgina .cshtml.


1 2 3 4 5 <!-- String Based Helper --> @Html.DropDownList("EditoraId") <!-- Strongly Typed Helper --> @Html.DropDownListFor(model => model.EditoraId, ViewBag.EditoraId as SelectList)

Pelo fato do Helper HTML strongly typed Drop Down List no aceitar tipos dinmicos, devemos fazer o cast para SelectList. 97 K19 Treinamentos

Camada de Apresentao (View)

6.4.4

Editor Helper

Suponha que tenhamos o seguinte exemplo:


1 2 3 4 5 6 7 8 public class Editora { public int Id { get; set; } public string Nome { get; set; } public string Email { get; set; } public bool IsAtivo { get; set; } public virtual ICollection<Livro> Livros { get; set; } }

Para editar o cadastro de uma editora, teramos uma pgina Edit.cshtml conforme exemplo abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Editora</legend> @Html.HiddenFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.TextBoxFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.TextBoxFor(model => model.Email) </div> <div class="editor-label"> @Html.LabelFor(model => model.IsAtivo) </div> <div class="editor-field"> @Html.CheckBoxFor(model => model.IsAtivo) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

Para cada propriedade do nosso modelo Editora, denimos um Helper apropriado para gerar www.k19.com.br 98

Camada de Apresentao (View) o elemento HTML para a entrada de dados. Por exemplo, no caso da propriedade Nome e Email utilizamos o Helper Text Box, j para a propriedade booleana IsAtivo utilizamos CheckBox.

Temos a seguinte tela:

Podemos utilizar o Helper Editor que dene o Helper HTML apropriado de acordo com o tipo da propriedade. Para propriedades e valores do tipo booleano, o helper utilizado ser o Check Box, j para elementos do tipo string, o helper o Text Box.

Podemos editar a nossa pgina Edit.cshtml para utilizar o Helper Editor: 99 K19 Treinamentos

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Editora</legend> @Html.EditorFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) </div> <div class="editor-label"> @Html.LabelFor(model => model.IsAtivo) </div> <div class="editor-field"> @Html.EditorFor(model => model.IsAtivo) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

Teremos a seguinte tela: www.k19.com.br 100

Camada de Apresentao (View)

Podemos perceber que a tela cou "parecida", porm para a propriedade Id foi denido o Helper Text Box e o mais apropriado o Helper Hidden. O Helper Editor no consegue denir em todos os casos, o Helper mais apropriado. Para casos especcos, o ASP .NET MVC prov templates para denir o Helper mais apropriado para determinada propriedade do nosso modelo. Por exemplo, para a propriedade Id, devemos acrescentar uma anotao indicando que para esta propriedade queremos utilizar o Helper Hidden.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 using System.Collections.Generic; using System.Web.Mvc; namespace LivrariaVirtual.Models { public class Editora { [HiddenInput(DisplayValue = false)] public int Id { get; set; } public string Nome { get; set; } public string Email { get; set; } public bool IsAtivo { get; set; } public virtual ICollection<Livro> Livros { get; set; } } }

Na propriedade Id acrescentamos a anotao System.Web.Mvc.HiddenInputAttribute que denir para esta propriedade o Helper Hidden. Com isto, teremos a seguinte tela: 101 K19 Treinamentos

Camada de Apresentao (View)

Os templates para entrada de dados so: Template HiddenInput Text String Password MultilineText Boolean Descrio Utiliza o Helper Hidden Utiliza o Helper Text Utiliza o Helper TextBox Utiliza o Helper Password Utiliza o Helper TextArea Utiliza o Helper CheckBox ou DropDownList para nullable boolean Utiliza o Helper TextBox e formata para duas casas decimais Percorre as propriedades do objeto e dene o Helper apropriado para cada uma Percorre atravs do IEnumerable e dene o Helper para cada elemento

Decimal Object

Collection

Tambm temos o Helper EditorForModel que percorrer todas as propriedades do ViewData.Model associado a pgina, e denir o Helper apropriado para cada uma das propriedades. www.k19.com.br 102

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Editora</legend> @Html.EditorForModel() <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

6.5

Exerccios

1. Utilize o projeto LivrariaVirtual denido nos captulos anteriores. 2. Altere o mtodo da action Edit do controlador Editoras para enviar a informao da hora do servidor.
1 2 3 4 5 6 7 8 9 // // GET: /Editoras/Edit/5 public ActionResult Edit(int id) { Editora editora = editoraRepository.Busca(id); ViewBag.Hora = DateTime.Now.ToShortTimeString(); return View(editora); }

3. Altere a View Editora.cshtml para mostrar a hora do servidor.

1 2 3 4

<!-- Mostrando a hora atual --> <div> Hora atual: @ViewBag.Hora </div>

4. Altere a View Editora.cshtml para utilizar somente Helpers string based. 103 K19 Treinamentos

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Editora</legend> @Html.Hidden("Id") <div class="editor-label"> @Html.Label("Nome") </div> <div class="editor-field"> @Html.TextBox("Nome") </div> <div class="editor-label"> @Html.Label("Email") </div> <div class="editor-field"> @Html.TextBox("Email") </div> <div class="editor-label"> @Html.Label("IsAtivo") </div> <div class="editor-field"> @Html.CheckBox("IsAtivo") </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <!-- Mostrando a hora atual --> <div> Hora atual: @ViewBag.Hora </div> <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

5. Acrescente o seguinte trecho cdigo ao controlador Editoras e verique o que acontece ao acessar a tela de edio de editoras.
1 2 3 4 5 6 7 8 9 10 // // GET: /Editoras/Edit/5 public ActionResult Edit(int id) { Editora editora = editoraRepository.Busca(id); ViewBag.Hora = DateTime.Now.ToShortTimeString(); ViewBag.Nome = "Prioridade mais alta"; return View(editora); }

www.k19.com.br

104

Camada de Apresentao (View) 6. Altere a pgina Edit.cshtml de Editoras para utilizar o helper Editor.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

@model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Editora</legend> @Html.EditorFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) </div> <div class="editor-label"> @Html.LabelFor(model => model.IsAtivo) </div> <div class="editor-field"> @Html.EditorFor(model => model.IsAtivo) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <!-- Mostrando a hora atual --> <div> Hora atual: @ViewBag.Hora </div> <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

7. Altere a classe Editora para que o Helper Editor dena o Helper Hidden para a propriedade Id. 105 K19 Treinamentos

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 using System.Collections.Generic; using System.Web.Mvc; namespace LivrariaVirtual.Models { public class Editora { [HiddenInput(DisplayValue=false)] public int Id { get; set; } public string Nome { get; set; } public string Email { get; set; } public bool IsAtivo { get; set; } public virtual ICollection<Livro> Livros { get; set; } } }

8. Altere a pgina Editora.cshtml para utilizar o Helper EditorForModel.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

@model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Editora</legend> @Html.EditorForModel() <p> <input type="submit" value="Save" /> </p> </fieldset> } <!-- Mostrando a hora atual --> <div> Hora atual: @ViewBag.Hora </div> <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

6.6

Master Pages

comum que as pginas de uma aplicao web possuam contedo em comum (por exemplo: um cabealho ou um rodap). O contedo em comum pode ser replicado em todas as pginas atravs do CTRL+C e CTRL+V. Porm, essa no uma boa abordagem pois quando alguma alterao precisa ser realizada, todos os arquivos devem ser modicados. Tambm comum que as pginas de uma aplicao web possuam um certo padro visual. Da surge o conceito de Master Page. www.k19.com.br 106

Camada de Apresentao (View)

6.6.1

Contedo comum

Tudo que comum a todas as pginas de um determinado grupo pode ser denido em uma Master Page. Dessa forma, qualquer alterao facilmente realizada modicando apenas um arquivo. Por exemplo, suponha que toda pgina da aplicao web da livraria virtual deva ter o mesmo ttulo e a mesma formatao. Podemos criar uma Master Page com o ttulo utilizado nas pginas e com a referncia ao arquivo CSS que dene a formatao padro.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!-- Views/Shared/LivrariaLayout.cshtml --> <!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> @Html.ActionLink("Editoras", "Index","Editoras") @Html.ActionLink("Livros", "Index","Livros") </div> @RenderBody() </body> </html>

Alguns detalhes: Estamos acrescentando @RenderBody() que indica onde o contedo das pginas ser encaixado. No title acrescentamos @ViewBag.Title, isto permitir que o title seja especco a cada pgina. O prximo passo indicar quais pginas utilizaro essa Master Page. Por exemplo, podemos atualizar a pgina Edit.cshtml de Editoras para utilizar a LivrariaLayout.cshtml como layout principal:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @model LivrariaVirtual.Models.Editora @{ Layout = "~/Views/Shared/LivrariaLayout.cshtml"; //Define o title especfico desta pgina ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using(Html.BeginForm()) { <fieldset> <legend>Editora</legend> @Html.EditorForModel() <p> <input type="submit" value="Save" /> </p> </fieldset> }

107

K19 Treinamentos

Camada de Apresentao (View) A pgina Edit.cshtml executada antes de LivrariaLayout.cshtml, o que permitiu acrescentarmos valor ao ViewBag.Title. Isto tambm facilita na denio de elementos meta e head, por exemplo, para ns de SEO. Para denir o layout de Edit.cshtml foi necessrio acrescentar o caminho completo a propriedade Layout. Este procedimento no muito prtico, pois em cada pgina devemos denir esta propriedade. No ASP .NET MVC 3, temos uma nova funcionalidade que permitir denir um layout padro a todas as pginas no havendo necessidade de denir a propriedade Layout em cada uma. Basta acrescentarmos a pasta View o arquivo _ViewStart.cshtml:

O _ViewStart.cshtml permite denirmos um cdigo que ser executado antes de cada View ser renderizada. Podemos denir, por exemplo, a propriedade Layout:
1 2 3 @{ Layout = "~/Views/Shared/LivrariaLayout.cshtml"; }

Como este cdigo executado no incio de cada view, no h mais necessidade de denir a propriedade Layout em cada pgina.

6.6.2

Lacunas

Tambm podemos criar lacunas na Master Page para serem preenchidas com contedos denidos nas pginas. Segue a pgina LivrariaLayout.cshtml: www.k19.com.br 108

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> @Html.ActionLink("Editoras", "Index","Editoras") @Html.ActionLink("Livros", "Index","Livros") </div> <div id="sidebar">Sidebar padro</div> <div id="content">@RenderBody()</div> <div id="footer">Livraria Virtual</div> </body> </html>

Acrescente o cdigo abaixo ao arquivo Content/Site.css:

Com isto, teremos uma tela conforme a gura abaixo: 109 K19 Treinamentos

Camada de Apresentao (View)

Para especicar uma lacuna em nosso layout, devemos utilizar o helper @RenderSection(string Nome Da Seo, bool Obrigatoriedade):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> @Html.ActionLink("Editoras", "Index","Editoras") @Html.ActionLink("Livros", "Index","Livros") </div> <!-- Definindo a lacuna "Sidebar" e indicando que opcional (false) --> <div id="sidebar">@RenderSection("sidebar",false)</div> <div id="content">@RenderBody()</div> <div id="footer">Livraria Virtual</div> </body> </html>

Para denir a seo Sidebar, devemos utilizar o cdigo @section. Segue a pgina Edit.cshtml de Editoras: www.k19.com.br 110

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @model LivrariaVirtual.Models.Editora @{ Layout = "~/Views/Shared/LivrariaLayout.cshtml"; //Define o title especfico desta pgina ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using(Html.BeginForm()) { <fieldset> <legend>Editora</legend> @Html.EditorForModel() @section Sidebar { <p>Sidebar do cadastro de Edio de Editora</p> } <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

Com isto, ao acessar o formulrio de edio de Editoras, teremos a seguinte tela:

Porm, ao acessar a tela de listagem de Editoras, temos a seguinte tela: 111 K19 Treinamentos

Camada de Apresentao (View)

Para no car este buraco, podemos denir um seo padro para casos em que as pginas no deniram uma seo especca. Para isto, devemos fazer uma vericao na pgina LivrariaLayout.cshtml atravs do mtodo IsSectionDened():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> @Html.ActionLink("Editoras", "Index","Editoras") @Html.ActionLink("Livros", "Index","Livros") </div> @if (IsSectionDefined("Sidebar")) { <div id="sidebar">@RenderSection("Sidebar", false)</div> } else { <div id="sidebar">Sidebar padro</div> } <div id="content">@RenderBody()</div> <div id="footer">Livraria Virtual</div> </body> </html>

6.7

Exerccios

9. Utilize o projeto LivrariaVirtual para resolver os exerccios a seguir. www.k19.com.br 112

Camada de Apresentao (View) 10. Crie uma pgina que servir de layout para a nossa aplicao.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <!-- ~/Views/Shared/LivrariaLayout.cshtml --> <!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> @Html.ActionLink("Editoras", "Index","Editoras") @Html.ActionLink("Livros", "Index","Livros") </div> @RenderBody() </body> </html>

11. Altere a pgina Edit.cshtml de Editoras para utilizar a pgina de layout denido no exerccio anterior.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @model LivrariaVirtual.Models.Editora @{ Layout = "~/Views/Shared/LivrariaLayout.cshtml"; ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using(Html.BeginForm()) { <fieldset> <legend>Editora</legend> @Html.EditorForModel() <p> <input type="submit" value="Save" /> </p> </fieldset> }

12. Dena a pgina LivrariaLayout.cshtml como layout padro de cada view.


1 2 3 4 <!-- Basta criar a pgina _ViewStart.cshtml na pasta Views --> @{ Layout = "~/Views/Shared/LivrariaLayout.cshtml"; }

13. Dena sees na pgina LivrariaLayout.cshtml. Para isto, acrescente ao arquivo Site.css na pasta Content o trecho de cdigo a seguir: 113 K19 Treinamentos

Camada de Apresentao (View)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> @Html.ActionLink("Editoras", "Index","Editoras") @Html.ActionLink("Livros", "Index","Livros") </div> <div id="sidebar">SideBar Padro</div> <div id="content">@RenderBody()</div> <div id="footer">Livraria Virtual</div> </body> </html>

14. Acrescente uma lacuna a pgina LivrariaLayout.cshtml. www.k19.com.br 114

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> @Html.ActionLink("Editoras", "Index","Editoras") @Html.ActionLink("Livros", "Index","Livros") </div> <div id="sidebar">@RenderSection("Sidebar", required:false)</div> <div id="content">@RenderBody()</div> <div id="footer">Livraria Virtual</div> </body> </html>

15. Dena na pgina Edit.cshtml de Editoras a seo Sidebar.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

@model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @using(Html.BeginForm()) { <fieldset> <legend>Editora</legend> @Html.EditorForModel() @section Sidebar { <p>Sidebar do cadastro de Edio de Editora</p> } <p> <input type="submit" value="Save" /> </p> </fieldset> }

16. Acrescente uma seo padro as pginas que no deniram a seo Sidebar. 115 K19 Treinamentos

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> @Html.ActionLink("Editoras", "Index","Editoras") @Html.ActionLink("Livros", "Index","Livros") </div> @if (IsSectionDefined("Sidebar")) { <div id="sidebar">@RenderSection("Sidebar", required: false)</div> } else { <div id="sidebar">Sidebar padro</div> } <div id="content">@RenderBody()</div> <div id="footer">Livraria Virtual</div> </body> </html>

6.8

Importao Automtica

Quando necessrio utilizar uma classe ou interface nas pginas .cshtml, devemos acrescentar a diretiva using adequada. Algumas classes e interfaces so utilizadas em muitas pginas. Para no ter que adicionar a diretiva de importao em todas as pginas, podemos alterar o arquivo de congurao (Web.cong) da pasta Views fazendo com que todas as pginas j tenham acesso a determinados namespaces.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <system.web.webPages.razor> <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version =3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> <pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="System.Linq"/> <add namespace="System.Collections.Generic"/> <add namespace="LivrariaVirtual.Models"/> </namespaces> </pages> </system.web.webPages.razor>

www.k19.com.br

116

Camada de Apresentao (View)

6.9

Exerccios

17. Edite o arquivo Web.cong da pasta Views para fazer as importaes de bibliotecas automaticamente.

6.10

Dividindo o contedo

Quanto mais elaborada uma pgina web maior o seu cdigo. Quando o cdigo muito extenso a sua legibilidade ca prejudicada. Para organizar melhor o cdigo, podemos dividir o contedo de uma pgina web em vrios arquivos .cshtml. Suponha que desejamos dividir o contedo de uma pgina em duas partes. Devemos criar um arquivo para cada parte. Normalmente, esses arquivos possuem a exteso .ascx.
1 2 3 <%-- Parte1.cshtml --%> <h1> Parte 1 </h> <p> Contedo da parte1</p>

1 2 3

<%-- Parte2.cshtml --%> <h1> Parte 2 </h> <p> Contedo da parte2</p>

Por m, devemos criar um arquivo .cshtml principal para agrupar as partes. Utilizaremos o mtodo Partial para inserir o contedo dos arquivos secundrios no arquivo principal.
1 2 3 4 5 6 7 8 9 10 <html> <head> <title>Exemplo de partial</title> </head> <body> Html.Partial("Parte1") Html.Partial("Parte2") </body> </html>

O mtodo Partial procura o arquivo Parte1.cshtml e Parte2.cshtml no mesmo diretrio do arquivo principal. Caso ele no encontre, ele procura o arquivo na pasta Views/Shared. Isto serve tambm para o mtodo View que utilizamos no controlador. O Partial View permite criarmos contedo reutilizvel de forma mais clara e concisa. As informaes entre as Views e Partial Views podem ser compartilhadas atravs da ViewBag. Podemos, por exemplo, alterar as pginas Create.cshtml e Edit.cshtml de Editoras para acrescentar uma partial view do formulrio, pois ambas as pginas compartilham o mesmo formulrio. 117 K19 Treinamentos

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <!-- ~/Views/Editoras/_Form.cshtml --> @model LivrariaVirtual.Models.Editora <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></ script> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Editora</legend> @if (Model != null) { @Html.EditorFor(model => model.Id) } <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) </div> <div class="editor-label"> @Html.LabelFor(model => model.IsAtivo) </div> <div class="editor-field"> @Html.EditorFor(model => model.IsAtivo) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> }

Segue o cdigo das pginas de Create.cshtml e Edit.cshtml:

1 2 3 4 5 6 7 8 9 10

<!-- ~/Views/Editora/Create.cshtml --> @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Cadastro de Editora"; } <h2>Cadastro de Editora</h2> @Html.Partial("_Form")

www.k19.com.br

118

Camada de Apresentao (View)


1 2 3 4 5 6 7 8 9 10 <!-- ~/Views/Editora/Edit.cshtml --> @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @Html.Partial("_Form")

6.11

Exerccios

18. Crie uma partial view para o formulrio de Editora.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <!-- ~/Views/Editoras/_Form.cshtml --> @model LivrariaVirtual.Models.Editora <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></ script> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Editora</legend> @if (Model != null) { @Html.EditorFor(model => model.Id) } <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) </div> <div class="editor-label"> @Html.LabelFor(model => model.IsAtivo) </div> <div class="editor-field"> @Html.EditorFor(model => model.IsAtivo) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> }

119

K19 Treinamentos

Camada de Apresentao (View) 19. Altere as pginas Create.cshtml e Edit.cshtml de Editoras para utilizar a partial view _Form.cshtml.
1 2 3 4 5 6 7 8 9 10 <!-- ~/Views/Editora/Create.cshtml --> @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Cadastro de Editora"; } <h2>Cadastro de Editora</h2> @Html.Partial("_Form")

1 2 3 4 5 6 7 8 9 10

<!-- ~/Views/Editora/Edit.cshtml --> @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Edio de Editora"; } <h2>Edio de Editora</h2> @Html.Partial("_Form")

www.k19.com.br

120

Captulo 7 Controle (Controller)


No ASP .NET MVC as URLs so mapeadas para classes que so chamadas de controllers. Os controladores (controllers) processam as requisies, recebem dados enviados pelos usurios, executam comandos para recuperar dados do modelo e chamam a view apropriada para gerar o HTML para a requisio. Os requisitos para uma classe ser considerada controller : O nome deve terminar com o suxo Controller A classe deve implementar a interface IController ou herdar da classe System.Web.Mvc.Controller Raramente voc denir uma classe controller implementando a interface IController. Comumente deniremos uma classe controller herdando de System.Web.Mvc.Controller.

7.1

Actions

Nas aplicaes ASP .NET que no utilizam MVC, as interaes do usurio em torno das pginas, em torno de eventos vindos da pgina e de seus controles. No ASP .NET MVC a interao do usurio em torno dos controllers e actions. Uma classe controller contm mtodos que so as actions. Uma action utilizada para processar uma requisio HTTP e ela pode conter 0 (zero) ou mais argumentos. Para criar uma action preciso denir o mtodo como public e , na maioria das vezes, o valor de retorno ser uma instncia de uma classe que deriva de ActionResult. Quando o usurio faz uma requisio atravs do Browser, o ASP .NET MVC verica na tabela de rotas, denido no arquivo Global.asax, o controller que ir receber a requisio. O controller ir denir o mtodo apropriado para processar a requisio. Por padro, as URLs seguem a estrutura {NomeDoControlador}/{NomeDaAction}. Caso o usurio acesse a URL http://www.exemplo.com/Editoras/Listagem, por padro, Editoras ser considerado como o prexo do nome do controller (EditorasController, o controlador termina com o suxo Controller) e Listagem como o nome da action. Ao acessar a url /Editoras/Alterar/1, por padro, Alterar ser considerado uma action do controller EditorasController e 1 ser enviado como parmetro para o mtodo Alterar. Exemplo de uma classe controller que contm uma action HelloWorld: 121

Controle (Controller)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 using System.Web.Mvc; namespace LivrariaVirtual.Controllers { public class HomeController : Controller { // // GET: /Home/HelloWorld public ActionResult HelloWorld() { ViewBag.Mensagem = "Hello World!"; return View(); } } }

7.2

ActionResult

Aps o controller receber a requisio e process-la, ele devolve uma resposta para o usurio. O controller responde basicamente de trs maneiras: Retorna uma resposta HTML ao chamar uma View Redireciona o usurio atravs do HTTP Redirect Retorna a resposta em outro formato. Por exemplo: XML, Json, arquivo binrio No ASP .NET MVC temos uma classe apropriada para cada tipo de retorno que derivada de ActionResult. www.k19.com.br 122

Controle (Controller) Action Result ViewResult Descrio Retorna uma View Exemplo return View(); return View(NomeDaView, objetoModel); return PartialView(); return PartialView(NomeDaPartialView, objetoModel); return Redirect(http://www.k19.com.br); return RedirectToAction(OutraAction, OutroController); return RedirectToRoute(NomeDaRota); return Content(Texto,text\plain); return Json(objeto); return JavaScript($(#divResultText). html(JavaScript Passed);); return File(@c:\relatorio.pdf, application\pdf); return new EmptyResult();

PartialViewResult

RedirectResult RedirectToRouteResult

Retorna uma partial View, que pode ser inserida dentro de outra View Redireciona para uma URL especca Redireciona para outra action

ContentResult JsonResult JavaScriptResult

FileResult

EmptyResult

Retorna texto, contenttype header opcional Retorna um objeto no formato JSON Retorna cdigo Javascript que pode ser executado no cliente Retorna dados binrios (arquivo em disco, por exemplo) Retorna um valor que utilizado quando a action precisa retornar valor nulo

7.3

Parmetros

Vimos que os parmetros enviados pelos usurios podem ser recuperados nos controladores atravs da propriedade Request.
1 string nome = Request["nome"];

Mas, h outras maneiras de recuperar esses valores.

7.3.1

Vrios parmetros

Uma das maneiras de recuperar os dados enviados pelos usurios denir um parmetro C# para cada parmetro HTTP enviado pelo usurio. necessrio denir os parmetros C# com o mesmo nome dos parmetros HTTP. 123 K19 Treinamentos

Controle (Controller)
1 2 3 4 5 6 7 8 9 10 11 12 <html> <head> <title>Cadastro de Editora</title> </head> <body> <form action="/Editoras/Salva" method="post"> Nome: <input type="text" name="nome"/> Email: <input type="text" name="email"/> <input type="submit" /> </form> </body> </html>

1 2 3 4 5 6 7

[HttpPost] public ActionResult Salva(string nome, string email) { Editora editora = new Editora { Nome = nome, Email = email }; editoraRepository.Adiciona(editora); return View(); }

7.3.2

Por objeto

O ASP.NET tambm capaz de montar objetos com os valores dos parmetros HTTP enviados pelo usurio e pass-los como argumento aos controladores.
1 2 3 4 5 6 [HttpPost] public ActionResult Salva(Editora e) { editoraRepository.Adiciona(e); return View(); }

As propriedades dos objetos recebidos como argumentos nos mtodos dos controladores precisam ter os mesmos nomes dos parmetros HTTP.

7.4

Exerccios

1. Adicione no controlador Editoras do projeto LivrariaVirtual uma action para visualizar o formulrio de cadastro.
1 2 3 4 public ActionResult Cadastra() { return View(); }

2. Crie uma pgina Cadastra.cshtml de cadastro de editoras na pasta Views/Editoras conforme exemplo abaixo: www.k19.com.br 124

Controle (Controller)
1 2 3 4 5 6 7 <h2>Cadastro de Editoras</h2> <form action="/Editoras/Salva"> Nome: <input name="nome" /> Email: <input name="email" /> <input type="submit" value="Enviar" /> </form>

3. Dena um mtodo para action Salva no controlador Editoras que ir receber os dados enviados pelo usurio e adicionar uma editora ao banco de dados. Para receber os dados, utilize a propriedade Request.

1 2 3 4 5 6

public ActionResult Salva() { Editora e = new Editora { Nome = Request["nome"], Email = Request["email"] }; editoraRepository.Adiciona(e); return RedirectToAction("index"); }

4. Altere o mtodo da action Salva para receber os dados como parmetro.

1 2 3 4 5 6

public ActionResult Salva(string nome, string email) { Editora e = new Editora { Nome = nome, Email = email }; editoraRepository.Adiciona(e); return RedirectToAction("index"); }

5. Altere o mtodo da action Salva para receber um objeto editora como parmetro.

1 2 3 4 5

public ActionResult Salva(Editora e) { editoraRepository.Adiciona(e); return RedirectToAction("index"); }

7.5

TempData

Ao efetuar um redirecionamento, uma nova requisio efetuada pelo browser. Nesta nova requisio no temos mais acesso aos dados e objetos da requisio anterior ao redirecionamento. Caso haja a necessidade de preservar os dados ao longo do redirecionamento podemos utilizar o TempData. Ao salvar uma Editora, por exemplo, efetuamos um redirecionamento para a tela de listagem. Podemos acrescentar uma mensagem indicando que a operao foi efetuada com sucesso. 125 K19 Treinamentos

Controle (Controller)
1 2 3 4 5 6 7 [HttpPost] public ActionResult Create(Editora editora) { editoraRepository.Adiciona(editora); TempData["mensagem"] = "Editora criada com sucesso!"; return RedirectToAction("Index"); }

Devemos acrescentar na tela de listagem o seguinte trecho de cdigo:


1 2 3 4 @if (TempData["mensagem"] != null) { <p>@TempData["mensagem"]</p> }

7.6

Exerccios

6. Ao adicionar uma editora e redirecionar o usurio para a tela de listagem, mostre uma mensagem ao usurio indicando que a operao foi realizada com sucesso.
1 2 3 4 5 6 7 8 //EditorasController.cs [HttpPost] public ActionResult Create(Editora editora) { editoraRepository.Adiciona(editora); TempData["mensagem"] = "Editora criada com sucesso!"; return RedirectToAction("Index"); }

1 2 3 4 5

<!-- ~/Views/Editoras/Index.cshtml --> @if (TempData["mensagem"] != null) { <p>@TempData["mensagem"]</p> }

7. (opcional) Mostre mensagens para o usurio nas operaes de atualizao e remoo de editoras.

www.k19.com.br

126

Captulo 8 Rotas
Para acessar uma determinada ao da nossa aplicao, os usurios devem utilizar a URL correspondente ao. Por exemplo, para acessar a listagem de categorias, necessrio digitar na barra de endereo do navegador a seguinte url: http://localhost/Editoras/ Lista. Perceba que o padro concatenar o nome do controlador com o nome do mtodo desejado. Esse padro denido por uma rota criada no arquivo Global.asax.
1 2 3 4 5 routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Editoras", action = "Lista", id = UrlParameter. Optional } // Parameter defaults );

O primeiro argumento do mtodo MapRoute o nome da rota, o segundo a expresso que dene o formato da rota e o terceiro o conjunto de valores padres dos parmetros da rota. A expresso que determina do formato da rota dene trs parmetros: o controlador que deve ser criado, o mtodo que deve ser chamado no controlador e um argumento para esse mtodo. Dessa forma, se o usurio digitar a http://localhost/Editoras/Remove/1 na barra de endereo do seu navegador o ASP.NET criar uma instncia do controlador de editoras e executar o mtodo Remove passando o valor 1 como argumento.
1 2 EditorasController controlador = new EditorasController(conexao); controlador.Remove(1);

A rota dene um padro para URL e dene como ela ser tratada. URL / /Livros /Livros/Adiciona /Livros/Remove/1 Mapeamento da URL new { controller = "Editoras", action = "Lista"} new { controller = "Livros", action = "Lista"} new { controller = "Livros", action = "Adiciona"} new { controller = "Livros", action = "Remove", id = 1 } 127

Rotas

8.1

Adicionando uma rota

Para acrescentar uma rota podemos utilizar o mtodo MapRoute. A ordem em que as rotas so acrescentadas muito importante. Acrescente rotas mais especcas antes de rotas menos especcas. Suponha que queiramos acessar a nossa lista de livros atravs da URL /Biblioteca.
1 2 routes.MapRoute("Nova Rota", "Biblioteca", new { controller = "Livros", action = "Index" });

8.2

Denindo parmetros

Podemos acrescentar parmetros a nossa rota. Podemos denir, por exemplo, a listagem de livros por editora.
1 2 routes.MapRoute("Nova Rota", "Biblioteca/{editora}", new { controller = "Livros", action = "Index" });

Quando denimos o parmetro editora na rota acima, obrigatoriamente devemos pass-la na nossa URL. Para torn-la opcional, podemos utilizar UrlParameter.Optional.
1 2 routes.MapRoute("Nova Rota", "Biblioteca/{editora}", new { controller = "Livros", action = "Index", editora = UrlParameter. Optional });

Podemos receber os parmetros no mtodo da nossa action.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 //parmetro editora public ViewResult Index(string editora) { List<Livro> livros; if (editora != null) { livros = livroRepository.BuscaPorEditora(editora); } else { livros = livroRepository.BuscaTodas(); } return View(livros); }

Ao denir parmetros opcionais, devemos utilizar parmetros do tipo nullable type nos mtodos das actions. Pois quando no denimos o parmetro na URL, atribudo o valor null ao parmetro do mtodo. No caso de int e double, por exemplo, devemos utilizar int?, double?.

8.3

Exerccios

1. Acrescente uma nova rota para acessarmos a lista de livros atravs da URL /Biblioteca. www.k19.com.br 128

Rotas
1 2 3 4 5 6 7 8 9 //Global.asax routes.MapRoute("Nova Rota", "Biblioteca", new { controller = "Livros", action = "Index" }); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Editoras", action = "Index", id = UrlParameter. Optional } // Parameter defaults );

2. Acrescente um parmetro editora a rota criada no exerccio anterior.

1 2 3 4 5 6 7 8 9

//Global.asax routes.MapRoute("Nova Rota", "Biblioteca/{editora}", new { controller = "Livros", action = "Index" }); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Editoras", action = "Index", id = UrlParameter. Optional } // Parameter defaults );

3. Verique o que acontece ao acessar a URL /Biblioteca aps o acrscimo do parmetro editora rota. Corrija este problema denindo o parmetro editora como opcional.

1 2 3 4 5 6 7 8 9

//Global.asax routes.MapRoute("Nova Rota", "Biblioteca/{editora}", new { controller = "Livros", action = "Index", editora = UrlParameter. Optional }); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Editoras", action = "Index", id = UrlParameter. Optional } // Parameter defaults );

4. Altere o mtodo de listagem de livros para receber o parmetro editora da URL.

1 2 3 4 5

//LivrosController.cs public ViewResult Index(string editora) { return View(livroRepository.BuscaTodas()); }

5. (opcional) Dena a lgica para listar os livros de acordo com o parmetro editora da URL. 129 K19 Treinamentos

Rotas
1 2 3 4 5 6 //EditorasController.cs public ViewResult Index(string editora) { List<Livro> livros = (editora != null) ? livroRepository.BuscaPorEditora(editora) : livroRepository.BuscaTodas(); return View(livros); }

1 2 3 4 5 6 7 8

//LivroRepository.cs public List<Livro> BuscaPorEditora(string nomeEditora) { var consulta = from e in context.Livros where e.Editora.Nome.StartsWith(nomeEditora) select e; return consulta.ToList(); }

www.k19.com.br

130

Captulo 9 Validao
Os usurios podem cometer erros ao preencher um formulrio. Por exemplo, esquecer de preencher um campo que obrigatrio. Os parmetros enviados pelos usurios devem ser validados pela aplicao com o intuito de no permitir o armazenamento de informaes erradas.

9.1

Controller

O primeiro passo para implementar a validao dos parmetros enviados pelos usurios denir a lgica de validao.
1 2 3 4 if (editora.Nome == null || editora.Nome.Trim().Length == 0) { // Erro de Validao }

O segundo passo denir mensagens informativas para enviar aos usurios. O ASP.NET possui um objeto especializado no armazenamento de mensagens de erros de validao (ModelState).
1 2 3 4 if (editora.Nome == null || editora.Nome.Trim().Length == 0) { ModelState.AddModelError("Nome", "O preenchimento do campo Nome obrigatrio"); }

As mensagens so armazenadas no ModelState atravs do mtodo AddModelError. Esse mtodo permite que as mensagens sejam agrupadas logicamente pois ele possui dois parmetros: o primeiro o grupo da mensagem e o segundo e a mensagem propriamente. O cdigo de validao pode ser colocado nos controladores, mais especicamente nas aes. Se algum erro for encontrado, o uxo de execuo pode ser redirecionado para uma pgina .aspx que mostre as mensagens informativas aos usurios. Normalmente, essa pgina a mesma do formulrio que foi preenchido incorretamente. O objeto ModelState possui uma propriedade que indica se erros foram adicionados ou no. Essa propriedade se chama IsValid. 131

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [HttpPost] public ActionResult Create(Editora editora) { if (editora.Nome == null || editora.Nome.Trim().Length == 0) { // Erro de Validao ModelState.AddModelError("Nome", "O preenchimento do campo Nome obrigatrio." ); } if (ModelState.IsValid) { editoraRepository.Adiciona(editora); TempData["mensagem"] = "Editora criada com sucesso!"; return RedirectToAction("Index"); } else { return View(); } }

O ASP.NET tambm pode adicionar mensagens no ModelState antes do controlador ser chamado. Normalmente, essas mensagens esto relacionadas a erros de converso. Por exemplo, um campo que espera um nmero preenchido com letras.

9.2

View

As mensagens dos erros de validao podem ser acrescentadas na pgina web atravs do mtodo ValidationSummary da propriedade Html. importante salientar que esse mtodo adiciona todas as mensagens de erro. www.k19.com.br 132

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Cadastro de Editora"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.ValidationSummary() <fieldset> <legend>Cadastro de Editora</legend> <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

Podemos utilizar o mtodo Html.ValidationMessage para mostrar somente as mensagens de erro de um determinado grupo. Para no mostrar erros das propriedades devemos acrescentar true ao nosso mtodo ValidationSummary. 133 K19 Treinamentos

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Cadastro de Editora"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Cadastro de Editora</legend> <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) @Html.ValidationMessageFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

9.3

Exerccios

1. Insira a validao dos campos nas editoras e livros da nossa aplicao. A editora deve ter obrigatoriamente nome e email, e o livro deve ter o nome, preo e editora relacionada. No caso do livro, o preo tambm no pode ser menor que zero. Voc deve informar ao usurio o erro ocorrido atravs do mtodo Html.ValidationMessage ou Html.ValidationMessageFor. www.k19.com.br 134

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // EditorasController.cs // // POST: /Editoras/Create [HttpPost] public ActionResult Create(Editora editora) { if (editora.Nome == null || editora.Nome.Trim().Length == 0) { // Erro de Validao ModelState.AddModelError("Nome", "O preenchimento do campo Nome obrigatrio." ); } if (editora.Email == null || editora.Email.Trim().Length == 0) { ModelState.AddModelError("Email", "O preenchimento do campo Email obrigatrio ."); } if (ModelState.IsValid) { editoraRepository.Adiciona(editora); return RedirectToAction("Index"); } else { return View(); } }

135

K19 Treinamentos

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <!-- ~/Views/Editoras/Create.cshtml --> @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Cadastro de Editora"; } <h2>Create</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Cadastro de Editora</legend> <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) @Html.ValidationMessageFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

www.k19.com.br

136

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // LivrosController.cs // // POST: /Livros/Create [HttpPost] public ActionResult Create(Livro livro) { if (livro.Titulo == null || livro.Titulo.Trim().Length == 0) { ModelState.AddModelError("Titulo", "O preenchimento do campo Ttulo obrigatrio."); } if (livro.Preco <= 0) { ModelState.AddModelError("Preco", "Preencha o campo Preo corretamente."); } if (ModelState.IsValid) { livroRepository.Adiciona(livro); return RedirectToAction("Index"); } else { return View(); } }

137

K19 Treinamentos

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 <!-- ~/Views/Livros/Create.cshtml --> @model LivrariaVirtual.Models.Livro @{ ViewBag.Title = "Cadastro de Livros"; } <h2>Cadastro de Livros</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Livro</legend> <div class="editor-label"> @Html.LabelFor(model => model.Titulo) </div> <div class="editor-field"> @Html.EditorFor(model => model.Titulo) @Html.ValidationMessageFor(model => model.Titulo) </div> <div class="editor-label"> @Html.LabelFor(model => model.Preco) </div> <div class="editor-field"> @Html.EditorFor(model => model.Preco) @Html.ValidationMessageFor(model => model.Preco) </div> <div class="editor-field"> @Html.DropDownListFor(model => model.EditoraId, new SelectList(ViewBag. Editoras,"Id","Nome")) @Html.ValidationMessageFor(model => model.EditoraId) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Livros", "Index") </div>

9.4

Anotaes

As lgicas de validao mais utilizadas tambm podem ser implementadas atravs de anotaes adicionadas nas classes de modelo. Dessa forma, essas lgicas no estariam mais nos controladores, o que conceitualmente o ideal pois nos controladores s deveria existir lgica para controlar o uxo da execuo. Para utilizar essas anotaes, necessrio adicionar uma dll na aplicao. O nome da dll : System.ComponentModel.DataAnnotations.dll.

9.4.1

Required

Uma das validaes mais comuns a de campo obrigatrio. Ela pode ser realizada atravs da anotao Required. www.k19.com.br 138

Validao
1 2 3 4 5 6 7 8 9 10 11 public class Editora { [Required] public string Nome { get; set; } // restante do cdigo }

Com essa anotao a lgica de validao pode ser retirada do controlador.


1 2 3 4 5 6 7 8 9 10 11 12 13 [HttpPost] public ActionResult Create(Editora editora) { if (ModelState.IsValid) { editoraRepository.Adiciona(editora); return RedirectToAction("Index"); } else { return View(); } }

9.4.2

Alterando a mensagem

As anotaes de validaes possuem mensagens padres que podem ser alteradas atravs da propriedade ErrorMessage.
1 2 3 4 5 6 [Required(ErrorMessage="O campo Nome obrigatrio")] public string Nome { get; set; }

9.4.3

Outros validadores

H outras anotaes para validao: Range ReqularExpression StringLength 139 K19 Treinamentos

Validao

9.5

Validao no lado do Cliente

Nas verses anteriores do MVC para habilitar a validao no lado do cliente era necessrio chamar explicitamente o mtodo Html.EnableClientValidation na View. No ASP .NET MVC 3 a validao no cliente est habilitada por padro. Para funcionar corretamente a validao, voc deve acrescentar as referncias corretas das bibliotecas javascript jQuery e jQuery Validation na View.

1 2

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script>

9.6

Exerccios

2. Altere as validaes feitas anteriormente, para utilizar DataAnnotations. Lembre-se de alterar todas as mensagens de erro para a lngua portuguesa. Acrescente tambm a validao no cliente.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

using using using using using

System; System.Collections.Generic; System.Linq; System.Web; System.ComponentModel.DataAnnotations;

namespace LivrariaVirtual.Models { public class Editora { public int Id { get; set; } [Required(ErrorMessage="O campo Nome obrigatrio.")] public string Nome { get; set; } [Required(ErrorMessage="O campo Email obrigatrio")] public string Email { get; set; } public virtual ICollection<Livro> Livros { get; set; } } }

www.k19.com.br

140

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 using using using using using System; System.Collections.Generic; System.Linq; System.Text; System.ComponentModel.DataAnnotations;

namespace LivrariaVirtual.Models { public class Livro { public int Id { get; set; } [Required(ErrorMessage="O campo Ttulo obrigatrio.")] public string Titulo { get; set; } [Required(ErrorMessage = "O campo Preo obrigatrio.")] public decimal Preco { get; set; } [Required(ErrorMessage = "O campo EditoraId obrigatrio.")] public int EditoraId { get; set; } public virtual Editora Editora { get; set; } } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

//EditorasController.cs // // POST: /Editoras/Create [HttpPost] public ActionResult Create(Editora editora) { if (ModelState.IsValid) { editoraRepository.Adiciona(editora); return RedirectToAction("Index"); } else { return View(); } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

//LivrosController.cs // // POST: /Livros/Create [HttpPost] public ActionResult Create(Livro livro) { if (ModelState.IsValid) { livroRepository.Adiciona(livro); return RedirectToAction("Index"); } else { ViewBag.Editoras = livroRepository.BuscaTodas(); return View(); } }

141

K19 Treinamentos

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <!-- ~/Views/Editoras/Create.cshtml --> @model LivrariaVirtual.Models.Editora @{ ViewBag.Title = "Cadastro de Editora"; } <h2>Create</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Cadastro de Editora</legend> <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) @Html.ValidationMessageFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Editoras", "Index") </div>

www.k19.com.br

142

Validao
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <!-- ~/Views/Livros/Create.cshtml --> @model LivrariaVirtual.Models.Livro @{ ViewBag.Title = "Cadastro de Livros"; } <h2>Create</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Livro</legend> <div class="editor-label"> @Html.LabelFor(model => model.Titulo) </div> <div class="editor-field"> @Html.EditorFor(model => model.Titulo) @Html.ValidationMessageFor(model => model.Titulo) </div> <div class="editor-label"> @Html.LabelFor(model => model.Preco) </div> <div class="editor-field"> @Html.EditorFor(model => model.Preco) @Html.ValidationMessageFor(model => model.Preco) </div> <div class="editor-field"> @Html.DropDownListFor(model => model.EditoraId, new SelectList(ViewBag. Editoras,"Id","Nome")) @Html.ValidationMessageFor(model => model.EditoraId) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Livros", "Index") </div>

143

K19 Treinamentos

Validao

www.k19.com.br

144

Captulo 10 Sesso
Quando um cliente for fazer compras na nossa loja virtual ele pode ter, por exemplo, um carrinho de compras, que uma informao gerada durante a navegao. A medida que ele visita as pginas, ele pode ir adicionando ou removendo itens do seu carrinho virtual. Porm isto um problema, pois o protocolo HTTP no armazena estado (stateless) das pginas visitadas anteriormente. Desse modo no podemos armazenar a informao entre uma pgina e outra.

10.1

Sesso

Nossa tarefa encontrar um modo de armazenar estes dados no servidor e deixar a informao disponvel para diferentes pginas da aplicao. Para solucionar este problema, utilizado o conceito de sesso. Uma sesso uma maneira de armazenar informaes geradas durante a navegao no lado do servidor. Como o sistema pode ter vrios usurios navegando simultaneamente, tambm devemos encontrar uma maneira de separar este conjunto de informaes por usurio, para que no haja nehum tipo de conito. Para isto precisamos identicar unicamente cada usurio da nossa aplicao de maneira que cada um tenha sua prpria sesso.

10.1.1

Identicando o Usurio

Uma primeira abordagem seria distinguir cada usurio utilizando o endereo de IP. Porm, caso existam usurios em uma rede local, eles teram o mesmo IP e no seria possvel identiclos individualmente. Podemos considerar ainda o caso de um usurio com o IP dinmico, caso ele reconecte durante a navegao, toda a informao do seu histrico recente ser perdida. A soluo seria deixar a cargo do servidor a gerao de um identicador nico e envi-lo para cada usurio. Desta maneira, a cada requisio, o cliente envia de volta este ID de forma que a aplicao possa reconhec-lo. O cliente pode reenviar o seu ID de diferentes formas. As mais utilizadas so: Reescrita de URL Nesta maneira, o ID embutido nas prprias URLs da aplicao. Sendo assim o ID pode ser reconhecido pela aplicao em todas as requisies. Uma desvantagem que todas as pginas devem ser geradas dinamicamente para conter o ID em todos os links e actions. Outro problema que este ID ca aparente na barra de navegao do navegador facilitando o acesso de pessoas mal intencionadas que poderiam, por sua vez, 145

Sesso obter informaes condenciais. Uma vez que a URL no contm mais o identicador, a aplicao considera que o usurio no tem uma sesso associada. Cookies Cookie um arquivo criado pelo servidor no navegador do cliente. Uma de suas funes persistir o ID da sesso. A cada requisio a aplicao consulta o ID da sesso no cookie para recuperar as informaes do usurio. Esta a maneira mais utilizada. A sesso pode ser encerrada com a retirada do cookie no navegador. Podemos fazer explicitamente atravs de uma rotina de logout no servidor, ou podemos deix-la expirar por tempo de inatividade, ou seja, caso o usurio que um determinado tempo sem fazer novas requisies, a sesso encerrada.

10.2

Utilizando Session no ASP.NET

No ASP.NET, a sesso um dicionrio. Para armazenar informaes, voc deve adicionar uma chave e um valor no objeto Session. Imagine um objeto do tipo Cliente que agrupa as informaes sobre um determinado cliente. O cdigo a seguir um exemplo de como podemos guardar as informaes relacionadas ao cliente no momento do login.
1 2 3 4 5 6 7 8 9 10 public class LoginController : Controller { ... public ActionResult Login(Cliente cliente) { ... // Armazenando informao na sesso Session["cliente"] = cliente; } }

Voc pode adicionar qualquer tipo de valor na sesso. De forma anloga, para resgatar a informao armazenada, basta acessar a chave correspondente no objeto Session, como no exemplo a seguir:
1 2 3 // Recuperando informao da sesso Cliente cliente = (Cliente)Session["cliente"]; string saudacao = "Bem vindo " + cliente.Nome;

Caso um usurio deslogue do sistema preciso eliminar a informao acumulada em sua sesso. Para isto podemos simplesmente remover todas as chaves do dicionrio como no exemplo a seguir.
1 2 // Eliminando todas as informaes do sistema Session.RemoveAll();

Contudo, fazendo isto no estaramos terminando com a sesso, o que desejvel ao fazer um logout. Ento, para terminar com a sesso, voc deve utilizar o comando Session.Abandon(). www.k19.com.br 146

Sesso
1 2 3 4 5 6 7 8 9 public class LoginController : Controller { ... public ActionResult Logout() { ... Session.Abandon(); } }

10.3

Session Mode

O ASP.NET disponibiliza quatro modos de Sesso (Session Modes): InProc StateServer SQLServer Custom A diferena de cada modo a maneira com que a sesso armazenada. Cada um tem um State Provider diferente. No modo InProc todas as informaes da sesso so armazenadas na memria do servidor. Esse o modo mais simples e utilizado, e vem congurado como o padro. Uma das desvantagens desse modo, a possvel sobrecarga de memria, se forem armazenadas muitas informaes na sesso. Por isso no indicado para sistemas muito grandes, com muitos usurios navegando simultaneamente. Outro problema que o servidor no pode ser desligado, pois a informao armazenada na memria ser perdida. No modo StateServer as informaes so serializadas e enviadas para um servidor independente do servidor da aplicao. Isto possibilita que o servidor de aplicao seja reiniciado sem que as sesses seja perdidas. Uma desvantagem o custo de tempo de serializao e desserializao. No modo SQLServer as informaes so serializadas porm armazenadas em um banco de dados. Este modo tambm permite que o servidor de aplicao seja reiniciado, alm disso possibilita um maior controle de segurana dos dados da sesso. Uma desvantagem importante que o processo naturalmente lento. No modo Custom todo o processo de identicao de usurio e armazenamento de sesses pode ser customizado. Para selecionar algum dos modos disponveis basta adicionar a tag <sessionState> dentro da tag <system.web>, no arquivo Web.Cong.
1 <sessionState mode="InProc"/>

Podemos personalizar nossa sesso modicando alguns atributos da tag <sessionState>. Por exemplo, podemos determinar o tempo de expirao do cookie em minutos atravs do atributo timeout. 147 K19 Treinamentos

Sesso
1 <sessionState mode="InProc" timeout="30"/>

Outra possibilidade desabilitar o uso de cookie com o atributo cookieless. Neste caso ser utilizada a reescrita de URL.

<sessionState mode="InProc" cookieless="true"/>

Se nenhum modo for selecionado o modo InProc ser utilizado por padro.

10.4

Exerccios

1. Para introduzirmos o conceito de sesso na nossa livraria virtual precisamos primeiro adicionar uma entidade Cliente na nossa aplicao. Seguindo os moldes de Editora e Livros crie a classe Cliente, a classe ClienteRepository, um controlador ClientesController (para listar, buscar, atualizar, remover e adicionar) e todas as pginas cshtml relacionadas.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

using using using using using using

System; System.Collections.Generic; System.Linq; System.Web; System.ComponentModel.DataAnnotations; System.Web.Mvc;

namespace LivrariaVirtual.Models { public class Cliente { public int Id { get; set; } [Required(ErrorMessage="O campo Nome obrigatrio")] public string Nome { get; set; } [Required(ErrorMessage="O campo Usurio obrigatrio")] public string Usuario { get; set; } [DataType(DataType.Password)] public string Senha { get; set; } [NotMapped] [DataType(DataType.Password)] [Compare("Senha",ErrorMessage="A confirmao da senha est incorreta.")] public string ComparaSenha { get; set; } } }

www.k19.com.br

148

Sesso
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Data;

namespace LivrariaVirtual.Models { public class ClienteRepository { private LivrariaContext context = new LivrariaContext(); public void Adiciona(Cliente c) { context.Clientes.Add(c); context.SaveChanges(); } public void Atualiza(Cliente c) { context.Entry(c).State = EntityState.Modified; context.SaveChanges(); } public void Remove(Cliente c) { context.Entry(c).State = EntityState.Deleted; context.SaveChanges(); } public void Remove(int id) { Cliente c = context.Clientes.Find(id); context.Clientes.Remove(c); context.SaveChanges(); } public Cliente Busca(int id) { return context.Clientes.Find(id); } public List<Cliente> BuscaTodas() { return context.Clientes.ToList(); } } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

using using using using using using using using

System; System.Collections.Generic; System.Data; System.Data.Entity; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class ClientesController : Controller { private ClienteRepository clienteRepository = new ClienteRepository(); // // GET: /Clientes/ public ViewResult Index() {

149

K19 Treinamentos

Sesso
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 return View(clienteRepository.BuscaTodas()); } // // GET: /Clientes/Details/5 public ViewResult Details(int id) { Cliente cliente = clienteRepository.Busca(id); return View(cliente); } // // GET: /Clientes/Create public ActionResult Create() { return View(); } // // POST: /Clientes/Create [HttpPost] public ActionResult Create(Cliente cliente) { if (ModelState.IsValid) { clienteRepository.Adiciona(cliente); return RedirectToAction("Index"); } return View(cliente); } // // GET: /Clientes/Edit/5 public ActionResult Edit(int id) { Cliente cliente = clienteRepository.Busca(id); return View(cliente); } // // POST: /Clientes/Edit/5 [HttpPost] public ActionResult Edit(Cliente cliente) { if (ModelState.IsValid) { clienteRepository.Atualiza(cliente); return RedirectToAction("Index"); } return View(cliente); } // // GET: /Clientes/Delete/5 public ActionResult Delete(int id) { Cliente cliente = clienteRepository.Busca(id); return View(cliente); } // // POST: /Clientes/Delete/5

www.k19.com.br

150

Sesso
91 92 93 94 95 96 97 98 [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { clienteRepository.Remove(id); return RedirectToAction("Index"); } } }

151

K19 Treinamentos

Sesso
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <!-- ~/Views/Clientes/Create.cshtml --> @model LivrariaVirtual.Models.Cliente @{ ViewBag.Title = "Cadastro de Clientes"; } <h2>Cadastro de Clientes</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Cliente</legend> <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) @Html.ValidationMessageFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Usuario) </div> <div class="editor-field"> @Html.EditorFor(model => model.Usuario) @Html.ValidationMessageFor(model => model.Usuario) </div> <div class="editor-label"> @Html.LabelFor(model => model.Senha) </div> <div class="editor-field"> @Html.EditorFor(model => model.Senha) @Html.ValidationMessageFor(model => model.Senha) </div> <div class="editor-label"> @Html.LabelFor(model => model.ComparaSenha) </div> <div class="editor-field"> @Html.EditorFor(model => model.ComparaSenha) @Html.ValidationMessageFor(model => model.ComparaSenha) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Clientes", "Index") </div>

2. Implemente um novo controlador chamado LoginController que ser responsvel pelo login e logout do usurio. Para isto o controlador precisar de uma action para login e outra para logout. Crie uma pgina de login chamada index.cshtml. Esta pgina deve disponibilizar um formulrio com usurio e senha. Para efetuar um login a action login www.k19.com.br 152

Sesso deve chamar um novo mtodo do ClienteRepository que recebe um par usuario/senha e devolve um bool inicando a existncia dos dados de entrada. Se a entrada for vlida, recupere as informaes do usurio em um objeto tipo Cliente, armazene-o em uma chave cliente da sesso e redirecione a pgina para a home. Se a entrada no for vlida ento imprima uma mensagem de falha na pgina de login. Na action logout faa com que a sesso seja terminada. Por ltimo, dentro do body do nosso layout principal adicione o cdigo para mostrar o nome do usurio logado.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

//~/Models/ClienteRepository.cs public Cliente Busca(string usuario, string senha) { var consulta = from e in context.Clientes where e.Usuario.Equals(usuario) && e.Senha.Equals(senha) select e; string query = consulta.ToString(); return consulta.First(); } public bool Autentica(string usuario, string senha) { var consulta = from e in context.Clientes where e.Usuario.Equals(usuario) && e.Senha.Equals(senha) select e; return consulta.ToList().Count >= 1; }

153

K19 Treinamentos

Sesso
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 using using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; LivrariaVirtual.Models;

namespace LivrariaVirtual.Controllers { public class LoginController : Controller { private ClienteRepository clienteRepository = new ClienteRepository(); // // GET: /Login/ public ActionResult Index() { return View(); } [HttpPost] public ActionResult Index(string usuario, string senha) { if (clienteRepository.Autentica(usuario,senha)) { Session["cliente"] = clienteRepository.Busca(usuario, senha); return RedirectToAction("Index", "Editoras"); } else { TempData["mensagem"] = "Usurio e senha incorretos"; return View(); } } public ActionResult Logout() { Session.Abandon(); return Redirect("/"); } } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

<!-- ~/Views/Login/Index.cshtml --> @{ ViewBag.Title = "Tela de Login"; } <h2>Tela de Login</h2> @if (TempData["mensagem"] != null) { <h3>@TempData["mensagem"]</h3> } <h3></h3> @using (Html.BeginForm()) { <p>Usurio: @Html.TextBox("Usuario")</p> <p>Senha: @Html.Password("Senha")</p> <input type="submit" value="Logar" /> }

www.k19.com.br

154

Sesso
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <!-- ~/Views/Shared/_Layout.cshtml --> <!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"> </script> </head> @{LivrariaVirtual.Models.Cliente c = (LivrariaVirtual.Models.Cliente)Session["cliente" ];} @if (Session["cliente"] != null) { <span>@c.Nome</span> <span>@Html.ActionLink("Logout","Logout","Login")</span> } else { <span>@Html.ActionLink("Login", "Index", "Login")</span> } <body> @RenderBody() </body> </html>

Este cdigo faz com que aparea o nome do cliente logado e um link para logout somente se o cliente estiver logado. Note que podemos navegar no sistema sem que estejamos logados. Este problema ser tratado no captulo de Filtros.

155

K19 Treinamentos

Sesso

www.k19.com.br

156

Captulo 11 Filtros
Muitas vezes em um sistema queremos restringir o acesso determinadas reas, seja por segurana ou por organizao.Por exemplo, na nossa aplicao poderamos denir que para poder adicionar, alterar e remover tanto categorias quanto produtos, o usurio deve estar logado no sistema. Caso contrrio, o usurio apenas pode listar as categorias e produtos.
1 2 3 4 5 6 7 8 9 10 11 public ActionResult FormularioCadastro() { if (Session["cliente"] != null) { return base.View(); } else { return base.RedirectToAction("Index", "Login"); } }

No exemplo acima, caso um usurio tente adicionar uma categoria atravs do formulrio de cadastro, o mtodo vai vericar se o usurio j est logado, atravs do uso da sesso visto no captulo anterior. Seno estiver logado, ele ser redirecionado para a pgina de Login . Apesar de funcionar, este cdigo apresenta uma inconvenincia. Temos que adicionar essa lgica a todas as Actions que queremos que tenha o mesmo comportamento, ou seja, que apenas permitam o acesso de usurios logados. Em outros casos, podemos querer que algumas Actions executem alguma tarefa em comum. Por exemplo, na nossa loja virtual, poderamos adicionar uma mensagem em um arquivo de Log sempre que uma Action fosse realizada. Desse modo, poderamos guardar um histrico sobre o que a aplicao mais realizou, qual foi a pgina mais visitada, etc. Mas novamente, teramos que adicionar a mesma tarefa em todas as Actions da nossa aplicao. Nesses casos, em que vrias Actions possuem um mesmo comportamento em comum, podemos utilizar o conceito de Filtros. Um ltro semelhante a um mtodo que executado antes ou depois que uma Action realizada.

11.1

Filtro de Autenticao

O ASP.NET j possui alguns ltros prontos para serem utilizados, como o ltro de autenticao. Podemos utilizar ele para o nosso primeiro exemplo, onde exigimos que o usurio 157

Filtros esteja logado (autenticado) para acessar determinadas reas da aplicao. Para isso precisamos adicionar o seguinte cdigo no nosso mtodo de login:
1 FormsAuthentication.SetAuthCookie(cliente.Usuario, false);

Isto adiciona um novo cookie utilizado para a autenticao do usurio. Este novo cookie independente do cookie utilizado para armazenar informaes da sesso. O primeiro parmetro referente ao nome do usurio (ou algo que o identique). O segundo parmetro um booleano relativo ao tipo do cookie, se permanente ou no. Caso seja true, ele sempre ir considerar que o usurio est autenticado aps a primeira autenticao. Para eliminar o cookie de autenticao, devemos realizar o seguinte cdigo no logout:
1 FormsAuthentication.SignOut();

Para adicionar o ltro, devemos incluir a anotao Authorize nas Actions em que desejamos a autenticao:
1 2 3 4 5 [Authorize] public ActionResult FormularioCadastro() { return base.View(); }

Se queremos aplicar o mesmo ltro a todas as Actions de um controlador, podemos adicionar a notao Authorize na classe:
1 2 3 4 5 [Authorize] public class CategoriaController : Controller { ... }

Desse modo, todas as Actions presentes no controlador da categoria exigem que o usurio esteja autenticado. Quando o ltro de autenticao barra um usurio de acessar uma pgina, podemos redirecionlo para a pgina de login. Devemos incluir o seguinte cdigo dentro da tag <system.web>:
1 2 3 <authentication mode="Forms"> <forms loginUrl="~/Login" timeout="2880"/> </authentication>

Para checar se a sesso est autenticada, podemos utilizar o atributo IsAuthenticated, como a seguir:
1 2 3 4 if (User.Identity.IsAuthenticated) { ... }

www.k19.com.br

158

Filtros Podemos pegar a informao de quem est autenticado atravs do seguinte comando:
1 string nome = User.Identity.Name;

Isto ir pegar o nome que passamos como parmetro para o mtodo SetAuthCookie.

11.2

Exerccios

1. Altere a aplicao do captulo anterior para incluir autenticao nas Actions de adicionar, alterar e remover de editoras e livros. Na Action de Login do LoginController, adicione o cookie de autenticao como visto na seo anterior, passando o nome de usuario como parmetro. No layout principal, altere a seo que mostra o nome do usurio, para utilizar a informao do cookie de autenticao, e no mais da sesso. Caso o usurio no esteja autenticado, e tente acessar uma das Actions acima, redirecione atravs do Web.Cong para a Action de Login.

11.3 Action Filters


O ltro de autenticao no o nico ltro que existe no ASP.NET. Outro tipo muito usado so os chamados Action Filters. Geralmente so usados quando queremos executar uma ao especca para mais de uma Action. Por exemplo, quando queremos gravar as aes que esto sendo realizadas em um arquivo de log. Para criar um Action Filter voc deve utilizar o suxo Attribute no nome da classe, e herdar a classe ActionFilterAttribute.
1 2 3 4 public class LogAttribute : ActionFilterAttribute { ... }

O nome utilizado na classe o mesmo utilizado nas anotaes das Actions, excluindo o suxo attribute. Por exemplo, para aplicar o ltro LogAttribute no mtodo que lista as categorias:
1 2 3 4 5 [Log] public ActionResult Lista() { ... }

Para fazer o ltro funcionar, deve ser implementado um ou mais dos seguintes mtodos: OnActionExecuting(ActionExecutedContext lterContext); OnActionExecuted(ActionExecutingContext lterContext); OnResultExecuting(ResultExecutedContext lterContext); 159 K19 Treinamentos

Filtros OnResultExecuted(ResultExecutingContext lterContext); Eles so executados na mesma ordem em que aparecem acima, sendo que todos so executados antes da renderizao da pgina. Logo, o nosso exemplo com o ltro de log poderia car assim:
1 2 3 4 5 6 7 8 9 public class LogAttribute : ActionFilterAttribute { ... public override void OnActionExecuted(ActionExecutedContext filterContext) { // escreve informao de log } ... }

Tambm possvel passar parmetros para o ltro da seguinte maneira:


1 2 3 4 5 [Log(Message="Executando lista de categorias"] public ActionResult Lista() { ... }

Sendo que a classe LogAttribute precisa ter um atributo ou propriedade com o mesmo nome do parmetro passado.
1 2 3 4 5 6 7 8 9 10 public class LogAttribute : ActionFilterAttribute { public string Message { get; set; } public override void OnActionExecuted(ActionExecutedContext filterContext) { // escreve a mensagem no arquivo de log } ... }

Voc pode passar vrios parmetros na anotao, separando-os por vrgulas.

11.4

Exerccios

2. Crie um ltro chamado LogAttribute, que grava mensagens em um arquivo de Log, chamado log.txt sempre que uma Action chamada. A informao no log deve incluir a data, horrio e pequena descrio da Action realizada. Aplique este ltro a todas as Actions do sistema. (Dica: utilize a classe FileInfo e seu mtodo AppendText para criar o arquivo de log e a classe StreamWriter para escrever, e passe um parmetro para o ltro para identicar a ao que est sendo realizada).

www.k19.com.br

160

Captulo 12 Projeto
Nos captulos anteriores, vimos os recursos do ASP .NET MVC e do Entity Framework. Agora, vamos solidicar os conhecimentos obtidos e, alm disso, mostraremos alguns padres e conceitos relacionados ao desenvolvimento de aplicaes web. Como exemplo de aplicao desenvolveremos uma aplicao de cadastro de jogadores e selees de futebol.

12.1

Modelo

Por onde comear o desenvolvimento de uma aplicao? Essa uma questo recorrente. Um timo ponto de partida desenvolver as entidades principais da aplicao. No nosso caso, vamos nos restringir s entidades Selecao e Jogador. Devemos estabelecer um relacionamento entre essas entidades j que um jogador atua em uma seleo.

12.2

Exerccios

1. Crie um projeto do tipo ASP .NET MVC 3 Web Application chamado K19-CopaDoMundo seguindo os passos vistos no exerccio do captulo 4. 2. Adicione na pasta Models as seguintes classes.

1 2 3 4 5 6 7 8

namespace K19_CopaDoMundo.Models { public class Selecao { public string Pais { get; set; } public string Tecnico { get; set; } } }

161

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 namespace K19_CopaDoMundo.Models { public class Jogador { public string Nome { get; set; } public string Posicao { get; set; } public DateTime Nascimento { get; set; } public double Altura { get; set; } public Selecao Selecao { get; set; } } }

12.3

Persistncia - Mapeamento

Depois de denir algumas entidades podemos comear o processo de implementao da persistncia da nossa aplicao. Vamos aplicar os recursos do Entity Framework - Code First que aprendemos nos primeiros captulos. Inicialmente, vamos denir o mapeamento das nossas entidades atravs de uma classe derivada de DbContext e acrescentar as propriedades referentes a chave primria e chave estrangeira. No se esquea de acrescentar as dlls EntityFramework e System.ComponentModel.DataAnnotations ao projeto.

12.4

Exerccios

3. Adicione as seguintes propriedades e anotaes.

1 2 3 4 5 6 7 8 9 10 11 12 13

using System.ComponentModel.DataAnnotations; namespace K19_CopaDoMundo.Models { [Table("Selecoes")] public class Selecao { public int Id { get; set; } public string Pais { get; set; } public string Tecnico { get; set; } public virtual ICollection<Jogador> Jogadores { get; set; } } }

www.k19.com.br

162

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using System.ComponentModel.DataAnnotations; namespace K19_CopaDoMundo.Models { [Table("Jogadores")] public class Jogador { public int Id { get; set; } public string Nome { get; set; } public string Posicao { get; set; } public DateTime Nascimento { get; set; } public double Altura { get; set; } public int SelecaoId { get; set; } [InverseProperty("Jogadores")] public virtual Selecao Selecao { get; set; } } }

1 2 3 4 5 6 7 8 9 10

using System.Data.Entity; namespace K19_CopaDoMundo.Models { public class CopaDoMundoContext : DbContext { public DbSet<Selecao> Selecoes { get; set; } public DbSet<Jogador> Jogadores { get; set; } } }

12.5

Persistncia - Congurao

Precisamos denir a nossa string de conexo para que a nossa aplicao utilize a base de dados copadomundo como padro.

12.6

Exerccios

4. Acrescente ao arquivo Web.cong, que ca na raiz do projeto, a string de conexo.

1 2 3 4 5 6

<connectionStrings> <add name="CopaDoMundoContext" providerName="System.Data.SqlClient" connectionString="Server=.\SQLEXPRESS;Database=copadomundo; User Id=sa; Password=sa;Trusted_Connection=False;Persist Security Info=True; MultipleActiveResultSets=True"/> </connectionStrings>

5. Altere a estratgia de criao do banco de dados. Para isto, acrescente ao mtodo Application_Start denido no arquivo Global.asax o seguinte trecho de cdigo. 163 K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 //Global.asax protected void Application_Start() { AreaRegistration.RegisterAllAreas(); // Alterando a estratgia de criao do banco de dados Database.SetInitializer(new DropCreateDatabaseIfModelChanges<K19_CopaDoMundo.Models .CopaDoMundoContext>()); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); }

12.7

Persistncia - Repositrios

Vamos deixar os repositrios para acessar as entidades da nossa aplicao preparados. Os repositrios precisam de DbContexts para realizar as operaes de persistncia. Ento, cada repositrio ter um construtor para receber um DbContext como parmetro.

12.8

Exerccios

6. Crie uma classe na pasta Models chamada SelecaoRepository. www.k19.com.br 164

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 using using using using System; System.Collections.Generic; System.Linq; System.Web;

namespace K19_CopaDoMundo.Models { public class SelecaoRepository : IDisposable { private bool disposed = false; private CopaDoMundoContext context; public SelecaoRepository(CopaDoMundoContext context) { this.context = context; } public void Adiciona(Selecao selecao) { context.Selecoes.Add(selecao); } public List<Selecao> Selecoes { get { return context.Selecoes.ToList(); } } public void Salva() { context.SaveChanges(); } protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { context.Dispose(); } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }

7. Analogamente crie um repositrio de jogadores. 165 K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 using using using using System; System.Collections.Generic; System.Linq; System.Web;

namespace K19_CopaDoMundo.Models { public class JogadorRepository : IDisposable { private bool disposed = false; private CopaDoMundoContext context; public JogadorRepository(CopaDoMundoContext context) { this.context = context; } public void Adiciona(Jogador jogador) { context.Jogadores.Add(jogador); } public List<Jogador> Jogadores { get { return context.Jogadores.ToList(); } } public void Salva() { context.SaveChanges(); } protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { context.Dispose(); } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }

12.8.1

Unit of Work

O nico propsito de criar uma classe UnitOfWork ter certeza que quando temos mltiplos repositrios eles compartilham o mesmo DbContext. Para isto, devemos apenas criar um mtodo Salva e uma propriedade para cada repositrio.

12.9

Exerccios

8. Crie uma classe UnitOfWork na pasta Models. www.k19.com.br 166

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 using using using using System; System.Collections.Generic; System.Linq; System.Web;

namespace K19_CopaDoMundo.Models { public class UnitOfWork : IDisposable { private bool disposed = false; private CopaDoMundoContext context = new CopaDoMundoContext(); private SelecaoRepository selecaoRepository; private JogadorRepository jogadorRepository;

public JogadorRepository JogadorRepository { get { if (jogadorRepository == null) { jogadorRepository = new JogadorRepository(context); } return jogadorRepository; } } public SelecaoRepository SelecaoRepository { get { if (selecaoRepository == null) { selecaoRepository = new SelecaoRepository(context); } return selecaoRepository; } } public void Salva() { context.SaveChanges(); } protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { context.Dispose(); } } this.disposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }

167

K19 Treinamentos

Projeto

12.10

Apresentao - Template

Vamos denir um template para as telas da nossa aplicao. Aplicaremos algumas regras CSS para melhorar a parte visual das telas.

12.11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

Exerccios

9. Na pasta Content, altere o arquivo Site.css acrescentando algumas regras CSS.


.logo{ vertical-align: middle; } .botao { background-color: #064D83; margin: 0 0 0 20px; color: white; text-decoration: none; font-size: 20px; line-height: 20px; padding: 5px; vertical-align: middle; } .botao:hover{ background-color: #cccccc; color: #666666; } .formulario fieldset{ float: left; margin: 0 0 20px 0; border: 1px solid #333333; } .formulario fieldset legend{ color: #064D83; font-weight: bold; } .botao-formulario{ background-color: #064D83; color: #ffffff; padding: 5px; vertical-align: middle; border: none; } .titulo { color: #064D83; clear: both; } .tabela{ border: 1px solid #064D83; border-collapse: collapse; } .tabela tr th{ background-color: #064D83; color: #ffffff; } .tabela tr th, .tabela tr td{

www.k19.com.br

168

Projeto
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 border: 1px solid #064D83; padding: 2px 5px; }

/* Styles for validation helpers -----------------------------------------------------------*/ .field-validation-error { color: #ff0000; } .field-validation-valid { display: none; } .input-validation-error { border: 1px solid #ff0000; background-color: #ffeeee; } .validation-summary-errors { font-weight: bold; color: #ff0000; } .validation-summary-valid { display: none; }

10. Copie o arquivo k19-logo.png da pasta K19-Arquivos da sua rea de Trabalho para a pasta Content. 11. Agora altere o arquivo _Layout.cshtml.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <!-- ~/Views/Shared/_Layout.cshtml --> <!DOCTYPE html> <html> <head> <title>Copa do Mundo</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"> </script> </head> <body> <div id="header"> <img class="logo" src="@Url.Content("~/Content/k19-logo.jpg")" alt="K19 Logo" / > @Html.ActionLink("Selecoes", "Index", "Selecoes", null, new { @class = "botao" }) @Html.ActionLink("Jogadores", "Index", "Jogadores", null, new { @class = "botao " }) <hr/> </div> @RenderBody() <div id="footer" style="text-align: center"> <hr /> &copy; 2010 K19. Todos os direitos reservados. </div> </body> </html>

169

K19 Treinamentos

Projeto

12.12

Cadastrando e Listando Selees

Na tela de selees, vamos adicionar um formulrio para cadastrar novas selees e uma tabela para apresentar as j cadastradas. Aplicaremos regras de validao especcas para garantir que nenhum dado incorreto seja armazenado no banco de dados.

12.13

Exerccios

12. Para cadastrar a seleo, devemos denir o controlador.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

using using using using using using using using

System; System.Collections.Generic; System.Data; System.Data.Entity; System.Linq; System.Web; System.Web.Mvc; K19_CopaDoMundo.Models;

namespace K19_CopaDoMundo.Controllers { public class SelecoesController : Controller { private UnitOfWork unitOfWork = new UnitOfWork(); public ActionResult Create() { return View(); } protected override void Dispose(bool disposing) { unitOfWork.Dispose(); base.Dispose(disposing); } } }

13. Vamos criar uma tela Create.cshtml para cadastrar as selees. Adicione o arquivo a pasta Views/Selecoes com o seguinte contedo. www.k19.com.br 170

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <!-- ~/Views/Selecoes/Create.cshtml --> @model K19_CopaDoMundo.Models.Selecao <h2>Cadastro de Selees</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Seleo</legend> <div class="editor-label"> @Html.LabelFor(model => model.Pais) </div> <div class="editor-field"> @Html.EditorFor(model => model.Pais) @Html.ValidationMessageFor(model => model.Pais) </div> <div class="editor-label"> @Html.LabelFor(model => model.Tecnico) </div> <div class="editor-field"> @Html.EditorFor(model => model.Tecnico) @Html.ValidationMessageFor(model => model.Tecnico) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Selees", "Index") </div>

14. O prximo passo denir a action que ir salvar a seleo no nosso banco de dados. Devemos tambm acrescentar as validaes a nossa entidade.

1 2 3 4 5 6 7 8 9 10 11 12

//SelecoesController.cs [HttpPost] public ActionResult Create(Selecao selecao) { if (ModelState.IsValid) { unitOfWork.SelecaoRepository.Adiciona(selecao); unitOfWork.Salva(); return RedirectToAction("Index"); } return View(selecao); }

171

K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //Selecao.cs using System.ComponentModel.DataAnnotations; namespace K19_CopaDoMundo.Models { [Table("Selecoes")] public class Selecao { public int Id { get; set; } [Required(ErrorMessage="O campo Pais obrigatrio.")] public string Pais { get; set; } [Required(ErrorMessage="O campo Tecnico obrigatrio.")] public string Tecnico { get; set; } public virtual ICollection<Jogador> Jogadores { get; set; } } }

15. Dena a action e a pgina para listar todas as entidades de seleo.


1 2 3 4 5

//SelecoesController.cs public ActionResult Index() { return View(unitOfWork.SelecaoRepository.Selecoes); }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

<!-- ~/Views/Selecoes/Index.cshtml --> @model IEnumerable<K19_CopaDoMundo.Models.Selecao> <h2>Listagem de Seleo</h2> <p> @Html.ActionLink("Cadastrar Nova Seleo", "Create") </p> <table> <tr> <th> Pais </th> <th> Tecnico </th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Pais) </td> <td> @Html.DisplayFor(modelItem => item.Tecnico) </td> </tr> } </table>

16. Vamos denir a tela de listagem de Selees como a pgina principal do nosso site. Altere a rota padro no arquivo Global.asax. www.k19.com.br 172

Projeto
1 2 3 4 5 6 //Global.asax routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Selecoes", action = "Index", id = UrlParameter.Optional } // Parameter defaults );

12.14

Removendo Selees

Vamos acrescentar a funcionalidade de remover selees.

12.15

Exerccios

17. Acrescente uma coluna na tabela de listagem de selees.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

<!-- ~/Views/Selecoes/Index.cshtml --> @model IEnumerable<K19_CopaDoMundo.Models.Selecao> <h2>Listagem de Seleo</h2> <p> @Html.ActionLink("Cadastrar Nova Seleo", "Create") </p> <table> <tr> <th> Pais </th> <th> Tecnico </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Pais) </td> <td> @Html.DisplayFor(modelItem => item.Tecnico) </td> <td>@Html.ActionLink("Remover","Delete", new {id = item.Id})</td> </tr> } </table>

18. Dena um mtodo Busca na classe SelecaoRepository que retorna uma entidade seleo a partir de um parmetro id. 173 K19 Treinamentos

Projeto
1 2 3 4 5 //SelecaoRepository.cs public Selecao Busca(int id) { return context.Selecoes.Find(id); }

19. Dena uma action Delete que ir mostrar a tela de conrmao de remoo da entidade.
1 2 3 4 5 6 //SelecoesController.cs public ActionResult Delete(int id) { Selecao selecao = unitOfWork.SelecaoRepository.Busca(id); return View(selecao); }

20. Dena a tela de conrmao de remoo da seleo.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <!-- ~/Views/Selecoes/Delete.cshtml --> @model K19_CopaDoMundo.Models.Selecao <h2>Remoo de Seleo</h2> <h3>Voc tem certeza que deseja remover esta entidade?</h3> <fieldset> <legend>Seleo</legend> <div class="display-label">Pais</div> <div class="display-field"> @Html.DisplayFor(model => model.Pais) </div> <div class="display-label">Tecnico</div> <div class="display-field"> @Html.DisplayFor(model => model.Tecnico) </div> </fieldset> @using (Html.BeginForm()) { <p> <input type="submit" value="Delete" /> | @Html.ActionLink("Listagem de Selees", "Index") </p> }

21. Dena um mtodo na classe SelecaoRepository que remove uma entidade seleo a partir de um parmetro id.
1 2 3 4 5 6 //SelecaoRepository.cs public void Remove(int id) { Selecao selecao = Busca(id); context.Selecoes.Remove(selecao); }

22. Dena a action que remove a seleo do banco de dados. www.k19.com.br 174

Projeto
1 2 3 4 5 6 7 8 9 //SelecoesController.cs [HttpPost] [ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { unitOfWork.SelecaoRepository.Remove(id); unitOfWork.Salva(); return RedirectToAction("Index"); }

12.16

Cadastrando, Listando e Removendo Jogadores

Na tela de jogadores, vamos adicionar um formulrio para cadastrar novos jogadores e uma tabela para apresentar os j cadastrados. Aplicaremos regras de validao especcas para garantir que nenhum dado incorreto seja armazenado no banco de dados.

12.17

Exerccios

23. Para cadastrar o jogador, devemos denir o controlador.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

using using using using using using using using

System; System.Collections.Generic; System.Data; System.Data.Entity; System.Linq; System.Web; System.Web.Mvc; K19_CopaDoMundo.Models;

namespace K19_CopaDoMundo.Controllers { public class JogadoresController : Controller { private UnitOfWork unitOfWork = new UnitOfWork(); public ActionResult Create() { ViewBag.SelecaoId = new SelectList(unitOfWork.SelecaoRepository.Selecoes, " Id", "Pais"); return View(); } protected override void Dispose(bool disposing) { unitOfWork.Dispose(); base.Dispose(disposing); } } }

24. Vamos criar uma tela Create.cshtml para cadastrar os jogadores. Adicione o arquivo a pasta Views/Jogadores com o seguinte contedo. 175 K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 <!-- ~/Views/Jogadores/Create.cshtml --> @model K19_CopaDoMundo.Models.Jogador <h2>Cadastro de Jogadores</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>Jogador</legend> <div class="editor-label"> @Html.LabelFor(model => model.Nome) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nome) @Html.ValidationMessageFor(model => model.Nome) </div> <div class="editor-label"> @Html.LabelFor(model => model.Posicao) </div> <div class="editor-field"> @Html.EditorFor(model => model.Posicao) @Html.ValidationMessageFor(model => model.Posicao) </div> <div class="editor-label"> @Html.LabelFor(model => model.Nascimento) </div> <div class="editor-field"> @Html.EditorFor(model => model.Nascimento) @Html.ValidationMessageFor(model => model.Nascimento) </div> <div class="editor-label"> @Html.LabelFor(model => model.Altura) </div> <div class="editor-field"> @Html.EditorFor(model => model.Altura) @Html.ValidationMessageFor(model => model.Altura) </div> <div class="editor-label"> @Html.LabelFor(model => model.SelecaoId, "Selecao") </div> <div class="editor-field"> @Html.DropDownList("SelecaoId", String.Empty) @Html.ValidationMessageFor(model => model.SelecaoId) </div> <p> <input type="submit" value="Salvar" /> </p> </fieldset> } <div> @Html.ActionLink("Listagem de Jogadores", "Index") </div>

25. O prximo passo denir a action que ir salvar o jogador no nosso banco de dados. Devemos tambm acrescentar as validaes a nossa entidade. www.k19.com.br 176

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 //JogadoresController.cs [HttpPost] public ActionResult Create(Jogador jogador) { if (ModelState.IsValid) { unitOfWork.JogadorRepository.Adiciona(jogador); unitOfWork.Salva(); } ViewBag.SelecaoId = new SelectList(unitOfWork.SelecaoRepository.Selecoes, " Id", "Pais"); return View(); }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

using System.ComponentModel.DataAnnotations; namespace K19_CopaDoMundo.Models { [Table("Jogadores")] public class Jogador { public int Id { get; set; } [Required(ErrorMessage="O campo Nome obrigatrio.")] public string Nome { get; set; } [Required(ErrorMessage = "O campo Posicao obrigatrio.")] public string Posicao { get; set; } [Required(ErrorMessage = "O campo Nascimento obrigatrio.")] [DataType(DataType.Date)] public DateTime Nascimento { get; set; } [Required(ErrorMessage = "O campo Altura obrigatrio.")] public double Altura { get; set; } public int SelecaoId { get; set; } [InverseProperty("Jogadores")] public virtual Selecao Selecao { get; set; } } }

26. Dena a action e a pgina para listar todas as entidades de jogador.

1 2 3 4 5

//JogadoresController.cs public ActionResult Index() { return View(unitOfWork.JogadorRepository.Jogadores); }

177

K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <!-- ~/Views/Jogadores/Index.cshtml --> @model IEnumerable<K19_CopaDoMundo.Models.Jogador> <h2>Listagem de Jogadores</h2> <p> @Html.ActionLink("Cadastrar Jogador", "Create") </p> <table> <tr> <th> Nome </th> <th> Posicao </th> <th> Nascimento </th> <th> Altura </th> <th> Selecao </th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem </td> <td> @Html.DisplayFor(modelItem </td> <td> @Html.DisplayFor(modelItem </td> <td> @Html.DisplayFor(modelItem </td> <td> @Html.DisplayFor(modelItem </td> </tr> } </table>

=> item.Nome)

=> item.Posicao)

=> item.Nascimento)

=> item.Altura)

=> item.Selecao.Pais)

12.18

Removendo Jogadores

Vamos acrescentar a funcionalidade de remover jogadores.

12.19

Exerccios

27. Acrescente uma coluna na tabela de listagem de jogadores. www.k19.com.br 178

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <!-- ~/Views/Jogadores/Index.cshtml --> @model IEnumerable<K19_CopaDoMundo.Models.Jogador> <h2>Listagem de Jogadores</h2> <p> @Html.ActionLink("Cadastrar Jogador", "Create") </p> <table> <tr> <th> Nome </th> <th> Posicao </th> <th> Nascimento </th> <th> Altura </th> <th> Selecao </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Nome) </td> <td> @Html.DisplayFor(modelItem => item.Posicao) </td> <td> @Html.DisplayFor(modelItem => item.Nascimento) </td> <td> @Html.DisplayFor(modelItem => item.Altura) </td> <td> @Html.DisplayFor(modelItem => item.Selecao.Pais) </td> <td>@Html.ActionLink("Remover", "Delete", new{id=item.Id})</td> </tr> } </table>

28. Dena um mtodo Busca na classe JogadorRepository que retorna uma entidade jogador a partir de um parmetro id.

1 2 3 4 5

//JogadorRepository.cs public Jogador Busca(int id) { return context.Jogadores.Find(id); }

29. Dena uma action Delete que ir mostrar a tela de conrmao de remoo da entidade. 179 K19 Treinamentos

Projeto
1 2 3 4 5 6 //JogadoresController.cs public ActionResult Delete(int id) { Jogador jogador = unitOfWork.JogadorRepository.Busca(id); return View(jogador); }

30. Dena a tela de conrmao de remoo do jogador.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 <!-- ~/Views/Jogadores/Delete.cshtml --> @model K19_CopaDoMundo.Models.Jogador <h2>Remoo do Jogador</h2> <h3>Voc tem certeza que deseja remover este Jogador?</h3> <fieldset> <legend>Jogador</legend> <div class="display-label">Nome</div> <div class="display-field"> @Html.DisplayFor(model => model.Nome) </div> <div class="display-label">Posicao</div> <div class="display-field"> @Html.DisplayFor(model => model.Posicao) </div> <div class="display-label">Nascimento</div> <div class="display-field"> @Html.DisplayFor(model => model.Nascimento) </div> <div class="display-label">Altura</div> <div class="display-field"> @Html.DisplayFor(model => model.Altura) </div> <div class="display-label">Selecao</div> <div class="display-field"> @Html.DisplayFor(model => model.Selecao.Pais) </div> </fieldset> @using (Html.BeginForm()) { <p> <input type="submit" value="Delete" /> | @Html.ActionLink("Listagem de Jogadores", "Index") </p> }

31. Dena um mtodo na classe JogadorRepository que remove uma entidade jogador a partir de um parmetro id.
1 2 3 4 5 6 //JogadorRepository.cs public void Remove(int id) { Jogador jogador = context.Jogadores.Find(id); context.Jogadores.Remove(jogador); }

www.k19.com.br

180

Projeto 32. Dena a action que remove o jogador do banco de dados.

1 2 3 4 5 6 7 8 9

//JogadoresController.cs [HttpPost] [ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { unitOfWork.JogadorRepository.Remove(id); unitOfWork.Salva(); return RedirectToAction("Index"); }

12.20

Membership e Autorizao

Na maioria dos casos, as aplicaes devem controlar o acesso dos usurios. Vamos implementar um mecanismo de autenticao na nossa aplicao utilizando ltro e Membership. As requisies feitas pelos usurios passaro pelo ltro. A funo do ltro vericar se o usurio est logado ou no. Se estiver logado o ltro autoriza o acesso. Caso contrrio, o ltro redirecionar o usurio para a tela de login.

12.21

Exerccios

33. Adicione a seguinte classe a pasta Models: 181 K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 using using using using using System; System.Collections.Generic; System.Linq; System.Web.Mvc; System.ComponentModel.DataAnnotations;

namespace K19_CopaDoMundo.Models { public class ChangePasswordModel { [Required] [DataType(DataType.Password)] [Display(Name = "Senha")] public string OldPassword { get; set; } [Required] [StringLength(100, ErrorMessage = "O {0} deve ter no mnimo {2} caracteres.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Nova senha")] public string NewPassword { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirmao de senha")] [Compare("NewPassword", ErrorMessage = "A senha e a confirmao no conferem.") ] public string ConfirmPassword { get; set; } } public class LogOnModel { [Required] [Display(Name = "Usurio")] public string UserName { get; set; } [Required] [DataType(DataType.Password)] [Display(Name = "Senha")] public string Password { get; set; } [Display(Name = "Lembrar?")] public bool RememberMe { get; set; } } public class RegisterModel { [Required] [Display(Name = "Usurio")] public string UserName { get; set; } [Required] [DataType(DataType.EmailAddress)] [Display(Name = "Email")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "O {0} deve ter no mnimo {2} caracteres.", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "Senha")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirmao de senha")] [Compare("Password", ErrorMessage = "A senha e a confirmao no conferem.")] public string ConfirmPassword { get; set; } } }

www.k19.com.br

182

Projeto 34. Acrescente a seguinte classe a pasta Controllers.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 using using using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; System.Web.Security; K19_CopaDoMundo.Models;

namespace K19_CopaDoMundo.Controllers { public class UsuarioController : Controller { // // GET: /Usuario/LogOn public ActionResult LogOn() { return View(); } // // POST: /Usuario/LogOn [HttpPost] public ActionResult LogOn(LogOnModel model, string returnUrl) { if (ModelState.IsValid) { if (Membership.ValidateUser(model.UserName, model.Password)) { FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe ); if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl .StartsWith("/") && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\") ) { return Redirect(returnUrl); } else { return RedirectToAction("Index", "Home"); } } else { ModelState.AddModelError("", "O usurio e/ou a senha est incorreto."); } }

return View(model); } // // GET: /Usuario/LogOff public ActionResult LogOff() { FormsAuthentication.SignOut(); return Redirect("/"); } // // GET: /Usuario/Register

183

K19 Treinamentos

Projeto
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 public ActionResult Register() { return View(); } // // POST: /Usuario/Register [HttpPost] public ActionResult Register(RegisterModel model) { if (ModelState.IsValid) { // Attempt to register the user MembershipCreateStatus createStatus; Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus); if (createStatus == MembershipCreateStatus.Success) { FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */); return Redirect("/"); } else { ModelState.AddModelError("", ErrorCodeToString(createStatus)); } }

return View(model); } // // GET: /Usuario/ChangePassword [Authorize] public ActionResult ChangePassword() { return View(); } // // POST: /Usuario/ChangePassword [Authorize] [HttpPost] public ActionResult ChangePassword(ChangePasswordModel model) { if (ModelState.IsValid) {

bool changePasswordSucceeded; try { MembershipUser currentUser = Membership.GetUser(User.Identity.Name , true /* userIsOnline */); changePasswordSucceeded = currentUser.ChangePassword(model. OldPassword, model.NewPassword); } catch (Exception) { changePasswordSucceeded = false; } if (changePasswordSucceeded) { return RedirectToAction("ChangePasswordSuccess");

www.k19.com.br

184

Projeto
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 } else { ModelState.AddModelError("", "A senha atual ou a confirmao est incorreta."); } }

return View(model); } // // GET: /Usuario/ChangePasswordSuccess public ActionResult ChangePasswordSuccess() { return View(); } #region Status Codes private static string ErrorCodeToString(MembershipCreateStatus createStatus) { // See http://go.microsoft.com/fwlink/?LinkID=177550 for // a full list of status codes. switch (createStatus) { case MembershipCreateStatus.DuplicateUserName: return "Este nome de usurio j existe. Defina outro usurio."; case MembershipCreateStatus.DuplicateEmail: return "Este email j foi cadastrado. Defina outro email."; case MembershipCreateStatus.InvalidPassword: return "Senha incorreta."; case MembershipCreateStatus.InvalidEmail: return "Email invlido."; case MembershipCreateStatus.InvalidAnswer: return "Resposta invlida para recuperar a senha."; case MembershipCreateStatus.InvalidQuestion: return "Questo invlida para recuperar a senha."; case MembershipCreateStatus.InvalidUserName: return "Usurio invlido."; case MembershipCreateStatus.ProviderError: return "Ocorreu um erro durante a autenticao. Se o problema persistir, contate o administrador."; case MembershipCreateStatus.UserRejected: return "O cadastro do usurio foi cancelado. Se o problema persistir, contate o administrador."; default: return "Um erro inesperado ocorreu. Se o problema persistir, contate o administrador."; } } #endregion } }

35. Crie uma pasta Usuario na pasta Views e acrescente os quatro arquivos abaixo. 185 K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 <!-- ~/Views/Usuario/ChangePassword.cshtml --> @model K19_CopaDoMundo.Models.ChangePasswordModel <h2>Alterao de Senha</h2> <p> Utilize o formulrio abaixo para alterar a senha </p> <p> Novas senhas devem ter no minimo @Membership.MinRequiredPasswordLength caracteres de tamanho. </p> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true, "Senha no foi alterada. Corrija os erros e tente novamente.") <div> <fieldset> <legend>Usurio</legend> <div class="editor-label"> @Html.LabelFor(m => m.OldPassword) </div> <div class="editor-field"> @Html.PasswordFor(m => m.OldPassword) @Html.ValidationMessageFor(m => m.OldPassword) </div> <div class="editor-label"> @Html.LabelFor(m => m.NewPassword) </div> <div class="editor-field"> @Html.PasswordFor(m => m.NewPassword) @Html.ValidationMessageFor(m => m.NewPassword) </div> <div class="editor-label"> @Html.LabelFor(m => m.ConfirmPassword) </div> <div class="editor-field"> @Html.PasswordFor(m => m.ConfirmPassword) @Html.ValidationMessageFor(m => m.ConfirmPassword) </div> <p> <input type="submit" value="Alterar senha" /> </p> </fieldset> </div> }

1 2 3 4 5

<!-- ~/Views/Usuario/ChangePasswordSuccess.cshtml --> <h2>Alterao de senha</h2> <p> Senha alterada com sucesso. </p>

www.k19.com.br

186

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <!-- ~/Views/Usuario/LogOn.cshtml --> @model K19_CopaDoMundo.Models.LogOnModel <h2>Autenticar</h2> <p> Entre com usurio e senha. @Html.ActionLink("Register", "Register") se voc no tiver usurio. </p> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @Html.ValidationSummary(true, "Login sem sucesso. Tente novamente") @using (Html.BeginForm()) { <div> <fieldset> <legend>Usurio</legend> <div class="editor-label"> @Html.LabelFor(m => m.UserName) </div> <div class="editor-field"> @Html.TextBoxFor(m => m.UserName) @Html.ValidationMessageFor(m => m.UserName) </div> <div class="editor-label"> @Html.LabelFor(m => m.Password) </div> <div class="editor-field"> @Html.PasswordFor(m => m.Password) @Html.ValidationMessageFor(m => m.Password) </div> <div class="editor-label"> @Html.CheckBoxFor(m => m.RememberMe) @Html.LabelFor(m => m.RememberMe) </div> <p> <input type="submit" value="Autenticar" /> </p> </fieldset> </div> }

187

K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <!-- ~/Views/Usuario/Register.cshtml --> @model K19_CopaDoMundo.Models.RegisterModel <h2>Criar novo usurio</h2> <p> Utilize o formulrio abaixo para cadastrar um novo usurio. </p> <p> As senhas devem ter no mnimo @Membership.MinRequiredPasswordLength caracteres de tamanho. </p> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript">< /script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/ javascript"></script> @using (Html.BeginForm()) { @Html.ValidationSummary(true, "Usurio no foi criado. Corrija os erros e tente novamente") <div> <fieldset> <legend>Usurio</legend> <div class="editor-label"> @Html.LabelFor(m => m.UserName) </div> <div class="editor-field"> @Html.TextBoxFor(m => m.UserName) @Html.ValidationMessageFor(m => m.UserName) </div> <div class="editor-label"> @Html.LabelFor(m => m.Email) </div> <div class="editor-field"> @Html.TextBoxFor(m => m.Email) @Html.ValidationMessageFor(m => m.Email) </div> <div class="editor-label"> @Html.LabelFor(m => m.Password) </div> <div class="editor-field"> @Html.PasswordFor(m => m.Password) @Html.ValidationMessageFor(m => m.Password) </div> <div class="editor-label"> @Html.LabelFor(m => m.ConfirmPassword) </div> <div class="editor-field"> @Html.PasswordFor(m => m.ConfirmPassword) @Html.ValidationMessageFor(m => m.ConfirmPassword) </div> <p> <input type="submit" value="Cadastrar" /> </p> </fieldset> </div> }

www.k19.com.br

188

Projeto

12.21.1

Adicionando um Usurio Administrador com ASP .NET Conguration

Antes de denir o ltro Authorize nos controladores de nosso site, vamos criar um usurio com acesso. A maneira mais fcil de criar o usurio atravs do ASP .NET Conguration.

12.22

Exerccios

36. Execute o ASP .NET Conguration.

37. Isto executar um ambiente de congurao. Abra a aba Security e clique no link Enable roles. 189 K19 Treinamentos

Projeto

38. Posteriormente, clique em Create or manage roles.

39. Dena um role Administrador e clique Add Role.

40. Clique no boto back e crie um usurio. www.k19.com.br 190

Projeto

41. Dena um usurio admin e senha admink19!.

12.22.1

Autorizao Role-based

Podemos restringir o acesso as pginas com o ltro Authorize e podemos especicar o role que o usurio precisa ter para ter acesso a pgina.

12.23

Exerccios

42. Altere o ltro de autenticao no Web.cong para redirecionar o usurio para a action LogOn do controlador Usuario.
1 2 3 4 <!-- ~/Web.config --> <authentication mode="Forms"> <forms loginUrl="~/Usuario/LogOn" timeout="2880" /> </authentication>

191

K19 Treinamentos

Projeto 43. Acrescente a seguinte string de conexo no arquivo Web.cong para denir o local que as informaes dos usurios sero armazenadas (No nosso caso, teremos duas strings de conexo).
1 2 3 4 5 6 7 8 9 10 11 <!-- ~/Web.config --> <connectionStrings> <add name="CopaDoMundoContext" providerName="System.Data.SqlClient" connectionString="Server=.\SQLEXPRESS;Database=copadomundo; User Id=sa; Password=sa;Trusted_Connection=False;Persist Security Info=True; MultipleActiveResultSets=True"/> <!-- Definindo o provedor para o Membership --> <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI; AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" /> </connectionStrings>

44. Dena o provedor padro que ser utilizado. No nosso caso, utilizaremos o provedor padro SqlMembershipProvider.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!-- ~/Web.config --> <system.web> <!-- ... --> <membership> <providers> <clear/> <add name="AspNetSqlMembershipProvider" type="System.Web.Security. SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" /> </providers> </membership> <profile> <providers> <clear/> <add name="AspNetSqlProfileProvider" type="System.Web.Profile. SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" /> </providers> </profile> <roleManager enabled="true"> <providers> <clear/> <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" /> <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security. WindowsTokenRoleProvider" applicationName="/" /> </providers> </roleManager> <!-- ... --> </system.web>

18 19 20 21 22 23 24 25 26 27 28 29

45. Acrescente o ltro de autenticao nos controladores Selecoes e Jogadores atravs do atributo Authorize. www.k19.com.br 192

Projeto
1 2 3 //SelecoesController.cs [Authorize(Roles="Administrador")] public class SelecoesController : Controller

1 2 3

//JogadoresController.cs [Authorize(Roles="Administrador")] public class JogadoresController : Controller

12.24

Controle de Erro

Podemos congurar uma pgina de erro padro para ser utilizada toda vez que um erro ocorrer.

12.25

Exerccios

46. Acrescente ao arquivo Web.cong a tag customErrors para especicar a pgina de erro padro. A tag customErrors ca dentro da tag system.web.
1 2 3 4 5 6 7 <system.web> <!-- ... --> <customErrors mode="On" defaultRedirect="~/Erro/Desconhecido"> <error statusCode="404" redirect="~/Erro/PaginaNaoEncontrada"/> </customErrors> <!-- ... --> </system.web>

47. Dena o controlador Erro e as pginas de erros padro. As pginas de erro padro sero criadas dentro da pasta Views numa subpasta Erro.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 namespace K19_CopaDoMundo.Controllers { public class ErroController : Controller { // // GET: /Erro/Desconhecido public ActionResult Desconhecido() { return View(); } // // GET: /Erro/PaginaNaoEncontrada public ActionResult PaginaNaoEncontrada() { return View(); } } }

193

K19 Treinamentos

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!-- ~/Views/Erro/Desconhecido.cshtml --> @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Problema no servidor</title> </head> <body> <h2>Desculpe, tivemos problema em nosso servidor. Volte dentro de alguns instantes. </h2> </body> </html>

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

<!-- ~/Views/Erro/PaginaNaoEncontrada.cshtml --> @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Pgina no encontrada</title> </head> <body> <h2>Pgina no encontrada</h2> </body> </html>

48. Altere o mtodo de listagem de jogadores para criar um erro em nosso site.
1 2 3 4 5 6 7 //JogadoresController.cs // GET: /Jogadores public ActionResult Index() { //return View(unitOfWork.JogadorRepository.Jogadores); return View(); }

12.26

Enviando email

Quando um erro ocorre na nossa aplicao, podemos permitir que o usurio envie uma email para os administradores do sistema. Para enviar as mensagens, podemos utilizar o Web

12.27

Exerccios

49. Altere a tela de erro adicionando um formulrio para o usurio escrever uma mensagem para os administradores da aplicao. www.k19.com.br 194

Projeto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <!-- ~/Views/Erro/Desconhecido.cshtml --> @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Problema no servidor</title> </head> <body> <h2>Desculpe, tivemos problema em nosso servidor. Volte dentro de alguns instantes. </h2> <p>Envie uma mensagem para os administradores do sistema.</p> @using (Html.BeginForm("Envia", "Email")) { <div class="editor-label"> @Html.Label("Mensagem") </div> <div class="editor-field"> @Html.TextArea("Mensagem") </div> <input type="submit" value="Enviar" /> } </body> </html>

50. Crie um controlador que envie as mensagens por email utilizando o helper WebMail. Observao, utilize usurios, senhas e emails vlidos do gmail para este exerccio.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

using using using using using using

System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; System.Web.Helpers;

namespace K19_CopaDoMundo.Controllers { public class EmailController : Controller { public EmailController() { WebMail.SmtpServer = "smtp.gmail.com"; WebMail.EnableSsl = true; WebMail.SmtpPort = 587; WebMail.From = "USUARIO@gmail.com"; WebMail.UserName = "USUARIO@gmail.com"; WebMail.Password = "SENHA"; } // // POST: /Email/Envia [HttpPost] public ActionResult Envia(string mensagem) { WebMail.Send("EMAIL", "Copa do Mundo - Erro", mensagem); return View(); } } }

195

K19 Treinamentos

Projeto 51. Crie uma pgina Envia.cshtml para mostrar ao usurio que a mensagem foi enviada com sucesso e acrescente um link para a pgina inicial do site.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <!-- ~/Views/Email/Envia.cshtml --> @{ Layout = null; } <!DOCTYPE html> <html> <head> <title>Envia</title> </head> <body> <div> Mensagem enviada com sucesso. </div> <div> @Html.ActionLink("Voltar para pgina inicial", "Index", "Selecoes") </div> </body> </html>

www.k19.com.br

196

Вам также может понравиться