SlideShare uma empresa Scribd logo
1 de 32
Baixar para ler offline
fevereiro
2014
fevereiro
2014
fevereiro
2014
03
18
Índice
Desafio The Club
30
Editorial
04
13
Autor: Hamden Vogel
05
Autor: Thiago Cavalheiro Montebugnoli
Autor: Luciano Pimenta
ASP.NET
Projeto Pegaso:
Validações no ASP.NET
MVC
Persistindo valores entre Web Forms
Aprendendo a utilizar Orientação a Objetos com Recursos
Multi-Plataforma – Novas Técnicas de Programação
fevereiro
2014
04
Delphi é marca registrada da Borland International,
as demais marcas citadas são registradas
pelos seus respectivos proprietários.
Thiago Montebugnoli- Editor Chefe
thiago@theclub.com.br
Caro amigo,
É sempre com muita alegria e satisfação que escrevo o editorial de mais
umarevista“TheClub”,procurandosanarasdúvidasesatisfazertodassuas
necessidades. Nossa equipe tem a obrigação de trazer artigos e dicas sem-
pre conectados com as últimas novidades do mundo da programação. Na
ediçãodestemês,nossocolunistaLucianoPimentacontinuacomasériede
artigos relacionados ao Asp.Net MVC, abordando um assunto de extrema
importância em cadastros, as denominadas Validações. Para que toda apli-
cação funcione da melhor maneira possível é necessário que os dados dos
usuários estejam íntegros, portanto o papel das validações é fundamental
nesta etapa de desenvolvimento. Neste mês apresento diversas formas
parapersistirvaloresentreWebForms,comoartigo“Asp.Net–Persistindo
valores entre Web Forms” com explicações e exemplos práticos. Discorro
sobre Variáveis de Sessões, QueryString, entre outras técnicas para obter
este resultado. Para finalizar com estilo, nosso colaborador Hamden Vogel,
comaprimeirapartedoartigo“ProjetoPegaso,aprendendoautilizarOrien-
taçãoaObjetoscomRecursosMulti-Plataforma”,comoopróprionomediz,
neste artigo são apresentadas inúmeras dicas e recursos para quem deseja
aprender e aprimorar conceitos de Orientação a Objetos utilizando um
projeto teste de exemplo.
Vou ficando por aqui desejando a todos uma boa leitura e que tirem o
maiorproveitodenossosartigos.Lembrandoquenossaequipeestásempre
aberta a críticas e sugestões.
Um Forte abraço,
Av. Profº Celso Ferreira da Silva, 190
Jd. Europa - Avaré - SP - CEP 18.707-150
Informações e Suporte: (14) 3732-1529
Internet
http://www.theclub.com.br
Cadastro: cadastro@theclub.com.br
Suporte: suporte@theclub.com.br
Informações: info@theclub.com.br
Skype Cadastro: theclub_cadastro
Skype Suporte: theclub_linha1
theclub_linha2
theclub_linha3
www.twitter.com/theclubbr
Copyright The Club 2013
Diretor Técnico
Marcos César Silva
Diagramação
Vitor M. Rodrigues
Design
Vitor M. Rodrigues
Revisão
Drielly Cristini Patrinhani
Colunistas
Hamden Vogel
Jeferson Silva de Lima
Luciano Pimenta
Thiago Cavalheiro Montebugnoli
Juninho
Jeferson Silva de Lima
Impressão e acabamento:
GRIL - Gráfica e Editora
Taquarituba-SP - Tel. (14) 3762-1345
Reprodução
A utilização, reprodução, apropriação, armazenamento em banco
de dados, sob qualquer forma ou meio, de textos, fotos e outras
criações intelectuais em cada publicação da revista “The Club
Megazine” são terminantemente proibidos sem autorização
escrita dos titulares dos direitos autorais.
Editorial
fevereiro
2014
05
Listagem 01: Código da Página 01.
Q
uando começamos a programar para web, uma das dú-
vidas mais freqüentes é: Como devemos persistir valores
entre Web Forms? Praticamente a maioria dos softwares
háanecessidadederecuperarvaloresentreFormulários,
em se tratando de Asp.Net seriam os denominados Web
Forms.Porexemplo,Imaginemaseguintesituação,temosumapáginaondeos
usuáriosirãorealizarumCadastrodeClientesenapáginaseguintedeveremos
transportarestesmesmosdadosparaumprocessamento,ondeosdadosdeve-
rãoserarmazenadose“lidos”.Ondeficarãoarmazenadosestesdados?Como
devemos tratá-los? Este artigo irá abordar as diversas formas de persistirem
estes valores. Temos diversos artifícios para trabalhar, como por exemplo:
• Variáveis de sessão (Session)
• QueryString
• Método Server.Transfer
• Classe HttpContext
Gostaria de exemplificar de uma forma simples todas as técnicas acima
descritas.Antesdeiniciarmosiremoscriarumprojetobaseparaoaprendizado.
ParaistoabraoMicrosoftVisualStudioecrieumapáginadoZero,adicionando
umWebFormpadrão(paraEnviarosdados)enomeucasoacheimelhorcriar
um Web Form para cada tipo de técnica citada anteriormente. Abaixo deixo
uma sugestão de lay-out para Envio e Recebimento.
NaFigura01foramadicionadosalgunsTextBoxs,como:Nome,Endereço,
Cidade, Estado, Tipo (Estes são os campos que iremos passar para a Página
seguinte). Foram adicionados um botão para cada técnica, sendo: Session,
QueryString, Server Transfer e HttpContext.
Veja a Figura 01.
ASP.NET - Persistindo
valores entre Web Forms
Figura 01: WebForm para Envio de dados.
Aproveito também para inserir o trecho principal do código em Aspx.
Veja Listagem 01.
<form id=”form1” runat=”server”>
<table class=”style1”
width=”380”>
<tr>
<td colspan=”2”
style=”text-align: center”>
<asp:Label
ID=”Label2” runat=”server”
ForeColor=”#000066”
style=”font-weight: 700; font-
size: large; font-family:
Arial, Helvetica, sans-serif;
text-decoration: underline;
font-style: italic;”
Text=”ASP.NET - Persistindo
valores entre Web Forms”></
asp:Label>
fevereiro
2014
06
</td>
</tr>
<tr>
<td colspan=”2”
style=”text-align: center”>
<asp:Label
ID=”Label1” runat=”server”
ForeColor=”#000066”
style=”font-weight: 700; font-
size: large; font-family:
Arial, Helvetica, sans-serif”
Text=”Página
01 - Enviar Dados”></asp:Label>
</td>
</tr>
<tr>
<td>
&nbsp;</td>
<td>
&nbsp;</td>
</tr>
<tr>
<td>
<asp:Label ID=”lblNome”
runat=”server” CssClass=”style3”
Text=”Nome:”></asp:Label>
</td>
<td>
<asp:TextBox ID=”txtNome”
runat=”server” CssClass=”style4”
Height=”20px” Width=”300px”
ClientIDMode=”Inherit”></
asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:Label ID=”lbEndereco”
runat=”server” CssClass=”style3”
Text=”Endereço:”></asp:Label>
</td>
<td>
<asp:TextBox ID=”txtEndereco”
runat=”server” CssClass=”style4”
Height=”20px”
Width=”300px”></asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:Label ID=”lblCidade”
runat=”server” CssClass=”style3”
Text=”Cidade:”></asp:Label>
</td>
<td>
<asp:TextBox ID=”txtCidade”
runat=”server” CssClass=”style4”
Height=”20px”
Width=”200px”></asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:Label ID=”lblEstado”
runat=”server” CssClass=”style3”
Text=”Estado:”></asp:Label>
</td>
<td>
<asp:TextBox ID=”txtEstado”
runat=”server” CssClass=”style4”
Height=”20px” Width=”150px”></
asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:Label ID=”lblTipo”
runat=”server” CssClass=”style3”
Text=”Tipo:”></asp:Label>
</td>
<td>
<asp:DropDownList ID=”dropTipo”
runat=”server” CssClass=”style4”
Height=”20px”
Width=”150px”>
<asp:ListItem></asp:ListItem>
<asp:ListItem Value=”F”>Física</
asp:ListItem>
<asp:ListItem
Value=”J”>Jurídica</
asp:ListItem>
</
asp:DropDownList>
</td>
</tr>
<tr>
<td>
&nbsp;</td>
<td>
&nbsp;</td>
</tr>
<tr>
<td class=”style2”
colspan=”2”>
<asp:Button
ID=”btnEnviarSession”
runat=”server”
style=”font-
fevereiro
2014
07
Listagem 02. Código da Página 02.
family: Arial, Helvetica, sans-
serif”
Text=”Session” Width=”260px”
onclick=”btnEnviar_Click” />
</td>
</tr>
<tr>
<td class=”style2”
colspan=”2”>
<asp:Button
ID=”btnEnviarquerystring”
runat=”server”
style=”font-
family: Arial, Helvetica, sans-
serif”
Text=”QueryString” Width=”260px”
onclick=”btnEnviarquerystring_
Click” />
</td>
</tr>
<tr>
<td class=”style2”
colspan=”2”>
<asp:Button
ID=”btnEnviarServerTransfer”
runat=”server”
style=”font-
family: Arial, Helvetica, sans-
serif”
Text=”Server
Transfer” Width=”260px”
onclick=”bt
nEnviarServerTransfer_Click” />
</td>
</tr>
<tr>
<td class=”style2”
colspan=”2”>
<asp:Button
ID=”btnEnviarHttpContext”
runat=”server”
style=”font-family: Arial,
Helvetica, sans-serif”
Text=”HttpContext” Width=”260px”
onclick=”btnEnviarHttpContext_
Click” />
</td>
</tr>
</table>
<div>
</div>
</form>
Abaixo o lay-Out da Página para receber os dados, contendo 5 Labels,
sendo: Nome, Endereço, Cidade, Estado e Tipo. Cada componente irá receber
o seu correspondente da página anterior. Ver Imagem 02.
Figura 02: WebForm de recebimento de dados.
O trecho principal do código em Aspx. Veja Listagem 02.
<form id=”form1” runat=”server”>
<table class=”style1”
width=”380”>
<tr>
<td colspan=”2”
style=”text-align: center”>
<asp:Label
ID=”Label1” runat=”server”
ForeColor=”#000066”
style=”font-weight: 700; font-
size: large; font-family:
Arial, Helvetica, sans-serif”
Text=”Página 02 - Receber
Dados”></asp:Label>
</td>
</tr>
<tr>
<td class=”style6”>
&nbsp;</td>
<td>
&nbsp;</td>
</tr>
<tr>
<td class=”style4”
colspan=”2”>
<asp:Label
ID=”lblInformativo”
runat=”server”
ForeColor=”#000066”
style=”font-weight: 700; font-
size: large; font-family:
Arial, Helvetica, sans-
serif”>Session</asp:Label>
</td>
</tr>
<tr>
fevereiro
2014
08
Listagem 03: Código para atribuir valores para as variáveis de sessão.
<td class=”style6”>
<asp:Label ID=”lblNome”
runat=”server” CssClass=”style3”
Text=”Nome:”></asp:Label>
</td>
<td>
<asp:Label ID=”lblNomeRec”
runat=”server”
CssClass=”style5”></asp:Label>
</td>
</tr>
<tr>
<td class=”style6”>
<asp:Label ID=”lblEndereco”
runat=”server” CssClass=”style3”
Text=”Endereço:”></asp:Label>
</td>
<td>
<asp:Label ID=”lblEnderecoRec”
runat=”server”
CssClass=”style5”></asp:Label>
</td>
</tr>
<tr>
<td class=”style6”>
<asp:Label ID=”lblCidade”
runat=”server” CssClass=”style3”
Text=”Cidade:”></asp:Label>
</td>
<td>
<asp:Label ID=”lblCidadeRec”
runat=”server”
CssClass=”style5”></asp:Label>
</td>
</tr>
<tr>
<td class=”style6”>
<asp:Label ID=”lblEstado”
runat=”server” CssClass=”style3”
Text=”Estado:”></asp:Label>
</td>
<td>
<asp:Label ID=”lblEstadoRec”
runat=”server”
CssClass=”style5”></asp:Label>
</td>
</tr>
<tr>
<td class=”style6”>
<asp:Label ID=”lblTipo”
runat=”server” CssClass=”style3”
Text=”Tipo:”></asp:Label>
</td>
<td>
<asp:Label ID=”lblTipoRec”
runat=”server”
CssClass=”style5”></asp:Label>
</td>
</tr>
<tr>
<td class=”style2”
colspan=”2”>
&nbsp;</td>
</tr>
</table>
<div>
</div>
</form>
1-) Variáveis de Sessão
As variáveis de Sessão fornecem uma facilidade para armazenar infor-
mações na memória do servidor podendo suportar qualquer tipo de objeto.
Paracadacliente,osdadosdasessãosãoarmazenadosseparadamente,oque
significaqueestesdadossãoarmazenadosemumabaseporcliente.Umasde
suasvantagenséqueaoutilizá-lamantemosoestadodousuárioeosdadosde
todooaplicativosecomportandodeformatotalmenteseguraetransparente.
Seguindonossoexemplo,paraarmazenarosdadosnasessãoutilizaremos
o código abaixo: Ver Listagem 03.
protected void btnEnviar_
Click(object sender, EventArgs
e)
{
Session[“nome”] = txtNome.
Text;
Session[“endereco”] =
txtEndereco.Text;
Session[“cidade”] =
txtCidade.Text;
Session[“estado”] =
txtEstado.Text;
Session[“tipo”] =
dropTipo.SelectedItem;
Response.
Redirect(“WebFormSession.
aspx”);
}
Podemoscriarquantasvariáveisdesessãoquedesejarecomonomeque
acharmos melhor. Seguiremos o padrão, respeitando a ordem dos campos.
Atribuímos os valores dos Componentes e logo em seguida com o comando
“Response.Redirect” redirecionamos para a página onde iremos receber os
valores destas variáveis. Iremos receber os dados no evento Page_Load() do
WebForm, Ver Listagem 04.
fevereiro
2014
09
Listagem 04: Código para receber valores das variáveis de sessão.
Listagem 05: Código para enviar valores das Querystring
Listagem 06: Código para receber valores da Querystring.
protected void Page_Load(object
sender, EventArgs e)
{
if (!Page.IsPostBack)
{
lblNomeRec.Text =
Session[“nome”].ToString();
lblEnderecoRec.Text =
Session[“endereco”].ToString();
lblCidadeRec.Text =
Session[“cidade”].ToString();
lblEstadoRec.Text =
Session[“estado”].ToString();
lblTipoRec.Text =
Session[“tipo”].ToString();
}
}
Para receber os valores, devemos atribuir para a propriedade “Text” dos
componentes. No caso estamos trabalhando com campos do tipo texto, mas
ressalto que poderíamos receber um Objeto inteiro de qualquer tipo que o
trabalho seria idêntico ao descrito acima.
2-) Querystring
A “Querystring” é um modelo clássico e talvez o mais utilizado em
sistemas Web. A única desvantagem no uso deste recurso é que os valores
passados serão visíveis no Navegador e não conseguimos passar objetos.
Recomendado para valores pequenos (limite de 255 caracteres) e que não
necessitamdesegurança.Ousoémuitosimples,aoredirecionarmosparauma
determinadapágina,adicionamosoprimeirovalorusandoaseguintesintaxe:
(?Chave=valor). No caso para passarmos mais de um conjunto de valores
devemos ir concatenando com o caractere coringa (&). Podemos conferir um
exemplo conforme nos ensina na listagem 05.
protected void
btnEnviarquerystring_
Click(object sender, EventArgs
e)
{
string dadosPagina;
dadosPagina =
“WebFormQueryString.aspx?nome=”
+ txtNome.Text +
“&endereco=” + txtEndereco.
Text +
“&cidade=” + txtCidade.
Text +
“&estado=” + txtEstado.
Text +
“&tipo=” + dropTipo.
SelectedItem;
Response.
Redirect(dadosPagina);
}
No primeiro momento criamos uma variável do tipo “string”, passando a
página(WebFormQueryString.aspx)seguidodospareschave/valorconcatena-
dopelocoringa(&).Ométodo“Response.Redirect”iránosredirecionarparaa
segunda página onde iremos carregar estes valores. Listagem 06.
protected void Page_Load(object
sender, EventArgs e)
{
if (!Page.IsPostBack)
{
lblNomeRec.Text = Request.
QueryString[“nome”];
lblEnderecoRec.Text =
Request.QueryString[“endereco”];
lblCidadeRec.Text =
Request.QueryString[“cidade”];
lblEstadoRec.Text =
Request.QueryString[“estado”];
lblTipoRec.Text = Request.
QueryString[“tipo”];
}
}
É recomendável sempre utilizar o evento Page_Load para carregar estes
parâmetros.Ométodo“Request.QueryString”identificaachaveenosretorna
o valor inserido. Armazenaremos os resultados em Labels.
3-) Método Server Transfer
Podemos dizer que o método “Server.Transfer” visivelmente possui o
mesmo resultado do conhecido método “Server.Redirect”, nos locomovendo
deumapáginaparaoutra.Adiferençaqueaousarométodo“Server.Transfer”
oservidorconservaosrecursosjáutilizados,ouseja,aoinvésdesimplesmente
redirecionarparaoutrapágina,eleapenasalteraofoconoservidoretransfere
toda a requisição. Devemos tomar cuidado, pois, o processo de transferência
pode operar somente em sites que estão rodando no servidor, lembrando
que não podemos utilizar este método para uma página externa ao servidor.
Outro detalhe interessante é que o “Server.Transfer” mantém a URL original
noBrowser. Paraentendermosmelhorfaremosousoconformealistagem07.
fevereiro
2014
10
Listagem 07: Código para enviar valores via Método “Server.Transfer”.
Listagem 08: Código para receber valores via Método “Server.Transfer”.
Listagem 09: Código para enviar valores via classe “HTTPContext”.
Listagem 10: Código para enviar valores via classe “HTTPContext”.
protected void
btnEnviarServerTransfer_
Click(object sender, EventArgs
e)
{
Server.
Transfer(“WebFormServerTransfer.
aspx”, true);
}
Nó código acima temos um segundo parâmetro booleano denominado
“preserveForm”. Estamos definindo para “True” sendo assim a consulta exis-
tente e qualquer variável de formulário ficará disponível para a página para a
qual você esta fazendo a transferência. Para recuperarmos faremos conforme
a Listagem 08.
protected void Page_Load(object
sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var form = Request.
Form;
lblNomeRec.Text =
form[“txtNome”];
lblEnderecoRec.Text =
form[“txtEndereco”];
lblCidadeRec.Text =
form[“txtCidade”];
lblEstadoRec.Text =
form[“txtEstado”];
lblTipoRec.Text =
form[“dropTipo”];
}
}
Noprimeiroatofoicriadaumavariáveldotipo“var”,recebendoosvalores
do método “Request.Form”. Ao fazermos esta referência automaticamente
conseguimos recuperar qualquer valor do webform anteriormente utilizado.
Usaremos os valores dos Textboxes e do DropDownlist.
4-) Classe HttpContext
Através desta classe podemos obter outras classes para manipulações de
objetos. Ela encapsula todas as informações específicas sobre uma requisição
HTTP, o objeto “HTTPContext” fornece acesso aos objetos em questão. É
importante lembrar que os valores armazenados neste objeto serão válidos
somente durante a duração de uma requisição. Ver Listagem 09.
protected void
btnEnviarHttpContext_
Click(object sender, EventArgs
e)
{
HttpContext contexto =
HttpContext.Current;
contexto.Items[“nome”] =
txtNome.Text;
contexto.Items[“endereco”]
= txtEndereco.Text;
contexto.Items[“cidade”] =
txtCidade.Text;
contexto.Items[“estado”] =
txtEstado.Text;
contexto.Items[“tipo”] =
dropTipo.SelectedItem;
Server.
Transfer(“WebFormHttpContext.
aspx”);
}
Primeiramente instancie o objeto “HTTPContext” atribuindo o contexto
corrente da aplicação. Podemos atribuir quais valores desejarmos utilizando
o método “Items”. Utilizamos o mesmo comando abordado anteriormente, o
Server.Transfer, sendo que desta vez passamos por parâmetro apenas alguns
valores.Parareceberestesdadosfaremosocontrário,usandoamesmalógica
de raciocínio. Ver Listagem 10.
protected void Page_Load(object
sender, EventArgs e)
{
if (!Page.IsPostBack)
{
HttpContext contexto =
HttpContext.Current;
lblNomeRec.Text = contexto.
Items[“nome”].ToString();
lblEnderecoRec.Text =
contexto.Items[“endereco”].
ToString();
lblCidadeRec.Text = contexto.
Items[“cidade”].ToString();
lblEstadoRec.Text = contexto.
Items[“estado”].ToString();
lblTipoRec.Text = contexto.
Items[“tipo”].ToString();
}
}
fevereiro
2014
11
Listagem 11: Classe Usuário.
Listagem 12: Código para enviar valores via Session.
Lembrandoqueaoutilizarestaclasseestamosrestritosapenasaosobjetos
definidos dentro do método “Context.Current.Items”.
Uma dica sobre as variáveis de Sessão
Umaideiaparaquemarmazenamuitasinformaçõesnasvariáveisdesessão
seriacriarumaclasseparaestatarefa.Umexemplomuitoclaroparaistoseria
para quem trabalha com dados de usuários, se tornando mais objetiva tanto
para armazenar quanto para recuperar os campos envolvidos. Possuímos os
mesmos campos descritos acima nesta classe. É necessário implementar os
métodos “Get” e “Set”. Para quem não sabe, criar uma classe no Asp.Net é
muito simples, basta clicar com o botão direito sobre a solução e escolher a
opção“Add/NewItem...”.Definaonomecomo:“Usuario.cs”.VerListagem11.
public class Usuario
{
public Usuario()
{
}
private string _NOME;
public string NOME
{
get { return _NOME; }
set { _NOME = value; }
}
private string _ENDERECO;
public string ENDERECO
{
get { return _ENDERECO;
}
set { _ENDERECO =
value; }
}
private string _CIDADE;
public string CIDADE
{
get { return _CIDADE; }
set { _CIDADE = value;
}
}
private string _ESTADO;
public string ESTADO
{
get { return _ESTADO; }
set { _ESTADO = value;
}
}
private string _TIPO;
public string TIPO
{
get { return _TIPO; }
set { _TIPO = value; }
}
}
Seguindoamesmatelacriadaanteriormente,iremoscodificarobotãoda
seguinte maneira, Ver Listagem 12.
protected void
btnEnviarSessionObjeto_
Click(object sender, EventArgs
e)
{
Usuario usuario = new
Usuario();
usuario.NOME = txtNome.
Text;
usuario.ENDERECO =
txtEndereco.Text;
usuario.CIDADE = txtCidade.
Text;
usuario.ESTADO = txtEstado.
Text;
usuario.TIPO = dropTipo.
SelectedItem.ToString();
Session.Add(“USUARIO”,
usuario);
Response.Redirect(“~/
WebFormSessionObjeto.aspx”);
}
Instancie a classe “Usuario” e alimente os seus atributos conforme os
valoresdoscomponentes.Oprincipalcomandoéo“Session.Add”,énesteato
queadicionamosoObjetocomovariáveldesessão.Paraefetuaraleituradestes
dados faremos um “TypeCast” para a classe “Usuário” para posteriormente
irmos recuperando os dados. Ver Listagem 13.
fevereiro
2014
12
Listagem 13: Código para receber valores via Session.
protected void Page_Load(object
sender, EventArgs e)
{
if (!Page.IsPostBack)
{
lblNomeRec.Text = ((Usuario)
Session[“USUARIO”]).NOME.
ToString();
lblEnderecoRec.Text =
((Usuario)Session[“USUARIO”]).
ENDERECO.ToString();
lblCidadeRec.Text = ((Usuario)
Session[“USUARIO”]).CIDADE.
ToString();
lblEstadoRec.Text = ((Usuario)
Session[“USUARIO”]).ESTADO.
ToString();
lblTipoRec.Text = ((Usuario)
Session[“USUARIO”]).TIPO.
ToString();
}
} thiago@theclub.com.br
Thiago Cavalheiro Montebugnoli
adora aprender novas tecnologias. Formado pela Faculdade de Tecnologia de Botucatu
– SP (FATEC), já desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco
de Dados SQL Server e Firebird. Atualmente trabalha no Centro de Processamento de Dados da
Prefeitura Municipal de Itaí-SP é colunista mensal da Revista The Club Megazine e é consultor
Técnico do The Club. Possui as seguintes certificações: MCP - Microsoft Certified Professional,
MCTS-MicrosoftCertifiedTechnologySpecialist,MCAD-MicrosoftCertifiedApplicationDeveloper
e MCSD - Microsoft Certified Solution Developer.
Sobre o autor
Conclusões
Pudemos aprender neste artigo diversas maneiras de resolver o mesmo
tipodeproblema,trabalhandocomVariáveisdeSessão,Querystring,oMétodo
Server.TransfereaclasseHttpContext.Ficaacargododesenvolvedorescolher
a melhor técnica a seguir.
Abraços e até o mês que vem!
fevereiro
2014
13
Mostramos anteriormente,emdois artigos, as características do ASP.NET
MVC. Neste artigo, quero falar exclusivamente de validações, pois é uma das
funcionalidades mais importantes para cadastros de aplicações Web.
Para que a sua aplicação funcione da melhor maneira possível, é neces-
sário que os dados oriundos dos usuários sejam os mais corretos (falando
em termos de integridade), assim temos a necessidade de validá-los antes
de inserir no banco.
Mostrarei nesse artigo como validar no ASP.NET MVC, verificando os
dados na Action e usando DataAnnotattions, uma facilidade onde indicamos
no Model o que queremos validar.
Validações no
ASP.NET MVC
Criando a aplicação
Vamoscriarumaaplicaçãosimples,paraquepossamosmostrarosexem-
plos de validações para serem usadas em aplicações Web com ASP.NET MVC.
Crie um novo projeto ASP.NET MVC 4 Web Application (Figura 1).
Veja a Figura 1.
Vamos usar o template Basic no projeto. Com o projeto criado, vamos
criar um modelo, conforme a Listagem 1.
Figura 1. Criando uma aplicação ASP.NET MVC
fevereiro
2014
14
Listagem 1. Criando o modelo
Listagem 2. Criando o contexto da aplicação
Listagem 3. Criando o controller
using System;
using System.ComponentModel.
DataAnnotations;
namespace Validacoes.Models
{
public class Pessoa
{
[Key]
public int ID { get;
set; }
public string Nome {
get; set; }
public DateTime
Nascimento { get; set; }
public string Login {
get; set; }
public string Email {
get; set; }
}
}
Crie também o Context, como podemos ver na Listagem 2.
using System.Data.Entity;
using Validacoes.Models;
namespace Validacoes.
Controllers
{
public class Contexto:
DbContext
{
public DbSet<Pessoa>
Pessoas { get; set; }
}
}
Vamos criar agora, o Controller (Figura 2).
Veja a Figura 2.
Nota: caso deseje pode usar a técnica de templates
com scaffolding. Resolvi fazer manualmente para mostrar
como seria sem a técnica.
Agora, vamos modificar o Controller (Listagem 3).
using System.Linq;
using System.Web.Mvc;
using Validacoes.Models;
namespace Validacoes.
Controllers
{
public class
PessoaController : Controller
{
private Contexto db =
new Contexto();
public ActionResult
Index()
{
return View(db.
Pessoas.ToList());
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult
Create(Pessoa pessoa)
{
if (ModelState.
IsValid)
{
db.Pessoas.
Add(pessoa);
db.SaveChanges();
Figura 2. Criando o controller da Pessoa
fevereiro
2014
15
Listagem 4. Validando na action
Listagem 5. View de cadastro de Pessoa
return
RedirectToAction(“Index”);
}
return View(pessoa);
}
}
}
Porenquanto,temosapenasdoismétodos.Umqueretornaumalistacom
os registros (Index) e outro que insere os registros (Create).
Validando na Action
NoASP.NETMVCnãotemososcontrolesValidators,comonoASP.NETWeb
Forms. Assim, podemos criar a validação na Action que cadastra o registro.
Veja na Listagem 4, como podemos fazer a validação no Create.
[HttpPost]
public ActionResult
Create(Pessoa pessoa)
{
if (string.
IsNullOrEmpty(pessoa.Nome))
ModelState.
AddModelError(“Nome”,
“Campo Nome: preenchimento
obrigatório.”);
if (string.
IsNullOrEmpty(pessoa.Login))
ModelState.
AddModelError(“Login”,
“Campo Login: preenchimento
obrigatório.”);
if (string.
IsNullOrEmpty(pessoa.Email))
ModelState.
AddModelError(“Email”,
“Campo Email: preenchimento
obrigatório.”);
if ((DateTime.Now.Year -
pessoa.Nascimento.Date.Year) <
18)
ModelState.
AddModelError(“Nascimento”,
“Campo Nascimento: A idade deve
ser maior que 18 anos.”);
if (ModelState.IsValid)
{
db.Pessoas.Add(pessoa);
db.SaveChanges();
return
RedirectToAction(“Index”);
}
return View(pessoa);
}
A validação é bem simples, pois verificamos se o campo tem valores e
adicionamos em ModelState.AddModelError, o nome do campo (parâmetro
pede uma chave) e a respectiva mensagem de erro. Fizemos uma validação
para que o cadastro aceite apenas Pessoas maiores de 18 anos.
Vamos criar a View que vai usar a Action do cadastro. Veja na Listagem 5,
a View do cadastro de Pessoa.
@model Validacoes.Models.Pessoa
@{
ViewBag.Title = “Create”;
}
<h2>Create</h2>
@using (Html.BeginForm()) {
@Html.
ValidationSummary(true)
<fieldset>
<legend>Pessoa</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.Nascimento)
</div>
<div class=”editor-
field”>
@Html.
fevereiro
2014
16
Listagem 6. Marcando o modelo com DataAnnotation
TextBoxFor(model => model.
Nascimento)
@Html.
ValidationMessageFor(model =>
model.Nascimento)
</div>
<div class=”editor-
label”>
@Html.LabelFor(model
=> model.Login)
</div>
<div class=”editor-
field”>
@Html.
EditorFor(model => model.Login)
@Html.
ValidationMessageFor(model =>
model.Login)
</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=”Salvar” />
</p>
</fieldset>
}
<div>
@Html.ActionLink(“Lista”,
“Index”)
</div>
O “segredo” para apresentar as mensagens, é usar o ValidationSumary e
ValidationMessageFor.CasonãousassemosoValidationMessageFor,amensa-
gem não é apresentada, somente o campo fica com a cor em vermelho. Rode
a aplicação e veja na Figura 3 o resultado.
Nota: Precisamos criar um cController Home para chamar a tela
de cadastro.
Figura 3. Validando o cadastro de Pessoa
Validando com DataAnnotattion
A validação anterior funciona, mas imagine uma quantidade grande de
camposnocadastro,otrabalhoéoneroso,semfalarqueprecisamosadicionar
nessa Action mais validações, se mais campos forem incluídos no modelo.
Umamaneirafácildevalidar,éusandoDataAnotattionnomodelo.Temos
queapenas“marcar”cadapropriedadedomodelo.Essamarcaçãoindicaseo
campoéobrigatório,quantidadedecaracterespermitidos,usodeexpressões
regulares etc.
Veja na Listagem 6 como fica o modelo com DataAnnotattion.
[Required(ErrorMessage=”Campo
Nome: preenchimento
obrigatório.”)]
[StringLength(35,
ErrorMessage=”Campo Nome: aceita
no máximo 35 caracteres.”)]
public string Nome { get; set;
}
[Remote(“ValidaIdade”,
“Pessoa”,
ErrorMessage = “Campo
Nascimento: A idade deve ser
maior que 18 anos.”)]
public DateTime Nascimento {
get; set; }
[Required(ErrorMessage =
“Campo Login: preenchimento
obrigatório.”)]
[StringLength(15, ErrorMessage
= “Campo Login: aceita no
máximo 15 caracteres.”)]
public string Login { get; set;
}
[Required(ErrorMessage =
fevereiro
2014
17
Listagem 7. Validando o campo Nascimento com método no Controller
“Campo Email: preenchimento
obrigatório.”)]
[RegularExpression(@”^[A-
Za-z0-9]
(([_.-]?[a-zA-Z0-9]+)*)@
([A-Za-z0-9]+)
(([.-]?[a-zA-Z0-9]+)*).
([A-Za-z]{2,})$”,
ErrorMessage = “Campo Email:
valor inválido.”)]
[EmailAddress(ErrorMessage=”Cam
po Email: valor inválido.”)]
public string Email { get; set;
}
Vamos explicar qual a característica de cada um.
O Required indica que o campo é obrigatório e um dos seus parâmetros
é a mensagem de erro (assim como temos nos outros).
StringLength permite que possamos definir um tamanho para a string,
assim indicamos no parâmetro o tamanho e no outro a mensagem.
Em RegularExpression podemos indicar uma expressão regular. Nesse
caso, é para validar o e-mail (código retirado da internet). Também podemos
validaroe-mailcomoEmailAddress,maseleestapresentesomentenaversão
4.5 do .NET Framework. Lembre-se disso.
Porfim,oRemote,possibilitaquepossamosusarummétodoparavalidaro
campo.Assim,indicamosométodo,ocontrollereamensagemdeerro.Muito
eficiente para validações que precisamos pesquisar no banco para verificar se
o campo é único, por exemplo, como o login.
No exemplo, vamos apenas validar se a data informada é maior que 18
anos, semelhante ao feito anteriormente. Veja na Listagem 7 o código do
método no PessoaController.
[AllowAnonymous]
public JsonResult
ValidaIdade(DateTime Nascimento)
{
var result = (DateTime.Now.
Year - Nascimento.Date.Year) >
18;
return Json(result,
JsonRequestBehavior.AllowGet);
}
Note que o retorno do método é um JsonResult. Dentro do método, veri-
ficamos se a idade é maior que 18 e retornamos o Json, com o parâmetro da
validação. Na View precisamos adicionar a biblioteca de validação do jQuery.
Adicione no final do arquivo o seguinte código:
@section Scripts {
@Scripts.Render(“~/bundles/
jqueryval”)
}
Executeaaplicaçãoetentesalvarumadatadenascimentoqueovalorda
idade seja menor que 18 (Figura 4).
Figura 4. Validando no servidor a idade da Pessoa
Note que é essencial o uso da biblioteca do jQuery para que a validação
funcionecorretamente.AfacilidadedeDataAnnotattionsproporcionaodesen-
volvimentodemodelosrobustosefáceisdeseremmodificados(manutenção).
Conclusões
VimosnesteartigocomotrabalharcomvalidaçõesemaplicaçõesASP.NET
MVC. Podemos notar que a quantidade de possibilidades é grande, deixando
a cargo do desenvolvedor, escolher a que mais se adapta a sua aplicação.
Validações de dados em ambiente Web são muito importantes, pois não
da margem para mal intencionados acessariam sua aplicação. Já trabalhei em
projetos que era solicitado que se fizesse validação no cliente e no servidor,
então, caso seja a sua necessidade, vimos nesse artigo as duas possibilidades
em aplicações ASP.NET MVC.
Um grande abraço a todos e até a próxima!
www.lucianopimenta.net
Luciano Pimenta
LucianoPimenta(NOVODOMINIO:www.lucianopimenta.com)édesenvolvedorDelphi/C#
paraaplicaçõesWebcomASP.NET,WindowscomWin32eWindowsFormscom.NET.Palestrante
da 4ª edição da Borland Conference (BorCon) e da 1ª Delphi Conference.
É MVP Embarcadero, grupo de profissionais que ajudam a divulgar o Delphi no mundo.
Atualmente é desenvolvedor da SoftDesign fábrica de softwares em Porto Alegre-RS.
Autor de mais de 90 artigos e de mais de 600 vídeos aulas publicadas em revistas e sites
especializados, além de treinamentos presenciais e multimídias. É consultor da FP2 Tecnologia
(www.fp2.com.br) onde ministra cursos de programação e banco de dados.
Sobre o autor
fevereiro
2014
18
O
Desenvolvimento de Software sempre trouxe técnicas
inovadoras, através do seu próprio processo de trabalho
ondedesenvolvedoresdeumdeterminadoprojetopodem
aprender com seus erros e compartilhar soluções, muitas
delas adquiridas com tempo, paciência, dedicação e não
por último aprendizado.
Ressaltei em artigos anteriores a importância de uma implementação de
recursos em mais de um ambiente, batizando de multiplataforma um concei-
to flexível e eficiente para o gestor que exige uma aplicação independente
do ambiente em que está rodando – experiência própria – portanto fica o
aprendizado e a sua transmissão no decorrer deste artigo em que procuro
abordar alguns tópicos produtivos e que podem ser estendidos com tamanha
profundidade e dinamismo.
Para este artigo será utilizado um aplicativo de demonstração (fictício) –
baseadoemumexistenteprofissionalmente–emqueserãodemonstradasas
funcionalidades em tempo de execução e como o código correspondente foi
escritoeassociadoàportabilidadedaideiaprincipaldesteartigo.Estánascendo
o nosso “Projeto Pegaso” (poderia ser qualquer nome).
O Framework Itil já dizia: “As Empresas buscam inovar seus processos
para se tornarem mais eficientes e competitivas. Inovações que dão certo
transformam-seemmelhorespráticas”.Estaimplementaçãojáfoidevidamente
testada, é livre, tem uma boa resposta de execução, é acessível a todos e por
issojustifica-seemumaboapráticadeserviço.Inovaçõesbemimplementadas
atravésderequisitosexigentesebemdocumentadospodemserbeneficiadas
futuramente com o ganho de produtividade e performance em que o ciclo do
projeto poderia experimentar – e a organização do código-fonte em módulos
Projeto Pegaso: Aprendendo a utilizar
OrientaçãoaObjetoscomRecursosMulti-Plataforma
– Novas Técnicas de Programação
também “alivia” a carga onerosa de implementação repetida exaustivamente
para todas as chamadas de tela, por exemplo.
TConexao–NossaclassedeAbstraçãoeEncapsulamentode
Segregação de Ambientes:
Nossaclassequejáfoitemadeoutrosartigosagoravoltamaisforte–sua
implementação e utilização está mais profissional para o desenvolvedor, que
irá perceber a empregabilidade e chamadas de funções/procedimentos em
um nível mais amigável, legível e mais poderoso no quesito portabilidade –
por isso segue abaixo para revisão – a classe TConexao e como ela trabalha
“embaixo dos panos”:
Veja a Figura 01.
Considerações Iniciais:
O nosso projeto consistirá de alguns itens importantes de construção e
modelagem, a seguir:
1. OBancodeDadoséoDBISAM,fácilpararelacionaraoprojeto,pois
não tem configuração alguma com dll´s, setup´s, drivers, etc; e como não é
um projeto grande (pelo menos por enquanto) pode-se utilizar esta solução
temporariamenteparaademonstraçãodanossaideiainicial;podendomigrar
evolutivamente para outra solução a medida em que o projeto cresce – mas
não está dentro do escopo deste artigo por agora;
2. Componentes adicionais foram utilizados, a maioria shareweare;
Figura 01 - Como as camadas se comunicam com a classe TConexao. Enquanto que uma camada chama, outra sempre a escuta e resolve.
fevereiro
2014
19
a principal intenção é permitir ao desenvolvedor visualizar o código-fonte e
compreender aos poucos a evolução do desenvolvimento e relacionar à sua
experiência de trabalho também – ele pode ser adaptado a qualquer projeto
e logicamente customizado sem nenhum problema. Claro que com todos os
componentesjáinstaladospode-secompilareexecutar,emboraqueosistema
possaserexecutadoporforasemproblemasvistoquecomoditoanteriormente
no item 1 que não há configurações de banco de dados que interfiram neste
processo. Por isso, o deploy inicial torna-se muito mais fácil.
3. Este projeto é freeware e pode ser estendido e reutilizado livre-
mente. A intenção é de que seja vista todos os recursos da Orientação a
Objetos utilizados bem como a empregabilidade do tema do artigo – a classe
de segregação de ambientes – a TConexao – foco principal do mesmo.
Primeiros Passos – O “pontapé” inicial:
Para conceituar e exemplificar nosso projeto, temos a camada de apre-
sentação principal, que é o cadastro de clientes, que por sua vez chama a
classe TPessoaFisica, e que por sua vez chama a classe TConexao, que por fim
realizará todo o processo de persistência ao nosso BD selecionado e escolhi-
do – diga-se de passagem “selecionado” por poder escolher mais de um; no
momento iremos abordar apenas a implementação primeiramente deste BD
devidoàsrazõeselencadasacima.Emoutroartigoiremosexploraravinculação
com outros bancos, dentre os quais relacionais e com outros tipos de dados
como o JSON, etc;
Iremos abordar também o uso de Tabsheets como contêineres para
objetos do tipo frames instanciados dinamicamente através de uma interface
padrão – a nossa IFrame.
Além de chamadas básicas à classe TPessoaFisica também haverá uma
chamada indireta – que é o módulo de histórico – onde o seu carregamento
será sob demanda (dinâmico) e com um objeto explícito (vide abaixo – alguns
trechosdecódigo-fonterelacionadosaoprocessodepersistênciadehistórico
transcritos manualmente):
“
procedure TfrmEditor.
CarregaHistorico;
begin
if not Assigned(_fObject)
then Exit;
if _fObject.ClassName =
‘TPessoaFisica’ then
begin
TPessoaFisica(_fObject).Ca
rregaHistorico(tempClientDataS
et);
end;
end;
procedure TfrmEditor.
SalvarHistorico;
begin
if not Assigned(_fObject)
then Exit;
if _fObject.ClassName =
‘TPessoaFisica’ then
begin
TPessoaFisica(_fObject).Sal
varHistorico(DBSRichViewEdit1.
RichViewEdit.Field.AsVariant);
end;
end;
function TPessoaFisica.
SalvarHistorico(const
myContentFieldHistorico:
Variant): Boolean;
begin
Result := Conexao.
CarregarBlob(AbreHistorico,’DS_
HISTORICO’,
myContentFieldHistorico);
end;
function TPessoaFisica.
AbreHistorico: TDataSet;
begin
Result := Conexao.RetornaData
Set(Format(sqlSelectHistoricoPe
ssoaFisicaFromNome, [Nome]));
end;
function TConexao.
CarregarBlob(const myDataSet:
TDataSet;
const myFieldBlob: string;
const myContentFieldBlob:
Variant): Boolean;
begin
with (myDataSet) do
begin
try
Edit;
FieldByName(myFieldBlob).
AsVariant := myContentFieldBlob;
Post;
Result := True;
except
on E: Exception do
begin
Raise EInvalidDataBase.
Create(EErroGeralBancoDeDados +
fevereiro
2014
20
#13#10 + E.Message);
Result := False;
end;
end;
end;
end;
Figura 01 – Fragmentos de Código-Fonte relacionados à função chamadora de
carregamento de histórico.
TMaskeditHV: Nosso componente Validador de Dados – Ca-
mada de Apresentação
Este componente, também tema de outras edições da TheClub, é o en-
carregado de manipular todas as críticas de dados de input manipuladas pelo
usuário. Formatos de dados como padrão ou do tipo checklistbox (seleção
múltipla), armazenamento interno (propriedade published CustomDataSet)
de qualquer descendente de TDataSet, vários tipos de formatos de entrada
de dados pré-definidos (Data, Data/Hora, Monetário, CPF, etc), detecção
de filtros de Estados/Cidades automáticas (onde um objeto instanciado de
TMaskeditHVfiltraoutrodele),combosinternascomocontêineres,tratamento
das teclas Enter/Tab para processamento automático, tratamento de campos
obrigatórios/default, validações de tipos (monetários, data, hora, etc), enfim,
muitosrecursosencapsuladosparamaiorversatilidadeeprodutividadeparaa
implementaçãodemáscaras,filtros,eventosetratamentoscomfunçõespara
suasmanipulações–tudoissoabstraídonestecomponente.Oboméquecomo
tudo isso já está pronto, as coisas ficaram fáceis para usar e testar – imagine
verificando um campo vazio:
if (mskProcuraDadosCliente.
IsEmpty) then Exit;
Outros exemplos:
Carregar um objeto com máscara de telefone, onde o valor guardado
está sem a máscara:
mskTelComercialAreaComercial01.
LoadText(PessoaFisica.
Telcomercialareacomercial01);
Carregar dados de um objeto descendente de TDataset para armazena-
mento interno do TMaskeditHV:
AssociarapropriedadeCustomDataSetdoObjectInspectorparaoobjeto
dataset desejado. Algumas funções interessantes:
Obter a Seleção Padrão:
//==> combobox default =>
ShowMessage(MaskEditHV1.Text + ‘ GetIndex ‘ +
IntToStr(MaskEditHV1.GetIndex));
Obter a Seleção Múltipla:
var
i: integer;
begin
//==> combobox tipo checkList
=> (abaixo) =>
if not Assigned(MaskEditHV2.
customComboCheckList) then
Exit;
for i := 0 to MaskEditHV2.
customComboCheckList.Items.
Count - 1 do
if MaskEditHV2.
customComboCheckList.
IsChecked(i) then
ShowMessage(‘Get Text at
Index ‘ +
MaskEditHV2.
GetTextAtCheckListPosition(i)
+ ‘ GetValue at Index ‘ +
IntToStr(MaskEditHV2.GetIndexAt
CheckListPosition(i)));
Carregando um conjunto de registros:
procedure TForm1.
Button1Click(Sender: TObject);
begin
if MaskEditHV1.IsEmpty then
Exit;
with MaskEditHV1.CustomDataSet
do
begin
Filter := ‘NOME = ‘ +
QuotedStr(MaskEditHV1.Text);
Filtered := True;
edtCDUsuario.Text :=
Fields[0].AsString;
edtNome.Text := Fields[1].
AsString;
edtDtNascimento.Text :=
Fields[2].AsString;
edtEndereco.Text :=
Fields[3].AsString;
edtCidade.Text :=
Fields[4].AsString;
edtEstado.Text :=
Fields[5].AsString;
edtCEP.Text := Fields[6].
AsString;
edtSetor.Text := Fields[7].
AsString;
edtTelefone.Text :=
fevereiro
2014
21
Fields[8].AsString;
edtSalario.Text :=
Fields[9].AsString;
edtMatricula.Text :=
Fields[11].AsString;
mskCDUsuario.Text :=
Fields[0].AsString;
mskNome.Text := Fields[1].
AsString;
mskDtNascimento.Text :=
Fields[2].AsString;
mskEndereco.Text :=
Fields[3].AsString;
mskCidade.
LoadValueByIndex(Fields[4].
AsString, True);
mskEstado.
LoadValueByIndex(Fields[5].
AsString, True);
mskCEP.LoadText(Fields[6].
AsString);
mskSetor.Text := Fields[7].
AsString;
mskTelefone.
LoadText(Fields[8].AsString);
mskSalario.Text :=
Fields[9].AsString;
mskMatricula.Text :=
Fields[11].AsString;
end;
end;
Tela correspondente do código acima (simulação com Firebird):
Figura03–ObjectInspectordoMaskeditHVcomsuapropriedadeCustomDataSet
selecionada, associada com um ClientDataSet “ClUsuario”.
Repare na figura acima: quando foi especificado o valor de um objeto
TDataSetnapropriedadeCustomDataSet,duaspropriedadesforamautomati-
Figura 02 – Modelo de Tela para chamar um objeto descendente de TDataSet associado com a propriedade CustomDataSet de um
MaskeditHV (no exemplo, associando um ClientDataSet – conexão com Firebird)
fevereiro
2014
22
camentepreenchidas:aCustomFieldNamePassedAsObjectStringParameterea
CustomFieldNamePassedAsObjectIntegerParameter.Essaspropriedadesobtém
o primeiro campo do tipo string e o primeiro campo do tipo integer encontra-
dos no dataset relacionado, respectivamente. Para que isso? É para quando o
componente entrar em modo de edição: ele vai simular um combobox, como
em“Items.AddObject(fComboCustomText.Strings[i],TObject(i)))”–ondeestes
valoresstringeintegerserãoarmazenadosnestafunçãoAddObjectdeTStrings
(functionTStrings.AddObject(constS:string;AObject:TObject):Integer).Aidéia
éfacilitarnaassociaçãoerecuperaçãodestesvalores–métodoget–GetIndex
– método set – LoadValueByIndex(intCodigoDesejado).
Finalmente, o componente MaskeditHV1.CustomDataSet funcionará da
mesma forma que um DataSet normal, podendo filtrar, etc; neste projeto a
camadadeapresentaçãosebaseiafortementenestecomponente.Ecomisso
todas as validações de input foram abstraídas e rapidamente implementadas.
Figura04–FormatosdeexibiçãodoTMaskeditHV–padrão(cbftDefault)eseleção
múltipla (cbftCheckList) da propriedade ComboboxFormate (declaração: type TCom-
boboxFormate = (cbftDefault, cbftCheckList) ).
Inicialização da Aplicação:
Figura 05 – Tela Principal do Projeto. Apenas o primeiro botão (Cadastro) está
funcional. O resto não foi escrito para este propósito do nosso artigo.
Figura06–EventoOnClickdobotãoCadastro,mostrandoateladeseleçãodotipo
de Pessoa – apenas a primeira opção está funcional.
Figura 07 – Carregamento da Tela de Cadastro de Pessoa Física.
fevereiro
2014
23
Figura 08 – Layout padrão das mensagens
de “alert” do sistema (tipos “Informação”, “Con-
firmação”, etc).
Figura 09 – Carregamento da Tela de Histórico – note a presença de um corretor ortográfico no campo memo de edição (componentes shareweare TAddictSpell e TScaleRi-
chView, respectivamente) – além de outros já utilizados em todas os demais forms por padrão (TMS Software e SuniSoft Software).
Figura10–CarregamentodaTela“ReferênciasBancárias”.Estatela(comooutrasreferenciadasnopaineldireitodeatalhos)serefereatodasquesãocriadasdinamicamente
via Tabsheet com frames embutidos. É a abstração via interface. Tal recurso será explicado adiante.
fevereiro
2014
24
Basicamente, nossa primeira versão da demonstração do programa se
resume a isto. Há algumas considerações a serem feitas antes da explicação
da classe de pessoa física. Vamos a elas:
1. A arquitetura da criação das janelas é do tipo MDI (Multiple Docu-
mentInterface),ondemaisdeumajanelafilhapodeserabertadentrodeuma
janela pai, que é a primeira janela (main) a ser exibida com a barra de botões
acima dela.
2. Nãopoderáserchamadaecarregadaamesmateladuasvezes.Para
isso, a função booleana “JanelaExiste” (unit Biblioteca) será chamada sempre
na criação desta janela, onde senão criada, será, se sim, será recuperada (if
Biblioteca.JanelaExiste(frmEscolherTipoPessoa) then Exit);
3. Algumas funções como LockClientWindowUpdate e U n l o -
ckClientWindowUpdateforamdeclaradaseimplementadasparaevitaroefeito
de“telacongelada”queapareciaquandoeraexibidasemaparentementeestar
toda carregada (vide trecho do código-fonte abaixo):
procedure TfrmPrincipal.
LockClientWindowUpdate;
begin
if
fLockClientWindowUpdateCount = 0
then SendMessage(ClientHandle,
WM_SETREDRAW, 0, 0);
Inc(fLockClientWindowUpdateCo
unt) ;
end;
procedure TfrmPrincipal.
UnlockClientWindowUpdate;
begin
Dec(fLockClientWindowUpdateCo
unt) ;
if
fLockClientWindowUpdateCount =
0 then
begin
SendMessage(ClientHandle,
WM_SETREDRAW, 1, 0) ;
RedrawWindow(ClientHandle,
nil, 0, RDW_FRAME or RDW_
INVALIDATE or RDW_ALLCHILDREN
or RDW_NOINTERNALPAINT);
end;
end;
Figura 11 – Chamadas das funções LockClientWindowUpdate e UnlockClientWin-
dowUpdate.
Carregando em um ClientDataSet automaticamente o conjunto de dados
retornados da nossa classe:
Nosso aplicativo teve a abstração e encapsulamento como as melhores
ideias para a performance e eficiência em sua construção, agilizando todas as
chamadas às consultas de banco de dados, como no seguinte caso demons-
trado abaixo, onde o nosso objeto de TPessoaFisica passa um objeto do tipo
TClientDataSet como referência, onde será carregado como retorno:
1. Passando o objeto do tipo TClientDataSet para o método de TPes-
soaFisica: PessoaFisica.CarregaConsultaPessoaFisica(ClPessoaFisica);
2. Este método, por sua vez, chamará internamente a função Abre-
RecordSetPessoaFisica, que retornará um TDataSet contendo os dados requi-
sitados, conforme mostrados abaixo:
procedure TPessoaFisica.
CarregaConsultaPessoaFisica(
var myClientDataSet:
TClientDataSet);
begin
Self.ObterDataSet(Self.
AbreRecordSetPessoaFisica,
myClientDataSet);
end;
{ TPessoaFisica }
function TPessoaFisica.
AbreRecordSetPessoaFisica:
TDataSet;
begin
Result := Conexao.RetornaData
Set(sqlSelectAllFieldsPessoaFis
ica);
end;
{ sql´s classe PessoaFisica }
sqlSelectAllFieldsPessoaFisica:
string = ‘SELECT * FROM
PESSOAFISICA ORDER BY NOME’;
function TConexao.
RetornaDataSet(Query: String):
TDataSet;
begin
if Self is TConexaoDBISAM
then
Result :=
TConexaoDBISAM(Self).
RetornaDataSet(Query)
else if Self is TConexaoXML
then
Result := TConexaoXML(Self).
ExecutaSelect(Query)
else if Self is
TConexaoFirebird then
Result :=
TConexaoFirebird(Self).
RetornaDataSet(Query);
end;
Figura 12 – Chamadas de alguns métodos relevantes para a obtenção de dados
para o carregamento de um ClientDataSet como parâmetro, a serem mostrados no
método CarregaConsultaPessoaFisica de TPessoaFisica.
Mapeamento de Objetos com ClientDataSets desejados:
Foi implementado uma função para simplificar as procuras dos objetos
comseusClientDatasetsrelacionados –poderíamosfazerumIFparacadaum
em uma coleção, mas dinamicamente poderia ficar pesado na construção –
principalmente em muitos objetos procurando todos os seus ClientDatasets,
umavezquenanossatécnicadeimplementaçãoédeumpraum–nessecaso
fevereiro
2014
25
doisarrayssãocriados–ondeumprocurapelooutroemumDataModuleese
encontrar, o retorna: imagine muitos DataModules de muitos bancos – sem
esta ideia ficaria muito complexo!
Segue a declaração da função abaixo – classe TConexao:
function TConexao.
MapClientDataSets(const fObject:
TObject; const fClientDataSet:
TObject): TClientDataSet;
const
arClientDataSets: array
[0..3] of string =
(‘ClPropriedadeRural’,
‘ClParticipacaoEmpresas’,
‘ClReferenciaBancaria’,
‘ClPessoaFisica’);
arObjects : array
[0..3] of string =
(‘TPropriedadeRural’,
‘TParticipacaoEmpresas’,
‘TReferenciaBancaria’,
‘TPessoaFisica’);
var
i: integer;
begin
Result := nil;
for i := 0 to High(arObjects)
do
if (fClientDataSet.
ClassName = arObjects[i]) then
begin
Result := TClientDataSet
(TConexao(fObject).RetornaDM.Fi
ndComponent(arClientDataSets[i]
));
Break;
end;
end;
if Self is TConexaoFirebird
then
begin
try
fClientDataSet :=
TConexao((TConexao(Self).
RetornaDM)).
MapClientDataSets(Self,
fClassName);
except on E: Exception do
Raise EAbstractError.
Create(EErroComponente + #13#10
+ E.Message);
end;
try
fClientDataSet.Close;
fClientDataSet.Open;
fClientDataSet.Refresh;
if not (fClientDataSet.
state in dsEditModes) then
fClientDataSet.Edit;
TBlobField(fClientDataSet.
FieldByName(MyFieldName)).
AsString := fTexto;
fClientDataSet.Post;
fClientDataSet.
ApplyUpdates(0);
except
on E: Exception do
Raise EInvalidDataBase.
Create(EErroGeralBancoDeDados +
#13#10 + E.Message);
end;
Result := True;
end;
Figura13–DemonstraçãodafunçãodemapeamentoMapClientDataSets,utilizada
nas chamadas entre objetos instanciados e ClientDataSets simultaneamente.
Figura 14 - Diagrama de Sequência do componente TConexao.
fevereiro
2014
26
Agora, finalmente, o processo completo de funcionamento de acordo
com a orientação a objetos juntamente com a nossa classe:
Veja a figura 15.
Resumindo:nossaclasseTConexaoserásemprearesponsávelporreceber
as requisições das classes negociais (no nosso caso, a classe TPessoaFisica) e
retornando um conjunto descendente de TDataSet (de acordo com o banco
escolhido). Portanto, toda vez que uma classe quiser acessar um banco, ela
na verdade acessa uma instância da classe de conexão (TConexao), onde esta
por sua vez referenciará-lo em memória. Toda a interface de comunicação e
operacionalização será realizada somente através dela, estando disponível
até ser destruída.
Abaixo, uma seleção de alguns métodos importantes utilizados na classe
TConexao - detalhe para os métodos ObterDataSet, CarregarFoto e GetCo-
nexao (sintaxe: Conexao := Conexao.GetConexao(fbdConexao)) - que são os
métodos mais importantes do processo de comunicação entre os objetos de
negócio e dados.
procedure TConexao.
ObterDataSet(const myDataSet:
TDataSet; var myClientDataSet:
TClientDataSet);
var
fDataSet: TDataSet;
i {, k}: integer;
FName: string;
begin
if not Assigned(myDataSet)
then Exit;
if not Self.BancoInstanciado
then
begin
Application.MessageBox(PCha
r(Format(EBancoNaoInstanciado,
[FUsuariosFDB])), ETituloErro,
MB_OK + MB_ICONERROR);
Abort;
end;
fDataSet :=
TClientDataSet(myDataSet);
fDataSet.First;
if not myClientDataSet.Active
then
myClientDataSet.
CreateDataSet
else
myClientDataSet.
EmptyDataSet;
myClientDataSet.
DisableControls;
try
while not fDataSet.Eof do
begin
myClientDataSet.Insert;
for i := 0 to fDataSet.
FieldCount - 1 do
begin
// myClientDataSet.
Fields[i].Assign(fDataSet.
Fields[i]);
myClientDataSet.
FieldDefs.Items[i].DataType :=
(fDataSet.FieldDefs.Items[i].
DataType);
myClientDataSet.
FieldDefs.Items[i].DisplayName
:= (fDataSet.FieldDefs.
Items[i].DisplayName);
case myClientDataSet.
FieldDefs.Items[i].DataType of
ftString:
myClientDataSet.Fields[i].
AsString := Self.
DefaultDateFormat2(fDataSet.
Fields[i].AsString);
ftDate:
myClientDataSet.Fields[i].
AsString := Self.
DefaultDateFormat2(fDataSet.
Fields[i].AsString);
ftFloat:
myClientDataSet.Fields[i].
AsFloat := Biblioteca.
Figura 15 - Explicação da operacionalização do funcionamento das camadas juntamente com as regras negociais e com a classe TConexao.
fevereiro
2014
27
ArredondaComDecimais( fDataSet.
Fields[i].AsFloat, 2);
else
myClientDataSet.
Fields[i].AsString :=
fDataSet.Fields[i].AsString;
end;
end;
myClientDataSet.Post;
fDataSet.Next;
end;
finally
myClientDataSet.
EnableControls;
end;
end;
procedure TConexao.
ObterDataSet(const myDataSet:
TDataSet; var myStringList:
TStringList);
var
fDataSet: TDataSet;
i: integer;
begin
if not Assigned(myDataSet)
then Exit;
fDataSet :=
TClientDataSet(myDataSet);
fDataSet.First;
if not Assigned(myStringList)
then myStringList :=
TStringList.Create;
while not fDataSet.Eof do
begin
myStringList.Add(fDataSet.
Fields[0].AsString);
fDataSet.Next;
end;
end;
function TConexao.
RecordCount(Query: String):
integer;
begin
if Self is TConexaoDBISAM
then
Result :=
TConexaoDBISAM(Self).
RecordCount(Query)
else if Self is TConexaoXML
then
Result := TConexaoXML(Self).
RecordCount(Query)
else if Self is
TConexaoFirebird then
Result :=
TConexaoFirebird(Self).
RecordCount(Query);
end;
function TConexao.
RecordCount(const myDataSet:
TDataSet): integer;
begin
Result :=
(TDataSet(myDataSet).
RecordCount);
end;
function TConexao.
RetornaDataSet(Query: String):
TDataSet;
begin
if Self is TConexaoDBISAM
then
Result :=
TConexaoDBISAM(Self).
RetornaDataSet(Query)
else if Self is TConexaoXML
then
Result := TConexaoXML(Self).
ExecutaSelect(Query)
else if Self is
TConexaoFirebird then
Result :=
TConexaoFirebird(Self).
RetornaDataSet(Query);
end;
function TConexao.
CarregarFoto(const MyFile:
string; const myDataSet:
TDataSet; const MyFieldName:
string = ‘FOTO’): Boolean;
function
GetTableNameFromXMLSyntax(const
mySQLXML: string): string;
begin
if System.
Pos(AnsiUpperCase(‘where’),
AnsiUpperCase(mySQLXML)) > 0
then
Result := trim(Before(af
ter(AnsiUpperCase(mySQLXML),
‘FROM’), ‘WHERE’));
end;
var
S: TFileStream;
fClientDataSet:
TClientDataSet;
fevereiro
2014
28
auxTableName: string;
auxFilterFields: string;
begin
if Self is TConexaoXML then
begin
if (Self.FiltroXML = ‘’)
then Exit;
auxTableName :=
GetTableNameFromXMLSyntax(Self.
FiltroXML);
auxTableName :=
auxTableName + ‘.xml’;
fClientDataSet
:= TConexaoXML(Self).
CarregarBanco(auxTableName);
auxFilterFields :=
Before(after(AnsiUpperCase(Self.
FiltroXML),’WHERE’), ‘ORDER’);
fClientDataSet.Filter :=
auxFilterFields;
fClientDataSet.Filtered
:= True;
try
fClientDataSet.Close;
fClientDataSet.Open;
if not (fClientDataSet.
state in dsEditModes) then
fClientDataSet.Edit;
TBlobField(fClientDataSet.
FieldByName(MyFieldName)).
LoadFromFile(MyFile);
fClientDataSet.Post;
fClientDataSet.
SaveToFile(TConexaoXML(Self).
CaminhoXMLAtual, dfXML);
except
on E: Exception do
begin
Raise EInvalidDataBase.
Create(EErroGeralBancoDeDados +
#13#10 + E.Message);
Result := False;
end;
end;
end
else
if Self is TConexaoDBISAM
then
begin
S := TFileStream.
Create(MyFile ,fmOpenRead);
with (myDataSet) do
begin
try
try
Edit;
TBlobField(Fie
ldByName(MyFieldName)).
LoadFromStream(S);
Post;
except
on E: Exception do
begin
Raise
EInvalidDataBase.
Create(EErroGeralBancoDeDados +
#13#10 + E.Message);
Result := False;
end;
end;
finally
S.Free;
end;
end;
end
else if Self is
TConexaoFirebird then
begin
fClientDataSet :=
dmFirebird.ClUsuario;
try
fClientDataSet.Close;
fClientDataSet.Open;
fClientDataSet.Refresh;
if not (fClientDataSet.
state in dsEditModes) then
fClientDataSet.Edit;
TBlobField(fClientDataSet.
FieldByName(MyFieldName)).
LoadFromFile(MyFile);
fClientDataSet.Post;
fClientDataSet.
ApplyUpdates(0);
except
on E: Exception do
begin
Raise EInvalidDataBase.
Create(EErroGeralBancoDeDados +
#13#10 + E.Message);
Result := False;
end;
end;
end;
end;
function TConexao.
fevereiro
2014
29
GetConexao(const typeConexao:
tBDConexao): TConexao;
begin
if Assigned(Result) then
closeConexao;
case typeConexao of
bdConexaoDBISAM: Result
:= TConexaoDBISAM.create;
bdConexaoXML: Result
:= TConexaoXML.create;
bdConexaoFirebird: Result
:= TConexaoFirebird.create;
end;
end;
Figura 16 – Alguns comandos importantes da classe TConexao relevantes para os
procedimentos de acesso e persistência das bases de dados do projeto (multiplatafor-
ma). Perceba os métodos RecordCount, ObterDataSet, RetornaDataSet, CarregarFoto
e outros.
Conclusão
Foramdemonstradasascaracterísticasmaisimportantesdonossoprojeto,
aindaqueemumnívelmenosdetalhado,ofuncionamento(comunicação)entre
acamadadeapresentação(unitUnCadastroPessoaFisica),classenegocial(unit
UnTPessoaFisica)eaclassedepersistênciamultiplataforma(unitUnConexao);
Foram explanados principais componentes que integram o projeto,
como a classe validadora TMaskeditHV de minha autoria, já explicado em
artigos anteriores e abordado principais aspectos novamente – utilizado na
camada de apresentação para críticas/formatos de validação, bem como
outras funcionalidades (combobox embutido, contêiner para TClientDataSet,
chamadas automáticas de formatação (ex: extrair somente o valor e sem
nenhuma máscara – método ExtractJustText de TMaskeditHV – PessoaFisica.
CPFMae := mskCPFMae.ExtractJustText); também foram mencionados alguns
componentes shareweare de terceiro, embora sem profundidade, utilizados
para design da camada de apresentação (ex: componentes dos pacotes TMS
Software/TScaleRichView/SuniSoft);
Por último, foi demonstrado um “overview” do sistema, exibindo o
principal funcionamento em nível de demonstração – o que o usuário final
realmentevê.Entretanto,focamosmais“nosbastidores”dosistema,extraindo
ositensrelevantesdecodificação(noçõesdeOrientaçãoaObjetos)bemcomo
a operacionalização das nossas classes que interagem entre si (TConexao e
TPessoaFisica);
Com isso, espero que esta leitura possa proporcionar ao leitor uma agra-
dável experiência de codificação e ideias novas de layout de telas, através
das técnicas de demonstração do código-fonte e sugestões suaves e leves de
forms, respectivamente. Finalmente, espero que o leitor tenha o prazer que
eu tive ao desenvolver este projeto também. Um abraço e até a continuação
do próximo artigo. Boa leitura !
fevereiro
2014
30
Questões
desafio the club
1.
Perform
-
2.
Repeat
-
3.
Interbase
-
4.
Delete
-
5.
Fieldbyname
-
6.
Savetofile
-
7.
Maskutils
-
8.
Dataset
-
9.
Abstract
-
10.
Controls
-
11.
Traceinto
-
12.
Dateutils
-
13.
Type
-
14.
Rave
designer
-
15.
Stringreplace
fevereiro
2014
05
fevereiro
2014

Mais conteúdo relacionado

Semelhante a 1402 - Revista - AspNet.pdf

Semelhante a 1402 - Revista - AspNet.pdf (20)

O mercado de trabalho em TI
O mercado de trabalho em TIO mercado de trabalho em TI
O mercado de trabalho em TI
 
Mvc 3 & razor
Mvc 3 & razorMvc 3 & razor
Mvc 3 & razor
 
MVC 3 & razor (DevBrasil Summit 2011)
MVC 3 & razor (DevBrasil Summit 2011)MVC 3 & razor (DevBrasil Summit 2011)
MVC 3 & razor (DevBrasil Summit 2011)
 
CV_ANDERSON_COELHO
CV_ANDERSON_COELHOCV_ANDERSON_COELHO
CV_ANDERSON_COELHO
 
PPT do Road Show - Infra
PPT do Road Show - InfraPPT do Road Show - Infra
PPT do Road Show - Infra
 
Programando extensões para Internet Explorer (Webslices e Aceleradores)
Programando extensões para Internet Explorer (Webslices e Aceleradores)Programando extensões para Internet Explorer (Webslices e Aceleradores)
Programando extensões para Internet Explorer (Webslices e Aceleradores)
 
Como avançar na Power Platform com Azure Functions e Logic Apps | MVPConf Lat...
Como avançar na Power Platform com Azure Functions e Logic Apps | MVPConf Lat...Como avançar na Power Platform com Azure Functions e Logic Apps | MVPConf Lat...
Como avançar na Power Platform com Azure Functions e Logic Apps | MVPConf Lat...
 
Replicando dados do Project Online com o SQL Server usando o protocolo OData
Replicando dados do Project Online com o SQL Server usando o protocolo ODataReplicando dados do Project Online com o SQL Server usando o protocolo OData
Replicando dados do Project Online com o SQL Server usando o protocolo OData
 
Mercado de profissionais técnicos na área de TI
Mercado de profissionais técnicos na área de TIMercado de profissionais técnicos na área de TI
Mercado de profissionais técnicos na área de TI
 
Segunda Empregável - Edição 00
Segunda Empregável - Edição 00Segunda Empregável - Edição 00
Segunda Empregável - Edição 00
 
BluDotNet - Conhecendo o Team Foundation Server 2010
BluDotNet - Conhecendo o Team Foundation Server 2010BluDotNet - Conhecendo o Team Foundation Server 2010
BluDotNet - Conhecendo o Team Foundation Server 2010
 
FabricioDoi
FabricioDoiFabricioDoi
FabricioDoi
 
Vitor portfólio prof tecnico 2016 free lance
Vitor portfólio prof tecnico 2016   free lanceVitor portfólio prof tecnico 2016   free lance
Vitor portfólio prof tecnico 2016 free lance
 
Dicas para uma Maior Performance em APIs REST no ASP.NET Core - MVPConf LATAM...
Dicas para uma Maior Performance em APIs REST no ASP.NET Core - MVPConf LATAM...Dicas para uma Maior Performance em APIs REST no ASP.NET Core - MVPConf LATAM...
Dicas para uma Maior Performance em APIs REST no ASP.NET Core - MVPConf LATAM...
 
Mini-Curso: Introdução à Big Data e Data Science - Aula 11 - SQL 2016 + BigDa...
Mini-Curso: Introdução à Big Data e Data Science - Aula 11 - SQL 2016 + BigDa...Mini-Curso: Introdução à Big Data e Data Science - Aula 11 - SQL 2016 + BigDa...
Mini-Curso: Introdução à Big Data e Data Science - Aula 11 - SQL 2016 + BigDa...
 
Reunião01 Pass Chapter - MCITPSC
Reunião01 Pass Chapter - MCITPSCReunião01 Pass Chapter - MCITPSC
Reunião01 Pass Chapter - MCITPSC
 
Reunião #1 – 2015 – Overview
Reunião #1 – 2015 – OverviewReunião #1 – 2015 – Overview
Reunião #1 – 2015 – Overview
 
Function as a Service: IT forum expo 2017
Function as a Service: IT forum expo 2017Function as a Service: IT forum expo 2017
Function as a Service: IT forum expo 2017
 
Polly: aplicações .NET resilientes e um melhor tratamento de falhas | MVPConf...
Polly: aplicações .NET resilientes e um melhor tratamento de falhas | MVPConf...Polly: aplicações .NET resilientes e um melhor tratamento de falhas | MVPConf...
Polly: aplicações .NET resilientes e um melhor tratamento de falhas | MVPConf...
 
Novidades no Deployment do Office 365
Novidades no Deployment do Office 365Novidades no Deployment do Office 365
Novidades no Deployment do Office 365
 

Último

Assessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdfAssessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdf
Natalia Granato
 

Último (6)

Assessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdfAssessement Boas Praticas em Kubernetes.pdf
Assessement Boas Praticas em Kubernetes.pdf
 
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docxATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
ATIVIDADE 1 - GCOM - GESTÃO DA INFORMAÇÃO - 54_2024.docx
 
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docxATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
ATIVIDADE 1 - CUSTOS DE PRODUÇÃO - 52_2024.docx
 
Padrões de Projeto: Proxy e Command com exemplo
Padrões de Projeto: Proxy e Command com exemploPadrões de Projeto: Proxy e Command com exemplo
Padrões de Projeto: Proxy e Command com exemplo
 
Boas práticas de programação com Object Calisthenics
Boas práticas de programação com Object CalisthenicsBoas práticas de programação com Object Calisthenics
Boas práticas de programação com Object Calisthenics
 
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docxATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
ATIVIDADE 1 - LOGÍSTICA EMPRESARIAL - 52_2024.docx
 

1402 - Revista - AspNet.pdf

  • 3. fevereiro 2014 03 18 Índice Desafio The Club 30 Editorial 04 13 Autor: Hamden Vogel 05 Autor: Thiago Cavalheiro Montebugnoli Autor: Luciano Pimenta ASP.NET Projeto Pegaso: Validações no ASP.NET MVC Persistindo valores entre Web Forms Aprendendo a utilizar Orientação a Objetos com Recursos Multi-Plataforma – Novas Técnicas de Programação
  • 4. fevereiro 2014 04 Delphi é marca registrada da Borland International, as demais marcas citadas são registradas pelos seus respectivos proprietários. Thiago Montebugnoli- Editor Chefe thiago@theclub.com.br Caro amigo, É sempre com muita alegria e satisfação que escrevo o editorial de mais umarevista“TheClub”,procurandosanarasdúvidasesatisfazertodassuas necessidades. Nossa equipe tem a obrigação de trazer artigos e dicas sem- pre conectados com as últimas novidades do mundo da programação. Na ediçãodestemês,nossocolunistaLucianoPimentacontinuacomasériede artigos relacionados ao Asp.Net MVC, abordando um assunto de extrema importância em cadastros, as denominadas Validações. Para que toda apli- cação funcione da melhor maneira possível é necessário que os dados dos usuários estejam íntegros, portanto o papel das validações é fundamental nesta etapa de desenvolvimento. Neste mês apresento diversas formas parapersistirvaloresentreWebForms,comoartigo“Asp.Net–Persistindo valores entre Web Forms” com explicações e exemplos práticos. Discorro sobre Variáveis de Sessões, QueryString, entre outras técnicas para obter este resultado. Para finalizar com estilo, nosso colaborador Hamden Vogel, comaprimeirapartedoartigo“ProjetoPegaso,aprendendoautilizarOrien- taçãoaObjetoscomRecursosMulti-Plataforma”,comoopróprionomediz, neste artigo são apresentadas inúmeras dicas e recursos para quem deseja aprender e aprimorar conceitos de Orientação a Objetos utilizando um projeto teste de exemplo. Vou ficando por aqui desejando a todos uma boa leitura e que tirem o maiorproveitodenossosartigos.Lembrandoquenossaequipeestásempre aberta a críticas e sugestões. Um Forte abraço, Av. Profº Celso Ferreira da Silva, 190 Jd. Europa - Avaré - SP - CEP 18.707-150 Informações e Suporte: (14) 3732-1529 Internet http://www.theclub.com.br Cadastro: cadastro@theclub.com.br Suporte: suporte@theclub.com.br Informações: info@theclub.com.br Skype Cadastro: theclub_cadastro Skype Suporte: theclub_linha1 theclub_linha2 theclub_linha3 www.twitter.com/theclubbr Copyright The Club 2013 Diretor Técnico Marcos César Silva Diagramação Vitor M. Rodrigues Design Vitor M. Rodrigues Revisão Drielly Cristini Patrinhani Colunistas Hamden Vogel Jeferson Silva de Lima Luciano Pimenta Thiago Cavalheiro Montebugnoli Juninho Jeferson Silva de Lima Impressão e acabamento: GRIL - Gráfica e Editora Taquarituba-SP - Tel. (14) 3762-1345 Reprodução A utilização, reprodução, apropriação, armazenamento em banco de dados, sob qualquer forma ou meio, de textos, fotos e outras criações intelectuais em cada publicação da revista “The Club Megazine” são terminantemente proibidos sem autorização escrita dos titulares dos direitos autorais. Editorial
  • 5. fevereiro 2014 05 Listagem 01: Código da Página 01. Q uando começamos a programar para web, uma das dú- vidas mais freqüentes é: Como devemos persistir valores entre Web Forms? Praticamente a maioria dos softwares háanecessidadederecuperarvaloresentreFormulários, em se tratando de Asp.Net seriam os denominados Web Forms.Porexemplo,Imaginemaseguintesituação,temosumapáginaondeos usuáriosirãorealizarumCadastrodeClientesenapáginaseguintedeveremos transportarestesmesmosdadosparaumprocessamento,ondeosdadosdeve- rãoserarmazenadose“lidos”.Ondeficarãoarmazenadosestesdados?Como devemos tratá-los? Este artigo irá abordar as diversas formas de persistirem estes valores. Temos diversos artifícios para trabalhar, como por exemplo: • Variáveis de sessão (Session) • QueryString • Método Server.Transfer • Classe HttpContext Gostaria de exemplificar de uma forma simples todas as técnicas acima descritas.Antesdeiniciarmosiremoscriarumprojetobaseparaoaprendizado. ParaistoabraoMicrosoftVisualStudioecrieumapáginadoZero,adicionando umWebFormpadrão(paraEnviarosdados)enomeucasoacheimelhorcriar um Web Form para cada tipo de técnica citada anteriormente. Abaixo deixo uma sugestão de lay-out para Envio e Recebimento. NaFigura01foramadicionadosalgunsTextBoxs,como:Nome,Endereço, Cidade, Estado, Tipo (Estes são os campos que iremos passar para a Página seguinte). Foram adicionados um botão para cada técnica, sendo: Session, QueryString, Server Transfer e HttpContext. Veja a Figura 01. ASP.NET - Persistindo valores entre Web Forms Figura 01: WebForm para Envio de dados. Aproveito também para inserir o trecho principal do código em Aspx. Veja Listagem 01. <form id=”form1” runat=”server”> <table class=”style1” width=”380”> <tr> <td colspan=”2” style=”text-align: center”> <asp:Label ID=”Label2” runat=”server” ForeColor=”#000066” style=”font-weight: 700; font- size: large; font-family: Arial, Helvetica, sans-serif; text-decoration: underline; font-style: italic;” Text=”ASP.NET - Persistindo valores entre Web Forms”></ asp:Label>
  • 6. fevereiro 2014 06 </td> </tr> <tr> <td colspan=”2” style=”text-align: center”> <asp:Label ID=”Label1” runat=”server” ForeColor=”#000066” style=”font-weight: 700; font- size: large; font-family: Arial, Helvetica, sans-serif” Text=”Página 01 - Enviar Dados”></asp:Label> </td> </tr> <tr> <td> &nbsp;</td> <td> &nbsp;</td> </tr> <tr> <td> <asp:Label ID=”lblNome” runat=”server” CssClass=”style3” Text=”Nome:”></asp:Label> </td> <td> <asp:TextBox ID=”txtNome” runat=”server” CssClass=”style4” Height=”20px” Width=”300px” ClientIDMode=”Inherit”></ asp:TextBox> </td> </tr> <tr> <td> <asp:Label ID=”lbEndereco” runat=”server” CssClass=”style3” Text=”Endereço:”></asp:Label> </td> <td> <asp:TextBox ID=”txtEndereco” runat=”server” CssClass=”style4” Height=”20px” Width=”300px”></asp:TextBox> </td> </tr> <tr> <td> <asp:Label ID=”lblCidade” runat=”server” CssClass=”style3” Text=”Cidade:”></asp:Label> </td> <td> <asp:TextBox ID=”txtCidade” runat=”server” CssClass=”style4” Height=”20px” Width=”200px”></asp:TextBox> </td> </tr> <tr> <td> <asp:Label ID=”lblEstado” runat=”server” CssClass=”style3” Text=”Estado:”></asp:Label> </td> <td> <asp:TextBox ID=”txtEstado” runat=”server” CssClass=”style4” Height=”20px” Width=”150px”></ asp:TextBox> </td> </tr> <tr> <td> <asp:Label ID=”lblTipo” runat=”server” CssClass=”style3” Text=”Tipo:”></asp:Label> </td> <td> <asp:DropDownList ID=”dropTipo” runat=”server” CssClass=”style4” Height=”20px” Width=”150px”> <asp:ListItem></asp:ListItem> <asp:ListItem Value=”F”>Física</ asp:ListItem> <asp:ListItem Value=”J”>Jurídica</ asp:ListItem> </ asp:DropDownList> </td> </tr> <tr> <td> &nbsp;</td> <td> &nbsp;</td> </tr> <tr> <td class=”style2” colspan=”2”> <asp:Button ID=”btnEnviarSession” runat=”server” style=”font-
  • 7. fevereiro 2014 07 Listagem 02. Código da Página 02. family: Arial, Helvetica, sans- serif” Text=”Session” Width=”260px” onclick=”btnEnviar_Click” /> </td> </tr> <tr> <td class=”style2” colspan=”2”> <asp:Button ID=”btnEnviarquerystring” runat=”server” style=”font- family: Arial, Helvetica, sans- serif” Text=”QueryString” Width=”260px” onclick=”btnEnviarquerystring_ Click” /> </td> </tr> <tr> <td class=”style2” colspan=”2”> <asp:Button ID=”btnEnviarServerTransfer” runat=”server” style=”font- family: Arial, Helvetica, sans- serif” Text=”Server Transfer” Width=”260px” onclick=”bt nEnviarServerTransfer_Click” /> </td> </tr> <tr> <td class=”style2” colspan=”2”> <asp:Button ID=”btnEnviarHttpContext” runat=”server” style=”font-family: Arial, Helvetica, sans-serif” Text=”HttpContext” Width=”260px” onclick=”btnEnviarHttpContext_ Click” /> </td> </tr> </table> <div> </div> </form> Abaixo o lay-Out da Página para receber os dados, contendo 5 Labels, sendo: Nome, Endereço, Cidade, Estado e Tipo. Cada componente irá receber o seu correspondente da página anterior. Ver Imagem 02. Figura 02: WebForm de recebimento de dados. O trecho principal do código em Aspx. Veja Listagem 02. <form id=”form1” runat=”server”> <table class=”style1” width=”380”> <tr> <td colspan=”2” style=”text-align: center”> <asp:Label ID=”Label1” runat=”server” ForeColor=”#000066” style=”font-weight: 700; font- size: large; font-family: Arial, Helvetica, sans-serif” Text=”Página 02 - Receber Dados”></asp:Label> </td> </tr> <tr> <td class=”style6”> &nbsp;</td> <td> &nbsp;</td> </tr> <tr> <td class=”style4” colspan=”2”> <asp:Label ID=”lblInformativo” runat=”server” ForeColor=”#000066” style=”font-weight: 700; font- size: large; font-family: Arial, Helvetica, sans- serif”>Session</asp:Label> </td> </tr> <tr>
  • 8. fevereiro 2014 08 Listagem 03: Código para atribuir valores para as variáveis de sessão. <td class=”style6”> <asp:Label ID=”lblNome” runat=”server” CssClass=”style3” Text=”Nome:”></asp:Label> </td> <td> <asp:Label ID=”lblNomeRec” runat=”server” CssClass=”style5”></asp:Label> </td> </tr> <tr> <td class=”style6”> <asp:Label ID=”lblEndereco” runat=”server” CssClass=”style3” Text=”Endereço:”></asp:Label> </td> <td> <asp:Label ID=”lblEnderecoRec” runat=”server” CssClass=”style5”></asp:Label> </td> </tr> <tr> <td class=”style6”> <asp:Label ID=”lblCidade” runat=”server” CssClass=”style3” Text=”Cidade:”></asp:Label> </td> <td> <asp:Label ID=”lblCidadeRec” runat=”server” CssClass=”style5”></asp:Label> </td> </tr> <tr> <td class=”style6”> <asp:Label ID=”lblEstado” runat=”server” CssClass=”style3” Text=”Estado:”></asp:Label> </td> <td> <asp:Label ID=”lblEstadoRec” runat=”server” CssClass=”style5”></asp:Label> </td> </tr> <tr> <td class=”style6”> <asp:Label ID=”lblTipo” runat=”server” CssClass=”style3” Text=”Tipo:”></asp:Label> </td> <td> <asp:Label ID=”lblTipoRec” runat=”server” CssClass=”style5”></asp:Label> </td> </tr> <tr> <td class=”style2” colspan=”2”> &nbsp;</td> </tr> </table> <div> </div> </form> 1-) Variáveis de Sessão As variáveis de Sessão fornecem uma facilidade para armazenar infor- mações na memória do servidor podendo suportar qualquer tipo de objeto. Paracadacliente,osdadosdasessãosãoarmazenadosseparadamente,oque significaqueestesdadossãoarmazenadosemumabaseporcliente.Umasde suasvantagenséqueaoutilizá-lamantemosoestadodousuárioeosdadosde todooaplicativosecomportandodeformatotalmenteseguraetransparente. Seguindonossoexemplo,paraarmazenarosdadosnasessãoutilizaremos o código abaixo: Ver Listagem 03. protected void btnEnviar_ Click(object sender, EventArgs e) { Session[“nome”] = txtNome. Text; Session[“endereco”] = txtEndereco.Text; Session[“cidade”] = txtCidade.Text; Session[“estado”] = txtEstado.Text; Session[“tipo”] = dropTipo.SelectedItem; Response. Redirect(“WebFormSession. aspx”); } Podemoscriarquantasvariáveisdesessãoquedesejarecomonomeque acharmos melhor. Seguiremos o padrão, respeitando a ordem dos campos. Atribuímos os valores dos Componentes e logo em seguida com o comando “Response.Redirect” redirecionamos para a página onde iremos receber os valores destas variáveis. Iremos receber os dados no evento Page_Load() do WebForm, Ver Listagem 04.
  • 9. fevereiro 2014 09 Listagem 04: Código para receber valores das variáveis de sessão. Listagem 05: Código para enviar valores das Querystring Listagem 06: Código para receber valores da Querystring. protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { lblNomeRec.Text = Session[“nome”].ToString(); lblEnderecoRec.Text = Session[“endereco”].ToString(); lblCidadeRec.Text = Session[“cidade”].ToString(); lblEstadoRec.Text = Session[“estado”].ToString(); lblTipoRec.Text = Session[“tipo”].ToString(); } } Para receber os valores, devemos atribuir para a propriedade “Text” dos componentes. No caso estamos trabalhando com campos do tipo texto, mas ressalto que poderíamos receber um Objeto inteiro de qualquer tipo que o trabalho seria idêntico ao descrito acima. 2-) Querystring A “Querystring” é um modelo clássico e talvez o mais utilizado em sistemas Web. A única desvantagem no uso deste recurso é que os valores passados serão visíveis no Navegador e não conseguimos passar objetos. Recomendado para valores pequenos (limite de 255 caracteres) e que não necessitamdesegurança.Ousoémuitosimples,aoredirecionarmosparauma determinadapágina,adicionamosoprimeirovalorusandoaseguintesintaxe: (?Chave=valor). No caso para passarmos mais de um conjunto de valores devemos ir concatenando com o caractere coringa (&). Podemos conferir um exemplo conforme nos ensina na listagem 05. protected void btnEnviarquerystring_ Click(object sender, EventArgs e) { string dadosPagina; dadosPagina = “WebFormQueryString.aspx?nome=” + txtNome.Text + “&endereco=” + txtEndereco. Text + “&cidade=” + txtCidade. Text + “&estado=” + txtEstado. Text + “&tipo=” + dropTipo. SelectedItem; Response. Redirect(dadosPagina); } No primeiro momento criamos uma variável do tipo “string”, passando a página(WebFormQueryString.aspx)seguidodospareschave/valorconcatena- dopelocoringa(&).Ométodo“Response.Redirect”iránosredirecionarparaa segunda página onde iremos carregar estes valores. Listagem 06. protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { lblNomeRec.Text = Request. QueryString[“nome”]; lblEnderecoRec.Text = Request.QueryString[“endereco”]; lblCidadeRec.Text = Request.QueryString[“cidade”]; lblEstadoRec.Text = Request.QueryString[“estado”]; lblTipoRec.Text = Request. QueryString[“tipo”]; } } É recomendável sempre utilizar o evento Page_Load para carregar estes parâmetros.Ométodo“Request.QueryString”identificaachaveenosretorna o valor inserido. Armazenaremos os resultados em Labels. 3-) Método Server Transfer Podemos dizer que o método “Server.Transfer” visivelmente possui o mesmo resultado do conhecido método “Server.Redirect”, nos locomovendo deumapáginaparaoutra.Adiferençaqueaousarométodo“Server.Transfer” oservidorconservaosrecursosjáutilizados,ouseja,aoinvésdesimplesmente redirecionarparaoutrapágina,eleapenasalteraofoconoservidoretransfere toda a requisição. Devemos tomar cuidado, pois, o processo de transferência pode operar somente em sites que estão rodando no servidor, lembrando que não podemos utilizar este método para uma página externa ao servidor. Outro detalhe interessante é que o “Server.Transfer” mantém a URL original noBrowser. Paraentendermosmelhorfaremosousoconformealistagem07.
  • 10. fevereiro 2014 10 Listagem 07: Código para enviar valores via Método “Server.Transfer”. Listagem 08: Código para receber valores via Método “Server.Transfer”. Listagem 09: Código para enviar valores via classe “HTTPContext”. Listagem 10: Código para enviar valores via classe “HTTPContext”. protected void btnEnviarServerTransfer_ Click(object sender, EventArgs e) { Server. Transfer(“WebFormServerTransfer. aspx”, true); } Nó código acima temos um segundo parâmetro booleano denominado “preserveForm”. Estamos definindo para “True” sendo assim a consulta exis- tente e qualquer variável de formulário ficará disponível para a página para a qual você esta fazendo a transferência. Para recuperarmos faremos conforme a Listagem 08. protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { var form = Request. Form; lblNomeRec.Text = form[“txtNome”]; lblEnderecoRec.Text = form[“txtEndereco”]; lblCidadeRec.Text = form[“txtCidade”]; lblEstadoRec.Text = form[“txtEstado”]; lblTipoRec.Text = form[“dropTipo”]; } } Noprimeiroatofoicriadaumavariáveldotipo“var”,recebendoosvalores do método “Request.Form”. Ao fazermos esta referência automaticamente conseguimos recuperar qualquer valor do webform anteriormente utilizado. Usaremos os valores dos Textboxes e do DropDownlist. 4-) Classe HttpContext Através desta classe podemos obter outras classes para manipulações de objetos. Ela encapsula todas as informações específicas sobre uma requisição HTTP, o objeto “HTTPContext” fornece acesso aos objetos em questão. É importante lembrar que os valores armazenados neste objeto serão válidos somente durante a duração de uma requisição. Ver Listagem 09. protected void btnEnviarHttpContext_ Click(object sender, EventArgs e) { HttpContext contexto = HttpContext.Current; contexto.Items[“nome”] = txtNome.Text; contexto.Items[“endereco”] = txtEndereco.Text; contexto.Items[“cidade”] = txtCidade.Text; contexto.Items[“estado”] = txtEstado.Text; contexto.Items[“tipo”] = dropTipo.SelectedItem; Server. Transfer(“WebFormHttpContext. aspx”); } Primeiramente instancie o objeto “HTTPContext” atribuindo o contexto corrente da aplicação. Podemos atribuir quais valores desejarmos utilizando o método “Items”. Utilizamos o mesmo comando abordado anteriormente, o Server.Transfer, sendo que desta vez passamos por parâmetro apenas alguns valores.Parareceberestesdadosfaremosocontrário,usandoamesmalógica de raciocínio. Ver Listagem 10. protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { HttpContext contexto = HttpContext.Current; lblNomeRec.Text = contexto. Items[“nome”].ToString(); lblEnderecoRec.Text = contexto.Items[“endereco”]. ToString(); lblCidadeRec.Text = contexto. Items[“cidade”].ToString(); lblEstadoRec.Text = contexto. Items[“estado”].ToString(); lblTipoRec.Text = contexto. Items[“tipo”].ToString(); } }
  • 11. fevereiro 2014 11 Listagem 11: Classe Usuário. Listagem 12: Código para enviar valores via Session. Lembrandoqueaoutilizarestaclasseestamosrestritosapenasaosobjetos definidos dentro do método “Context.Current.Items”. Uma dica sobre as variáveis de Sessão Umaideiaparaquemarmazenamuitasinformaçõesnasvariáveisdesessão seriacriarumaclasseparaestatarefa.Umexemplomuitoclaroparaistoseria para quem trabalha com dados de usuários, se tornando mais objetiva tanto para armazenar quanto para recuperar os campos envolvidos. Possuímos os mesmos campos descritos acima nesta classe. É necessário implementar os métodos “Get” e “Set”. Para quem não sabe, criar uma classe no Asp.Net é muito simples, basta clicar com o botão direito sobre a solução e escolher a opção“Add/NewItem...”.Definaonomecomo:“Usuario.cs”.VerListagem11. public class Usuario { public Usuario() { } private string _NOME; public string NOME { get { return _NOME; } set { _NOME = value; } } private string _ENDERECO; public string ENDERECO { get { return _ENDERECO; } set { _ENDERECO = value; } } private string _CIDADE; public string CIDADE { get { return _CIDADE; } set { _CIDADE = value; } } private string _ESTADO; public string ESTADO { get { return _ESTADO; } set { _ESTADO = value; } } private string _TIPO; public string TIPO { get { return _TIPO; } set { _TIPO = value; } } } Seguindoamesmatelacriadaanteriormente,iremoscodificarobotãoda seguinte maneira, Ver Listagem 12. protected void btnEnviarSessionObjeto_ Click(object sender, EventArgs e) { Usuario usuario = new Usuario(); usuario.NOME = txtNome. Text; usuario.ENDERECO = txtEndereco.Text; usuario.CIDADE = txtCidade. Text; usuario.ESTADO = txtEstado. Text; usuario.TIPO = dropTipo. SelectedItem.ToString(); Session.Add(“USUARIO”, usuario); Response.Redirect(“~/ WebFormSessionObjeto.aspx”); } Instancie a classe “Usuario” e alimente os seus atributos conforme os valoresdoscomponentes.Oprincipalcomandoéo“Session.Add”,énesteato queadicionamosoObjetocomovariáveldesessão.Paraefetuaraleituradestes dados faremos um “TypeCast” para a classe “Usuário” para posteriormente irmos recuperando os dados. Ver Listagem 13.
  • 12. fevereiro 2014 12 Listagem 13: Código para receber valores via Session. protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { lblNomeRec.Text = ((Usuario) Session[“USUARIO”]).NOME. ToString(); lblEnderecoRec.Text = ((Usuario)Session[“USUARIO”]). ENDERECO.ToString(); lblCidadeRec.Text = ((Usuario) Session[“USUARIO”]).CIDADE. ToString(); lblEstadoRec.Text = ((Usuario) Session[“USUARIO”]).ESTADO. ToString(); lblTipoRec.Text = ((Usuario) Session[“USUARIO”]).TIPO. ToString(); } } thiago@theclub.com.br Thiago Cavalheiro Montebugnoli adora aprender novas tecnologias. Formado pela Faculdade de Tecnologia de Botucatu – SP (FATEC), já desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco de Dados SQL Server e Firebird. Atualmente trabalha no Centro de Processamento de Dados da Prefeitura Municipal de Itaí-SP é colunista mensal da Revista The Club Megazine e é consultor Técnico do The Club. Possui as seguintes certificações: MCP - Microsoft Certified Professional, MCTS-MicrosoftCertifiedTechnologySpecialist,MCAD-MicrosoftCertifiedApplicationDeveloper e MCSD - Microsoft Certified Solution Developer. Sobre o autor Conclusões Pudemos aprender neste artigo diversas maneiras de resolver o mesmo tipodeproblema,trabalhandocomVariáveisdeSessão,Querystring,oMétodo Server.TransfereaclasseHttpContext.Ficaacargododesenvolvedorescolher a melhor técnica a seguir. Abraços e até o mês que vem!
  • 13. fevereiro 2014 13 Mostramos anteriormente,emdois artigos, as características do ASP.NET MVC. Neste artigo, quero falar exclusivamente de validações, pois é uma das funcionalidades mais importantes para cadastros de aplicações Web. Para que a sua aplicação funcione da melhor maneira possível, é neces- sário que os dados oriundos dos usuários sejam os mais corretos (falando em termos de integridade), assim temos a necessidade de validá-los antes de inserir no banco. Mostrarei nesse artigo como validar no ASP.NET MVC, verificando os dados na Action e usando DataAnnotattions, uma facilidade onde indicamos no Model o que queremos validar. Validações no ASP.NET MVC Criando a aplicação Vamoscriarumaaplicaçãosimples,paraquepossamosmostrarosexem- plos de validações para serem usadas em aplicações Web com ASP.NET MVC. Crie um novo projeto ASP.NET MVC 4 Web Application (Figura 1). Veja a Figura 1. Vamos usar o template Basic no projeto. Com o projeto criado, vamos criar um modelo, conforme a Listagem 1. Figura 1. Criando uma aplicação ASP.NET MVC
  • 14. fevereiro 2014 14 Listagem 1. Criando o modelo Listagem 2. Criando o contexto da aplicação Listagem 3. Criando o controller using System; using System.ComponentModel. DataAnnotations; namespace Validacoes.Models { public class Pessoa { [Key] public int ID { get; set; } public string Nome { get; set; } public DateTime Nascimento { get; set; } public string Login { get; set; } public string Email { get; set; } } } Crie também o Context, como podemos ver na Listagem 2. using System.Data.Entity; using Validacoes.Models; namespace Validacoes. Controllers { public class Contexto: DbContext { public DbSet<Pessoa> Pessoas { get; set; } } } Vamos criar agora, o Controller (Figura 2). Veja a Figura 2. Nota: caso deseje pode usar a técnica de templates com scaffolding. Resolvi fazer manualmente para mostrar como seria sem a técnica. Agora, vamos modificar o Controller (Listagem 3). using System.Linq; using System.Web.Mvc; using Validacoes.Models; namespace Validacoes. Controllers { public class PessoaController : Controller { private Contexto db = new Contexto(); public ActionResult Index() { return View(db. Pessoas.ToList()); } public ActionResult Create() { return View(); } [HttpPost] public ActionResult Create(Pessoa pessoa) { if (ModelState. IsValid) { db.Pessoas. Add(pessoa); db.SaveChanges(); Figura 2. Criando o controller da Pessoa
  • 15. fevereiro 2014 15 Listagem 4. Validando na action Listagem 5. View de cadastro de Pessoa return RedirectToAction(“Index”); } return View(pessoa); } } } Porenquanto,temosapenasdoismétodos.Umqueretornaumalistacom os registros (Index) e outro que insere os registros (Create). Validando na Action NoASP.NETMVCnãotemososcontrolesValidators,comonoASP.NETWeb Forms. Assim, podemos criar a validação na Action que cadastra o registro. Veja na Listagem 4, como podemos fazer a validação no Create. [HttpPost] public ActionResult Create(Pessoa pessoa) { if (string. IsNullOrEmpty(pessoa.Nome)) ModelState. AddModelError(“Nome”, “Campo Nome: preenchimento obrigatório.”); if (string. IsNullOrEmpty(pessoa.Login)) ModelState. AddModelError(“Login”, “Campo Login: preenchimento obrigatório.”); if (string. IsNullOrEmpty(pessoa.Email)) ModelState. AddModelError(“Email”, “Campo Email: preenchimento obrigatório.”); if ((DateTime.Now.Year - pessoa.Nascimento.Date.Year) < 18) ModelState. AddModelError(“Nascimento”, “Campo Nascimento: A idade deve ser maior que 18 anos.”); if (ModelState.IsValid) { db.Pessoas.Add(pessoa); db.SaveChanges(); return RedirectToAction(“Index”); } return View(pessoa); } A validação é bem simples, pois verificamos se o campo tem valores e adicionamos em ModelState.AddModelError, o nome do campo (parâmetro pede uma chave) e a respectiva mensagem de erro. Fizemos uma validação para que o cadastro aceite apenas Pessoas maiores de 18 anos. Vamos criar a View que vai usar a Action do cadastro. Veja na Listagem 5, a View do cadastro de Pessoa. @model Validacoes.Models.Pessoa @{ ViewBag.Title = “Create”; } <h2>Create</h2> @using (Html.BeginForm()) { @Html. ValidationSummary(true) <fieldset> <legend>Pessoa</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.Nascimento) </div> <div class=”editor- field”> @Html.
  • 16. fevereiro 2014 16 Listagem 6. Marcando o modelo com DataAnnotation TextBoxFor(model => model. Nascimento) @Html. ValidationMessageFor(model => model.Nascimento) </div> <div class=”editor- label”> @Html.LabelFor(model => model.Login) </div> <div class=”editor- field”> @Html. EditorFor(model => model.Login) @Html. ValidationMessageFor(model => model.Login) </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=”Salvar” /> </p> </fieldset> } <div> @Html.ActionLink(“Lista”, “Index”) </div> O “segredo” para apresentar as mensagens, é usar o ValidationSumary e ValidationMessageFor.CasonãousassemosoValidationMessageFor,amensa- gem não é apresentada, somente o campo fica com a cor em vermelho. Rode a aplicação e veja na Figura 3 o resultado. Nota: Precisamos criar um cController Home para chamar a tela de cadastro. Figura 3. Validando o cadastro de Pessoa Validando com DataAnnotattion A validação anterior funciona, mas imagine uma quantidade grande de camposnocadastro,otrabalhoéoneroso,semfalarqueprecisamosadicionar nessa Action mais validações, se mais campos forem incluídos no modelo. Umamaneirafácildevalidar,éusandoDataAnotattionnomodelo.Temos queapenas“marcar”cadapropriedadedomodelo.Essamarcaçãoindicaseo campoéobrigatório,quantidadedecaracterespermitidos,usodeexpressões regulares etc. Veja na Listagem 6 como fica o modelo com DataAnnotattion. [Required(ErrorMessage=”Campo Nome: preenchimento obrigatório.”)] [StringLength(35, ErrorMessage=”Campo Nome: aceita no máximo 35 caracteres.”)] public string Nome { get; set; } [Remote(“ValidaIdade”, “Pessoa”, ErrorMessage = “Campo Nascimento: A idade deve ser maior que 18 anos.”)] public DateTime Nascimento { get; set; } [Required(ErrorMessage = “Campo Login: preenchimento obrigatório.”)] [StringLength(15, ErrorMessage = “Campo Login: aceita no máximo 15 caracteres.”)] public string Login { get; set; } [Required(ErrorMessage =
  • 17. fevereiro 2014 17 Listagem 7. Validando o campo Nascimento com método no Controller “Campo Email: preenchimento obrigatório.”)] [RegularExpression(@”^[A- Za-z0-9] (([_.-]?[a-zA-Z0-9]+)*)@ ([A-Za-z0-9]+) (([.-]?[a-zA-Z0-9]+)*). ([A-Za-z]{2,})$”, ErrorMessage = “Campo Email: valor inválido.”)] [EmailAddress(ErrorMessage=”Cam po Email: valor inválido.”)] public string Email { get; set; } Vamos explicar qual a característica de cada um. O Required indica que o campo é obrigatório e um dos seus parâmetros é a mensagem de erro (assim como temos nos outros). StringLength permite que possamos definir um tamanho para a string, assim indicamos no parâmetro o tamanho e no outro a mensagem. Em RegularExpression podemos indicar uma expressão regular. Nesse caso, é para validar o e-mail (código retirado da internet). Também podemos validaroe-mailcomoEmailAddress,maseleestapresentesomentenaversão 4.5 do .NET Framework. Lembre-se disso. Porfim,oRemote,possibilitaquepossamosusarummétodoparavalidaro campo.Assim,indicamosométodo,ocontrollereamensagemdeerro.Muito eficiente para validações que precisamos pesquisar no banco para verificar se o campo é único, por exemplo, como o login. No exemplo, vamos apenas validar se a data informada é maior que 18 anos, semelhante ao feito anteriormente. Veja na Listagem 7 o código do método no PessoaController. [AllowAnonymous] public JsonResult ValidaIdade(DateTime Nascimento) { var result = (DateTime.Now. Year - Nascimento.Date.Year) > 18; return Json(result, JsonRequestBehavior.AllowGet); } Note que o retorno do método é um JsonResult. Dentro do método, veri- ficamos se a idade é maior que 18 e retornamos o Json, com o parâmetro da validação. Na View precisamos adicionar a biblioteca de validação do jQuery. Adicione no final do arquivo o seguinte código: @section Scripts { @Scripts.Render(“~/bundles/ jqueryval”) } Executeaaplicaçãoetentesalvarumadatadenascimentoqueovalorda idade seja menor que 18 (Figura 4). Figura 4. Validando no servidor a idade da Pessoa Note que é essencial o uso da biblioteca do jQuery para que a validação funcionecorretamente.AfacilidadedeDataAnnotattionsproporcionaodesen- volvimentodemodelosrobustosefáceisdeseremmodificados(manutenção). Conclusões VimosnesteartigocomotrabalharcomvalidaçõesemaplicaçõesASP.NET MVC. Podemos notar que a quantidade de possibilidades é grande, deixando a cargo do desenvolvedor, escolher a que mais se adapta a sua aplicação. Validações de dados em ambiente Web são muito importantes, pois não da margem para mal intencionados acessariam sua aplicação. Já trabalhei em projetos que era solicitado que se fizesse validação no cliente e no servidor, então, caso seja a sua necessidade, vimos nesse artigo as duas possibilidades em aplicações ASP.NET MVC. Um grande abraço a todos e até a próxima! www.lucianopimenta.net Luciano Pimenta LucianoPimenta(NOVODOMINIO:www.lucianopimenta.com)édesenvolvedorDelphi/C# paraaplicaçõesWebcomASP.NET,WindowscomWin32eWindowsFormscom.NET.Palestrante da 4ª edição da Borland Conference (BorCon) e da 1ª Delphi Conference. É MVP Embarcadero, grupo de profissionais que ajudam a divulgar o Delphi no mundo. Atualmente é desenvolvedor da SoftDesign fábrica de softwares em Porto Alegre-RS. Autor de mais de 90 artigos e de mais de 600 vídeos aulas publicadas em revistas e sites especializados, além de treinamentos presenciais e multimídias. É consultor da FP2 Tecnologia (www.fp2.com.br) onde ministra cursos de programação e banco de dados. Sobre o autor
  • 18. fevereiro 2014 18 O Desenvolvimento de Software sempre trouxe técnicas inovadoras, através do seu próprio processo de trabalho ondedesenvolvedoresdeumdeterminadoprojetopodem aprender com seus erros e compartilhar soluções, muitas delas adquiridas com tempo, paciência, dedicação e não por último aprendizado. Ressaltei em artigos anteriores a importância de uma implementação de recursos em mais de um ambiente, batizando de multiplataforma um concei- to flexível e eficiente para o gestor que exige uma aplicação independente do ambiente em que está rodando – experiência própria – portanto fica o aprendizado e a sua transmissão no decorrer deste artigo em que procuro abordar alguns tópicos produtivos e que podem ser estendidos com tamanha profundidade e dinamismo. Para este artigo será utilizado um aplicativo de demonstração (fictício) – baseadoemumexistenteprofissionalmente–emqueserãodemonstradasas funcionalidades em tempo de execução e como o código correspondente foi escritoeassociadoàportabilidadedaideiaprincipaldesteartigo.Estánascendo o nosso “Projeto Pegaso” (poderia ser qualquer nome). O Framework Itil já dizia: “As Empresas buscam inovar seus processos para se tornarem mais eficientes e competitivas. Inovações que dão certo transformam-seemmelhorespráticas”.Estaimplementaçãojáfoidevidamente testada, é livre, tem uma boa resposta de execução, é acessível a todos e por issojustifica-seemumaboapráticadeserviço.Inovaçõesbemimplementadas atravésderequisitosexigentesebemdocumentadospodemserbeneficiadas futuramente com o ganho de produtividade e performance em que o ciclo do projeto poderia experimentar – e a organização do código-fonte em módulos Projeto Pegaso: Aprendendo a utilizar OrientaçãoaObjetoscomRecursosMulti-Plataforma – Novas Técnicas de Programação também “alivia” a carga onerosa de implementação repetida exaustivamente para todas as chamadas de tela, por exemplo. TConexao–NossaclassedeAbstraçãoeEncapsulamentode Segregação de Ambientes: Nossaclassequejáfoitemadeoutrosartigosagoravoltamaisforte–sua implementação e utilização está mais profissional para o desenvolvedor, que irá perceber a empregabilidade e chamadas de funções/procedimentos em um nível mais amigável, legível e mais poderoso no quesito portabilidade – por isso segue abaixo para revisão – a classe TConexao e como ela trabalha “embaixo dos panos”: Veja a Figura 01. Considerações Iniciais: O nosso projeto consistirá de alguns itens importantes de construção e modelagem, a seguir: 1. OBancodeDadoséoDBISAM,fácilpararelacionaraoprojeto,pois não tem configuração alguma com dll´s, setup´s, drivers, etc; e como não é um projeto grande (pelo menos por enquanto) pode-se utilizar esta solução temporariamenteparaademonstraçãodanossaideiainicial;podendomigrar evolutivamente para outra solução a medida em que o projeto cresce – mas não está dentro do escopo deste artigo por agora; 2. Componentes adicionais foram utilizados, a maioria shareweare; Figura 01 - Como as camadas se comunicam com a classe TConexao. Enquanto que uma camada chama, outra sempre a escuta e resolve.
  • 19. fevereiro 2014 19 a principal intenção é permitir ao desenvolvedor visualizar o código-fonte e compreender aos poucos a evolução do desenvolvimento e relacionar à sua experiência de trabalho também – ele pode ser adaptado a qualquer projeto e logicamente customizado sem nenhum problema. Claro que com todos os componentesjáinstaladospode-secompilareexecutar,emboraqueosistema possaserexecutadoporforasemproblemasvistoquecomoditoanteriormente no item 1 que não há configurações de banco de dados que interfiram neste processo. Por isso, o deploy inicial torna-se muito mais fácil. 3. Este projeto é freeware e pode ser estendido e reutilizado livre- mente. A intenção é de que seja vista todos os recursos da Orientação a Objetos utilizados bem como a empregabilidade do tema do artigo – a classe de segregação de ambientes – a TConexao – foco principal do mesmo. Primeiros Passos – O “pontapé” inicial: Para conceituar e exemplificar nosso projeto, temos a camada de apre- sentação principal, que é o cadastro de clientes, que por sua vez chama a classe TPessoaFisica, e que por sua vez chama a classe TConexao, que por fim realizará todo o processo de persistência ao nosso BD selecionado e escolhi- do – diga-se de passagem “selecionado” por poder escolher mais de um; no momento iremos abordar apenas a implementação primeiramente deste BD devidoàsrazõeselencadasacima.Emoutroartigoiremosexploraravinculação com outros bancos, dentre os quais relacionais e com outros tipos de dados como o JSON, etc; Iremos abordar também o uso de Tabsheets como contêineres para objetos do tipo frames instanciados dinamicamente através de uma interface padrão – a nossa IFrame. Além de chamadas básicas à classe TPessoaFisica também haverá uma chamada indireta – que é o módulo de histórico – onde o seu carregamento será sob demanda (dinâmico) e com um objeto explícito (vide abaixo – alguns trechosdecódigo-fonterelacionadosaoprocessodepersistênciadehistórico transcritos manualmente): “ procedure TfrmEditor. CarregaHistorico; begin if not Assigned(_fObject) then Exit; if _fObject.ClassName = ‘TPessoaFisica’ then begin TPessoaFisica(_fObject).Ca rregaHistorico(tempClientDataS et); end; end; procedure TfrmEditor. SalvarHistorico; begin if not Assigned(_fObject) then Exit; if _fObject.ClassName = ‘TPessoaFisica’ then begin TPessoaFisica(_fObject).Sal varHistorico(DBSRichViewEdit1. RichViewEdit.Field.AsVariant); end; end; function TPessoaFisica. SalvarHistorico(const myContentFieldHistorico: Variant): Boolean; begin Result := Conexao. CarregarBlob(AbreHistorico,’DS_ HISTORICO’, myContentFieldHistorico); end; function TPessoaFisica. AbreHistorico: TDataSet; begin Result := Conexao.RetornaData Set(Format(sqlSelectHistoricoPe ssoaFisicaFromNome, [Nome])); end; function TConexao. CarregarBlob(const myDataSet: TDataSet; const myFieldBlob: string; const myContentFieldBlob: Variant): Boolean; begin with (myDataSet) do begin try Edit; FieldByName(myFieldBlob). AsVariant := myContentFieldBlob; Post; Result := True; except on E: Exception do begin Raise EInvalidDataBase. Create(EErroGeralBancoDeDados +
  • 20. fevereiro 2014 20 #13#10 + E.Message); Result := False; end; end; end; end; Figura 01 – Fragmentos de Código-Fonte relacionados à função chamadora de carregamento de histórico. TMaskeditHV: Nosso componente Validador de Dados – Ca- mada de Apresentação Este componente, também tema de outras edições da TheClub, é o en- carregado de manipular todas as críticas de dados de input manipuladas pelo usuário. Formatos de dados como padrão ou do tipo checklistbox (seleção múltipla), armazenamento interno (propriedade published CustomDataSet) de qualquer descendente de TDataSet, vários tipos de formatos de entrada de dados pré-definidos (Data, Data/Hora, Monetário, CPF, etc), detecção de filtros de Estados/Cidades automáticas (onde um objeto instanciado de TMaskeditHVfiltraoutrodele),combosinternascomocontêineres,tratamento das teclas Enter/Tab para processamento automático, tratamento de campos obrigatórios/default, validações de tipos (monetários, data, hora, etc), enfim, muitosrecursosencapsuladosparamaiorversatilidadeeprodutividadeparaa implementaçãodemáscaras,filtros,eventosetratamentoscomfunçõespara suasmanipulações–tudoissoabstraídonestecomponente.Oboméquecomo tudo isso já está pronto, as coisas ficaram fáceis para usar e testar – imagine verificando um campo vazio: if (mskProcuraDadosCliente. IsEmpty) then Exit; Outros exemplos: Carregar um objeto com máscara de telefone, onde o valor guardado está sem a máscara: mskTelComercialAreaComercial01. LoadText(PessoaFisica. Telcomercialareacomercial01); Carregar dados de um objeto descendente de TDataset para armazena- mento interno do TMaskeditHV: AssociarapropriedadeCustomDataSetdoObjectInspectorparaoobjeto dataset desejado. Algumas funções interessantes: Obter a Seleção Padrão: //==> combobox default => ShowMessage(MaskEditHV1.Text + ‘ GetIndex ‘ + IntToStr(MaskEditHV1.GetIndex)); Obter a Seleção Múltipla: var i: integer; begin //==> combobox tipo checkList => (abaixo) => if not Assigned(MaskEditHV2. customComboCheckList) then Exit; for i := 0 to MaskEditHV2. customComboCheckList.Items. Count - 1 do if MaskEditHV2. customComboCheckList. IsChecked(i) then ShowMessage(‘Get Text at Index ‘ + MaskEditHV2. GetTextAtCheckListPosition(i) + ‘ GetValue at Index ‘ + IntToStr(MaskEditHV2.GetIndexAt CheckListPosition(i))); Carregando um conjunto de registros: procedure TForm1. Button1Click(Sender: TObject); begin if MaskEditHV1.IsEmpty then Exit; with MaskEditHV1.CustomDataSet do begin Filter := ‘NOME = ‘ + QuotedStr(MaskEditHV1.Text); Filtered := True; edtCDUsuario.Text := Fields[0].AsString; edtNome.Text := Fields[1]. AsString; edtDtNascimento.Text := Fields[2].AsString; edtEndereco.Text := Fields[3].AsString; edtCidade.Text := Fields[4].AsString; edtEstado.Text := Fields[5].AsString; edtCEP.Text := Fields[6]. AsString; edtSetor.Text := Fields[7]. AsString; edtTelefone.Text :=
  • 21. fevereiro 2014 21 Fields[8].AsString; edtSalario.Text := Fields[9].AsString; edtMatricula.Text := Fields[11].AsString; mskCDUsuario.Text := Fields[0].AsString; mskNome.Text := Fields[1]. AsString; mskDtNascimento.Text := Fields[2].AsString; mskEndereco.Text := Fields[3].AsString; mskCidade. LoadValueByIndex(Fields[4]. AsString, True); mskEstado. LoadValueByIndex(Fields[5]. AsString, True); mskCEP.LoadText(Fields[6]. AsString); mskSetor.Text := Fields[7]. AsString; mskTelefone. LoadText(Fields[8].AsString); mskSalario.Text := Fields[9].AsString; mskMatricula.Text := Fields[11].AsString; end; end; Tela correspondente do código acima (simulação com Firebird): Figura03–ObjectInspectordoMaskeditHVcomsuapropriedadeCustomDataSet selecionada, associada com um ClientDataSet “ClUsuario”. Repare na figura acima: quando foi especificado o valor de um objeto TDataSetnapropriedadeCustomDataSet,duaspropriedadesforamautomati- Figura 02 – Modelo de Tela para chamar um objeto descendente de TDataSet associado com a propriedade CustomDataSet de um MaskeditHV (no exemplo, associando um ClientDataSet – conexão com Firebird)
  • 22. fevereiro 2014 22 camentepreenchidas:aCustomFieldNamePassedAsObjectStringParameterea CustomFieldNamePassedAsObjectIntegerParameter.Essaspropriedadesobtém o primeiro campo do tipo string e o primeiro campo do tipo integer encontra- dos no dataset relacionado, respectivamente. Para que isso? É para quando o componente entrar em modo de edição: ele vai simular um combobox, como em“Items.AddObject(fComboCustomText.Strings[i],TObject(i)))”–ondeestes valoresstringeintegerserãoarmazenadosnestafunçãoAddObjectdeTStrings (functionTStrings.AddObject(constS:string;AObject:TObject):Integer).Aidéia éfacilitarnaassociaçãoerecuperaçãodestesvalores–métodoget–GetIndex – método set – LoadValueByIndex(intCodigoDesejado). Finalmente, o componente MaskeditHV1.CustomDataSet funcionará da mesma forma que um DataSet normal, podendo filtrar, etc; neste projeto a camadadeapresentaçãosebaseiafortementenestecomponente.Ecomisso todas as validações de input foram abstraídas e rapidamente implementadas. Figura04–FormatosdeexibiçãodoTMaskeditHV–padrão(cbftDefault)eseleção múltipla (cbftCheckList) da propriedade ComboboxFormate (declaração: type TCom- boboxFormate = (cbftDefault, cbftCheckList) ). Inicialização da Aplicação: Figura 05 – Tela Principal do Projeto. Apenas o primeiro botão (Cadastro) está funcional. O resto não foi escrito para este propósito do nosso artigo. Figura06–EventoOnClickdobotãoCadastro,mostrandoateladeseleçãodotipo de Pessoa – apenas a primeira opção está funcional. Figura 07 – Carregamento da Tela de Cadastro de Pessoa Física.
  • 23. fevereiro 2014 23 Figura 08 – Layout padrão das mensagens de “alert” do sistema (tipos “Informação”, “Con- firmação”, etc). Figura 09 – Carregamento da Tela de Histórico – note a presença de um corretor ortográfico no campo memo de edição (componentes shareweare TAddictSpell e TScaleRi- chView, respectivamente) – além de outros já utilizados em todas os demais forms por padrão (TMS Software e SuniSoft Software). Figura10–CarregamentodaTela“ReferênciasBancárias”.Estatela(comooutrasreferenciadasnopaineldireitodeatalhos)serefereatodasquesãocriadasdinamicamente via Tabsheet com frames embutidos. É a abstração via interface. Tal recurso será explicado adiante.
  • 24. fevereiro 2014 24 Basicamente, nossa primeira versão da demonstração do programa se resume a isto. Há algumas considerações a serem feitas antes da explicação da classe de pessoa física. Vamos a elas: 1. A arquitetura da criação das janelas é do tipo MDI (Multiple Docu- mentInterface),ondemaisdeumajanelafilhapodeserabertadentrodeuma janela pai, que é a primeira janela (main) a ser exibida com a barra de botões acima dela. 2. Nãopoderáserchamadaecarregadaamesmateladuasvezes.Para isso, a função booleana “JanelaExiste” (unit Biblioteca) será chamada sempre na criação desta janela, onde senão criada, será, se sim, será recuperada (if Biblioteca.JanelaExiste(frmEscolherTipoPessoa) then Exit); 3. Algumas funções como LockClientWindowUpdate e U n l o - ckClientWindowUpdateforamdeclaradaseimplementadasparaevitaroefeito de“telacongelada”queapareciaquandoeraexibidasemaparentementeestar toda carregada (vide trecho do código-fonte abaixo): procedure TfrmPrincipal. LockClientWindowUpdate; begin if fLockClientWindowUpdateCount = 0 then SendMessage(ClientHandle, WM_SETREDRAW, 0, 0); Inc(fLockClientWindowUpdateCo unt) ; end; procedure TfrmPrincipal. UnlockClientWindowUpdate; begin Dec(fLockClientWindowUpdateCo unt) ; if fLockClientWindowUpdateCount = 0 then begin SendMessage(ClientHandle, WM_SETREDRAW, 1, 0) ; RedrawWindow(ClientHandle, nil, 0, RDW_FRAME or RDW_ INVALIDATE or RDW_ALLCHILDREN or RDW_NOINTERNALPAINT); end; end; Figura 11 – Chamadas das funções LockClientWindowUpdate e UnlockClientWin- dowUpdate. Carregando em um ClientDataSet automaticamente o conjunto de dados retornados da nossa classe: Nosso aplicativo teve a abstração e encapsulamento como as melhores ideias para a performance e eficiência em sua construção, agilizando todas as chamadas às consultas de banco de dados, como no seguinte caso demons- trado abaixo, onde o nosso objeto de TPessoaFisica passa um objeto do tipo TClientDataSet como referência, onde será carregado como retorno: 1. Passando o objeto do tipo TClientDataSet para o método de TPes- soaFisica: PessoaFisica.CarregaConsultaPessoaFisica(ClPessoaFisica); 2. Este método, por sua vez, chamará internamente a função Abre- RecordSetPessoaFisica, que retornará um TDataSet contendo os dados requi- sitados, conforme mostrados abaixo: procedure TPessoaFisica. CarregaConsultaPessoaFisica( var myClientDataSet: TClientDataSet); begin Self.ObterDataSet(Self. AbreRecordSetPessoaFisica, myClientDataSet); end; { TPessoaFisica } function TPessoaFisica. AbreRecordSetPessoaFisica: TDataSet; begin Result := Conexao.RetornaData Set(sqlSelectAllFieldsPessoaFis ica); end; { sql´s classe PessoaFisica } sqlSelectAllFieldsPessoaFisica: string = ‘SELECT * FROM PESSOAFISICA ORDER BY NOME’; function TConexao. RetornaDataSet(Query: String): TDataSet; begin if Self is TConexaoDBISAM then Result := TConexaoDBISAM(Self). RetornaDataSet(Query) else if Self is TConexaoXML then Result := TConexaoXML(Self). ExecutaSelect(Query) else if Self is TConexaoFirebird then Result := TConexaoFirebird(Self). RetornaDataSet(Query); end; Figura 12 – Chamadas de alguns métodos relevantes para a obtenção de dados para o carregamento de um ClientDataSet como parâmetro, a serem mostrados no método CarregaConsultaPessoaFisica de TPessoaFisica. Mapeamento de Objetos com ClientDataSets desejados: Foi implementado uma função para simplificar as procuras dos objetos comseusClientDatasetsrelacionados –poderíamosfazerumIFparacadaum em uma coleção, mas dinamicamente poderia ficar pesado na construção – principalmente em muitos objetos procurando todos os seus ClientDatasets, umavezquenanossatécnicadeimplementaçãoédeumpraum–nessecaso
  • 25. fevereiro 2014 25 doisarrayssãocriados–ondeumprocurapelooutroemumDataModuleese encontrar, o retorna: imagine muitos DataModules de muitos bancos – sem esta ideia ficaria muito complexo! Segue a declaração da função abaixo – classe TConexao: function TConexao. MapClientDataSets(const fObject: TObject; const fClientDataSet: TObject): TClientDataSet; const arClientDataSets: array [0..3] of string = (‘ClPropriedadeRural’, ‘ClParticipacaoEmpresas’, ‘ClReferenciaBancaria’, ‘ClPessoaFisica’); arObjects : array [0..3] of string = (‘TPropriedadeRural’, ‘TParticipacaoEmpresas’, ‘TReferenciaBancaria’, ‘TPessoaFisica’); var i: integer; begin Result := nil; for i := 0 to High(arObjects) do if (fClientDataSet. ClassName = arObjects[i]) then begin Result := TClientDataSet (TConexao(fObject).RetornaDM.Fi ndComponent(arClientDataSets[i] )); Break; end; end; if Self is TConexaoFirebird then begin try fClientDataSet := TConexao((TConexao(Self). RetornaDM)). MapClientDataSets(Self, fClassName); except on E: Exception do Raise EAbstractError. Create(EErroComponente + #13#10 + E.Message); end; try fClientDataSet.Close; fClientDataSet.Open; fClientDataSet.Refresh; if not (fClientDataSet. state in dsEditModes) then fClientDataSet.Edit; TBlobField(fClientDataSet. FieldByName(MyFieldName)). AsString := fTexto; fClientDataSet.Post; fClientDataSet. ApplyUpdates(0); except on E: Exception do Raise EInvalidDataBase. Create(EErroGeralBancoDeDados + #13#10 + E.Message); end; Result := True; end; Figura13–DemonstraçãodafunçãodemapeamentoMapClientDataSets,utilizada nas chamadas entre objetos instanciados e ClientDataSets simultaneamente. Figura 14 - Diagrama de Sequência do componente TConexao.
  • 26. fevereiro 2014 26 Agora, finalmente, o processo completo de funcionamento de acordo com a orientação a objetos juntamente com a nossa classe: Veja a figura 15. Resumindo:nossaclasseTConexaoserásemprearesponsávelporreceber as requisições das classes negociais (no nosso caso, a classe TPessoaFisica) e retornando um conjunto descendente de TDataSet (de acordo com o banco escolhido). Portanto, toda vez que uma classe quiser acessar um banco, ela na verdade acessa uma instância da classe de conexão (TConexao), onde esta por sua vez referenciará-lo em memória. Toda a interface de comunicação e operacionalização será realizada somente através dela, estando disponível até ser destruída. Abaixo, uma seleção de alguns métodos importantes utilizados na classe TConexao - detalhe para os métodos ObterDataSet, CarregarFoto e GetCo- nexao (sintaxe: Conexao := Conexao.GetConexao(fbdConexao)) - que são os métodos mais importantes do processo de comunicação entre os objetos de negócio e dados. procedure TConexao. ObterDataSet(const myDataSet: TDataSet; var myClientDataSet: TClientDataSet); var fDataSet: TDataSet; i {, k}: integer; FName: string; begin if not Assigned(myDataSet) then Exit; if not Self.BancoInstanciado then begin Application.MessageBox(PCha r(Format(EBancoNaoInstanciado, [FUsuariosFDB])), ETituloErro, MB_OK + MB_ICONERROR); Abort; end; fDataSet := TClientDataSet(myDataSet); fDataSet.First; if not myClientDataSet.Active then myClientDataSet. CreateDataSet else myClientDataSet. EmptyDataSet; myClientDataSet. DisableControls; try while not fDataSet.Eof do begin myClientDataSet.Insert; for i := 0 to fDataSet. FieldCount - 1 do begin // myClientDataSet. Fields[i].Assign(fDataSet. Fields[i]); myClientDataSet. FieldDefs.Items[i].DataType := (fDataSet.FieldDefs.Items[i]. DataType); myClientDataSet. FieldDefs.Items[i].DisplayName := (fDataSet.FieldDefs. Items[i].DisplayName); case myClientDataSet. FieldDefs.Items[i].DataType of ftString: myClientDataSet.Fields[i]. AsString := Self. DefaultDateFormat2(fDataSet. Fields[i].AsString); ftDate: myClientDataSet.Fields[i]. AsString := Self. DefaultDateFormat2(fDataSet. Fields[i].AsString); ftFloat: myClientDataSet.Fields[i]. AsFloat := Biblioteca. Figura 15 - Explicação da operacionalização do funcionamento das camadas juntamente com as regras negociais e com a classe TConexao.
  • 27. fevereiro 2014 27 ArredondaComDecimais( fDataSet. Fields[i].AsFloat, 2); else myClientDataSet. Fields[i].AsString := fDataSet.Fields[i].AsString; end; end; myClientDataSet.Post; fDataSet.Next; end; finally myClientDataSet. EnableControls; end; end; procedure TConexao. ObterDataSet(const myDataSet: TDataSet; var myStringList: TStringList); var fDataSet: TDataSet; i: integer; begin if not Assigned(myDataSet) then Exit; fDataSet := TClientDataSet(myDataSet); fDataSet.First; if not Assigned(myStringList) then myStringList := TStringList.Create; while not fDataSet.Eof do begin myStringList.Add(fDataSet. Fields[0].AsString); fDataSet.Next; end; end; function TConexao. RecordCount(Query: String): integer; begin if Self is TConexaoDBISAM then Result := TConexaoDBISAM(Self). RecordCount(Query) else if Self is TConexaoXML then Result := TConexaoXML(Self). RecordCount(Query) else if Self is TConexaoFirebird then Result := TConexaoFirebird(Self). RecordCount(Query); end; function TConexao. RecordCount(const myDataSet: TDataSet): integer; begin Result := (TDataSet(myDataSet). RecordCount); end; function TConexao. RetornaDataSet(Query: String): TDataSet; begin if Self is TConexaoDBISAM then Result := TConexaoDBISAM(Self). RetornaDataSet(Query) else if Self is TConexaoXML then Result := TConexaoXML(Self). ExecutaSelect(Query) else if Self is TConexaoFirebird then Result := TConexaoFirebird(Self). RetornaDataSet(Query); end; function TConexao. CarregarFoto(const MyFile: string; const myDataSet: TDataSet; const MyFieldName: string = ‘FOTO’): Boolean; function GetTableNameFromXMLSyntax(const mySQLXML: string): string; begin if System. Pos(AnsiUpperCase(‘where’), AnsiUpperCase(mySQLXML)) > 0 then Result := trim(Before(af ter(AnsiUpperCase(mySQLXML), ‘FROM’), ‘WHERE’)); end; var S: TFileStream; fClientDataSet: TClientDataSet;
  • 28. fevereiro 2014 28 auxTableName: string; auxFilterFields: string; begin if Self is TConexaoXML then begin if (Self.FiltroXML = ‘’) then Exit; auxTableName := GetTableNameFromXMLSyntax(Self. FiltroXML); auxTableName := auxTableName + ‘.xml’; fClientDataSet := TConexaoXML(Self). CarregarBanco(auxTableName); auxFilterFields := Before(after(AnsiUpperCase(Self. FiltroXML),’WHERE’), ‘ORDER’); fClientDataSet.Filter := auxFilterFields; fClientDataSet.Filtered := True; try fClientDataSet.Close; fClientDataSet.Open; if not (fClientDataSet. state in dsEditModes) then fClientDataSet.Edit; TBlobField(fClientDataSet. FieldByName(MyFieldName)). LoadFromFile(MyFile); fClientDataSet.Post; fClientDataSet. SaveToFile(TConexaoXML(Self). CaminhoXMLAtual, dfXML); except on E: Exception do begin Raise EInvalidDataBase. Create(EErroGeralBancoDeDados + #13#10 + E.Message); Result := False; end; end; end else if Self is TConexaoDBISAM then begin S := TFileStream. Create(MyFile ,fmOpenRead); with (myDataSet) do begin try try Edit; TBlobField(Fie ldByName(MyFieldName)). LoadFromStream(S); Post; except on E: Exception do begin Raise EInvalidDataBase. Create(EErroGeralBancoDeDados + #13#10 + E.Message); Result := False; end; end; finally S.Free; end; end; end else if Self is TConexaoFirebird then begin fClientDataSet := dmFirebird.ClUsuario; try fClientDataSet.Close; fClientDataSet.Open; fClientDataSet.Refresh; if not (fClientDataSet. state in dsEditModes) then fClientDataSet.Edit; TBlobField(fClientDataSet. FieldByName(MyFieldName)). LoadFromFile(MyFile); fClientDataSet.Post; fClientDataSet. ApplyUpdates(0); except on E: Exception do begin Raise EInvalidDataBase. Create(EErroGeralBancoDeDados + #13#10 + E.Message); Result := False; end; end; end; end; function TConexao.
  • 29. fevereiro 2014 29 GetConexao(const typeConexao: tBDConexao): TConexao; begin if Assigned(Result) then closeConexao; case typeConexao of bdConexaoDBISAM: Result := TConexaoDBISAM.create; bdConexaoXML: Result := TConexaoXML.create; bdConexaoFirebird: Result := TConexaoFirebird.create; end; end; Figura 16 – Alguns comandos importantes da classe TConexao relevantes para os procedimentos de acesso e persistência das bases de dados do projeto (multiplatafor- ma). Perceba os métodos RecordCount, ObterDataSet, RetornaDataSet, CarregarFoto e outros. Conclusão Foramdemonstradasascaracterísticasmaisimportantesdonossoprojeto, aindaqueemumnívelmenosdetalhado,ofuncionamento(comunicação)entre acamadadeapresentação(unitUnCadastroPessoaFisica),classenegocial(unit UnTPessoaFisica)eaclassedepersistênciamultiplataforma(unitUnConexao); Foram explanados principais componentes que integram o projeto, como a classe validadora TMaskeditHV de minha autoria, já explicado em artigos anteriores e abordado principais aspectos novamente – utilizado na camada de apresentação para críticas/formatos de validação, bem como outras funcionalidades (combobox embutido, contêiner para TClientDataSet, chamadas automáticas de formatação (ex: extrair somente o valor e sem nenhuma máscara – método ExtractJustText de TMaskeditHV – PessoaFisica. CPFMae := mskCPFMae.ExtractJustText); também foram mencionados alguns componentes shareweare de terceiro, embora sem profundidade, utilizados para design da camada de apresentação (ex: componentes dos pacotes TMS Software/TScaleRichView/SuniSoft); Por último, foi demonstrado um “overview” do sistema, exibindo o principal funcionamento em nível de demonstração – o que o usuário final realmentevê.Entretanto,focamosmais“nosbastidores”dosistema,extraindo ositensrelevantesdecodificação(noçõesdeOrientaçãoaObjetos)bemcomo a operacionalização das nossas classes que interagem entre si (TConexao e TPessoaFisica); Com isso, espero que esta leitura possa proporcionar ao leitor uma agra- dável experiência de codificação e ideias novas de layout de telas, através das técnicas de demonstração do código-fonte e sugestões suaves e leves de forms, respectivamente. Finalmente, espero que o leitor tenha o prazer que eu tive ao desenvolver este projeto também. Um abraço e até a continuação do próximo artigo. Boa leitura !