O que é o Framework .NET

Transcrição

O que é o Framework .NET
Framewoks de
Desenvolvimento
Frameworks de Desenvolvimento
Conteúdo
Unidade 1 Definição de Framework
5
Classificação dos Frameworks
7
Profissionais Envolvidos
8
Benefícios e Desafios Decorrentes da Adoção de um Framework
Unidade 2 Plataforma de Desenvolvimento Java
10
11
Ambiente Eclipse
Unidade 3 Introdução ao Framework .NET
18
Visão Geral
19
O que é o Framework .NET
19
Common Language Runtime
19
Biblioteca de Classes do Framework .NET
20
Dificuldades encontradas no desenvolvimento de sistemas para Windows antes do .NET
21
A abordagem .NET
24
Unidade 4 A Arquitetura .NET
25
CLR (Commom Language Runtime)
25
CTS (Common Type System)
25
CLS (Common Language Specification)
26
BCL (Base Classe Library)
26
Unidade 5 Criando Aplicações com o Visual Studio
28
Versões do Framework .NET e Visual Studio
28
Conhecendo a IDE
29
Criando um Novo Projeto
29
Componentes da IDE
31
Menu
2
13
31
Frameworks de Desenvolvimento
Toolbar (Barra de Ferramentas)
32
Toolbox
32
Solution Explorer
35
Properties
36
Janela de Design
38
Janela de Código – Code View
38
Criando um Hello World
38
Criando uma Calculadora
40
Passo 1 – Ajustando o Formulário
41
Passo 2 – Posicionando os Controles
41
Passo 3 – Adicionando Funcionalidades
43
Unidade 6 Programação Orientada a Objetos
Introdução
47
Por que OOP existe?
47
Conceitos de encapsulamento, herança e polimorfismo
50
Implementação prática dos conceitos
52
Herança e Agregação
56
Interfaces
63
Tratamento de exceções
69
Conversão de tipos (Typecasting)
75
Unidade 7 Segurança em Aplicações .NET
81
Utilização de Strong Names
81
A importância do StrongName
82
SQL Injection
86
Unidade 8 Acessando Dados com ADO
3
47
88
Camada Desconectada
88
Camada Conectada
88
Frameworks de Desenvolvimento
ADO Object Model
89
Camada Desconectada
89
Camada Conectada
90
Contectando a um Banco de Dados
91
Criando um Banco de Dados
91
Criando um Formulário de Inserção de Dados
93
Criando uma Listagem de Dados
96
Unidade 9 Depurando Aplicações no Visual Studio
99
Erros de Sintaxe (Syntax Errors)
99
Erros em tempo de execução (runtime)
99
Erros de Semântica
99
A Classe Debug
100
Habilitando a Depuração
100
Adicionando BreakPoints
101
Executando a Aplicação em Modo de Depuração
101
Execução Passo a Passo
101
Usando a Janela de Depuração
102
Exibindo a Janela Window
102
Depuração Remota
102
Tracing
102
Classe TraceContext
103
Habilitando o Tracing em uma Aplicação Web
104
Dados do Trace
104
Categorias do Trace
104
Unidade 10 Compilando, Testando e Distribuindo Aplicações .NET ..........................106
Criando um Projeto de Instalação
4
106
Frameworks de Desenvolvimento
Unidade 1
Definição de Framework
Um framework captura a funcionalidade comum a várias aplicações.
As aplicações devem ter algo razoavelmente grande em comum: pertencem a um mesmo
domínio de problema:
A definição que usamos foca quatro características principais de um framework (Orientado a
Objeto):
- Um framework provê uma solução para uma família de problemas semelhantes;
- Usando um conjunto de classes e interfaces que mostra como decompor a família de
problemas;
- E como objetos dessas classes colaboram para cumprir suas responsabilidades;
- O conjunto de classes deve ser flexível e extensível para permitir a construção de várias
aplicações com pouco esforço, especificando apenas as particularidades de cada aplicação;
Observe que um framework é uma aplicação quase completa, mas com pedaços faltando.
Ao receber um framework, seu trabalho consiste em prover os pedaços que são específicos
para sua aplicação.
5
Frameworks de Desenvolvimento
Na prática, então, um framework é um conjunto de facilidades definidas por um conjunto de
funcionalidades que interagem entre si e que é capaz de auxiliar no trabalho do desenvolvedor
em determinada área de atuação desse framework.
Esse conceito começou a ser utilizado para ajudar no processo de reutilização de softwares ou
pedaços desses softwares.
6
Frameworks de Desenvolvimento
Classificação dos Frameworks
Orientados a objetos / baseados em componentes
Os frameworks podem ser classificados em caixa-branca e caixa-preta [Fayad 97]. Os
frameworks caixa-branca baseiam-se nos mecanismos de herança e ligação dinâmica
(dynamic binding) presentes em orientação a objetos. Os recursos existentes em um
framework caixa-branca são reutilizados e estendidos a partir de: herança de classes do
framework e sobrecarga (overriding) de métodos "hook" pré-definidos. Métodos "hook" são
definidos em interfaces ou classes abstratas e devem necessariamente ser implementados por
uma aplicação. Um exemplo de método hook na linguagem Java é o actionPerformed(Action
Event e) pertencente à interface ActionListener do framework AWT (Abstract Window
Toolkit). Este método é chamado sempre que ocorre um evento ActionEvent correspondendo,
por exemplo, a um clique de botão. Os padrões de projeto (design patterns) utilizados são o
Command, o Observer e o Template Method [Gamma 94].
Frameworks caixa-preta são baseados em componentes de software. A extensão da
arquitetura é feita a partir de interfaces definidas para componentes. Os recursos existentes
são reutilizados e estendidos por meio de: definição de um componente adequado a uma
interface específica e integração de componentes em um framework que utiliza padrões de
projeto como o Strategy [Gamma 94].
Quanto ao contexto de utilização do framework há uma classificação proposta em [Fayad 97],
segundo a qual os frameworks são classificados em: "Framework de Infraestrutura de
Sistema", "Framework de Integração de Middleware" e "Framework de Aplicação".
Frameworks de infraestrutura de sistema tratam de questões de projeto como sistemas
operacionais, comunicação, interfaces gráficas e linguagens de programação. O framework
AWT seria classificado como um framework de infraestrutura de sistema.
Frameworks de integração de middleware são responsáveis por integrar aplicações
distribuídas e componentes em uma mesma arquitetura. Exemplos de frameworks de
middleware são os ORB (Object Request Broker) como o CORBA - Common ORB
Architecture, e o RMI - Remote Method Invocation.
Frameworks de aplicação tratam de questões de projeto de domínios de aplicação, como
telecomunicações, finanças, produção e educação. O framework que se está desenvolvendo
neste trabalho é um framework de aplicação.
7
Frameworks de Desenvolvimento
Profissionais Envolvidos
No processo de desenvolvimento de um framework deve-se produzir uma estrutura de classes
com a capacidade de adaptar-se a um conjunto de aplicações diferentes.
A principal característica buscada ao desenvolver um framework é a generalidade em relação
aos conceitos e funcionalidades do domínio tratado. Além disso, é fundamental que a
estrutura produzida seja flexível.
Pode-se afirmar que o desenvolvimento de um framework é diferente do desenvolvimento de
uma aplicação padrão. A distinção mais importante é que frameworks tem que cobrir todos os
conceitos relevantes do domínio enquanto uma aplicação se preocupa somente com os
conceitos mencionados nos requisitos da aplicação (Bosh, 1999).
A complexidade em se desenvolver um framework deve-se aos seguintes fatores (Silva,
2000):
• Necessidade de considerar os requisitos de um conjunto significativo de aplicações de modo
a torná-lo genérico.
• Necessidade de ciclos de evolução voltados a dotar a estrutura de classes do framework de
alterabilidade (capacidade de alterar suas funcionalidades sem conseqüências imprevistas
sobre o conjunto da estrutura) e extensibilidade (capacidade de ampliar a funcionalidade
presente sem conseqüências imprevistas sobre o conjunto da estrutura).
Em termos práticos, dotar um framework de generabilidade, alterabilidade e extensibilidade
requerem uma cuidadosa identificação das partes que devem ser flexíveis e a seleção de
soluções de projetos de modo a produzir uma arquitetura bem estruturada. Isto conduz a
observação de princípios de projeto orientados a objetos.
Em termos ideais, um framework deve abranger todos os conceitos gerais de um domínio de
aplicação, deixando apenas aspectos particulares para serem definidos nas aplicações
específicas (Silva, 2000).
No contexto de desenvolvimento, a existência do framework estará sempre relacionada à
existência de outros artefatos que são originadores do framework, originados a partir dele ou
que exercem influência na definição das estruturas de classes.
A figura mostra as várias fontes de informação que influem na definição da estrutura de um
framework: artefatos de software existentes, artefatos de software produzidos a partir do
framework e o conhecimento do desenvolvedor do framework (ou a equipe de
desenvolvimento). As setas representam o fluxo de informações que levam à produção da
estrutura de classes do framework.
Como um framework geralmente não consegue ser uma construção completa de um domínio,
mas sim uma descrição aproximada, é possível que a construção de aplicações sob um
framework leve à obtenção de novos conhecimentos do domínio tratado, que talvez não
estivessem disponíveis durante a construção do framework. Estas novas informações podem
levar à necessidade de alterar o framework, causando a sua evolução como ilustra a figura:
8
Frameworks de Desenvolvimento
Silva (2000) aborda que o desenvolvimento tradicional de aplicações envolve dois tipos de
indivíduos: o desenvolvedor de aplicação e o usuário de aplicação (ambos podem
corresponder a grupos de indivíduos com diferentes funções).
Desenvolvedores devem levantar os requisitos de uma aplicação, desenvolvê-la e entregá-la
aos usuários, que por sua vez interagem com a aplicação apenas através de sua interface.
O desenvolvimento de frameworks introduz outro indivíduo, a saber, o desenvolvedor de
framework . Nesse contexto, o papel do usuário de aplicação é o mesmo descrito acima. O
papel do desenvolvedor de aplicações difere do caso anterior pela inserção do framework no
processo de desenvolvimento de aplicações. Com isto, o desenvolvedor de aplicações é um
usuário de um framework que deve estender e adaptar a estrutura deste framework para a
produção de aplicações.
De forma genérica as atividades macros são descritas a seguir:
• Análise de domínio - processo de identificar e organizar o conhecimento sobre alguma
classe de problemas – o domínio do problema – para dar suporte à descrição e solução destes
(Arango e Prieto-Díaz, 1991).
• Projeto de framework – o objetivo ao realizar essa atividade é obter um framework flexível.
A atividade é árdua já que é difícil encontrar as abstrações corretas e identificar as partes
estáveis e variáveis do framework. Para aumentar a extensibilidade e flexibilidade do
framework padrões de projeto podem ser usados (Mattsson, 2000).
• Instanciação do framework – a instanciação difere dependendo do tipo de framework: caixa
branca (o usuário constrói classes a partir das classes disponíveis), caixa preta (o usuário tem
que escolher uma das classes fornecidas). Um framework pode ser instanciado uma ou mais
vezes dentro da mesma aplicação ou instanciado em diferentes aplicações (Mattsson,2000).
9
Frameworks de Desenvolvimento
Benefícios e Desafios Decorrentes da Adoção de um
Framework
Os principais benefícios da utilização de frameworks de aplicação orientada a objetos são a
modularidade, a reusabilidade, a extensibilidade e a inversão de controle que eles fornecem
aos desenvolvedores (Fayad e outros, 1999):
• Modularidade: frameworks promovem a modularidade por encapsular detalhes de
implementação volátil em interfaces estáveis. A modularidade ajuda a aumentar a qualidade
do software por localizar o impacto de mudanças no projeto e na implementação. Essa
localização reduz o esforço requerido para entender e manter o software existente.
• Reusabilidade: as interfaces estáveis fornecidas pelo framework promovem a reusabilidade
por definir um componente genérico que pode ser reaplicado para criar novas aplicações. A
reusabilidade influencia no conhecimento do domínio e prioriza os esforços de
desenvolvedores experientes a fim de evitar recriação e revalidação de soluções comuns a
requisitos recorrentes de aplicações e desafios de projeto de software.
• Extensibilidade: um framework promove a extensibilidade por fornecer métodos adaptáveis
(hook) explícitos (Pree, 1995). Permitindo as aplicações estenderem suas interfaces estáveis.
A extensibilidade é essencial para assegurar a especialização de novos serviços da aplicação e
novas características.
• Inversão de controle: a arquitetura do framework é caracterizada por uma inversão de
controle. Isso permite ao framework (ao invés da aplicação) determinar que conjunto de
métodos específicos da aplicação invocar em resposta a eventos externos.
Frameworks são considerados de grande importância para o desenvolvimento de aplicações
orientadas a objetos. Eles são considerados como uma das principais formas através da qual
sistemas orientados a objetos podem alcançar a reusabilidade.
10
Frameworks de Desenvolvimento
Unidade 2
Plataforma de Desenvolvimento Java
Plataforma Java é o nome dado ao ambiente computacional, ou plataforma, da empresa Sun
Microsystems (agora Oracle).
A plataforma permite desenvolver aplicativos utilizando qualquer uma das linguagens criadas
para a plataforma Java, sendo a linguagem padrão a que leva seu próprio nome: Linguagem
Java.
Uma grande vantagem da plataforma é a de não estar presa a um único sistema operacional ou
hardware, pois seus programas rodam através de uma máquina virtual que pode ser emulada
em qualquer sistema que suporte a linguagem Java.
O universo Java é um vasto conjunto de tecnologias, composto por três plataformas principais
que foram criadas para segmentos específicos de aplicações:
- Java SE (Java Platform, Standard Edition). É a base da plataforma; inclui o ambiente de
execução e as bibliotecas comuns.
- Java EE (Java Platform, Enterprise Edition). A edição voltada para o desenvolvimento de
aplicações corporativas e para internet.
- Java ME (Java Platform, Micro Edition). A edição para o desenvolvimento de aplicações
para dispositivos móveis e embarcados.
Além disso, podem-se destacar outras duas plataformas Java mais específicas:
- Java Card. Voltada para dispositivos embarcados com limitações de processamento e
armazenamento, como smart cards e o Java Ring.
- JavaFX. Plataforma para desenvolvimento de aplicações multimídia em desktop/web
(JavaFX Script) e dispositivos móveis (JavaFX Mobile).
Tecnologias Java
A plataforma Java é constituída de um grande número de tecnologias, cada uma provê uma
porção distinta de todo o ambiente de desenvolvimento e execução de software. Os usuários
finais, tipicamente, interagem com a máquina virtual Java (Java Virtual Machine, ou JVM) e
um conjunto padrão de bibliotecas de classe.
11
Frameworks de Desenvolvimento
Existe um grande número de maneiras de se utilizar uma aplicação Java, incluíndo applets
embutidas em páginas web, aplicativos de uso geral em desktops, aplicativos em aparelhos
celulares e em servidores de aplicações para Internet.
Os desenvolvedores de aplicações em Java utilizam um conjunto de ferramentas de
desenvolvimento, o JDK.
12
Frameworks de Desenvolvimento
Ambiente Eclipse
Eclipse é um IDE (ambiente de desenvolvimento integrado) de código aberto. Existe mais
ferramentas similares de código aberto disponíveis, mas o Eclipse IDE acabou tornando-se
uma ótima alternativa em virtude da quantidade de “plug-ins” disponíveis para dar suporte
aos diversos tipos de tecnologias que envolvem o desenvolvimento de softwares e sistemas.
Sua instalação é muito simples, podemos baixá-lo de http://www.eclipse.org em forma de
arquivo ZIP e só temos que descompactá-lo na pasta onde quisermos tê-lo instalado.
No site oficial, há opções para download que sugerem um desenvolvimento mais focado para
uma ou outra área. Isso se deve ao fato de que essas opções de download já trazem embutidos
alguns plug-ins necessários para facilitar o desenvolvimento dos projetos focados em uma ou
outra área.
Para executá-lo basta acionar o arquivo “Eclipse.exe”. Uma vez iniciado abrirá uma tela
inicial solicitando onde queremos que o Eclipse vá salvando os projetos que criarmos:
Obs.: Nessa apostila optamos por usar a versão “Eclipse IDE for Java EE Developers”, que já
traz o suporte para o desenvolvimento de aplicações web.
13
Frameworks de Desenvolvimento
Após escolher a área de trabalho (onde serão criados os diretórios - projetos – com seus
códigos), abrirá a primeira tela da IDE, dando as “boas vindas”.
Essa página inicial pode ser fechada. Atrás dela está efetivamente o ambiente de
desenvolvimento.
Caso seja de seu interesse, navegue pelas opções que aparecem nessa tela inicial para obter
maiores informações sobre a IDE.
14
Frameworks de Desenvolvimento
A primeira tela realmente significativa do Eclipse IDE possui uma série de informações
organizadas em painéis.
O “Package Explorer”, que está no lado esquerdo da tela, é a área onde estarão dispostas as
informações básicas do seu projeto – arquivos, diretórios, plugins, etc.
Os outros painéis não são tão importantes e alguns podem até ser fechados de acordo com a
preferência do desenvolvedor.
Todos os painéis podem ser abertos/fechados através do menu “Window”, em “Show View”.
Outro painel interessante é o “Outline”, que fornece informações sobre as classes, métodos e
outros recursos usados no seu projeto.
Para vermos esses painéis em pleno funcionamento, criaremos um exemplo básico “Olá
Mundo”, como segue:
- Vá ao menu “File” e escolha “New” e dentro dessa opção “Java Project”.
15
Frameworks de Desenvolvimento
- Defina um nome para seu projeto.
- O Eclipse já encontra automaticamente o JDK instalado no seu computador, bastando
apenas avançar para a próxima etapa.
- Nessa próxima tela (que é opcional) você pode configurar plugins e outros recursos. Se isso
não for do seu interesse, apenas confirme e finalize essa etapa.
16
Frameworks de Desenvolvimento
- Na etapa seguinte, você deverá criar um novo arquivo, vinculado ao projeto Java que você
acabou de criar.
- Dê um nome (Mundo) para esse novo arquivo (classe Java), escolha se você quer que essa
nova classe já venha com o código referente ao método “main” e construtores da superclasse
(caso esteja herdando de outra classe).
17
Frameworks de Desenvolvimento
Como todo bom software de desenvolvimento, o Eclipse traz um auxílio ao desenvolvedor
quando esse está escrevendo o código, que chamamos de “auto completar”.
Esse recurso permite que não seja necessário decorar todas as possibilidades de uso das
funções e métodos disponíveis da linguagem.
Após escrever o código, podemos visualizar o resultado no painel “Console” (nesse nosso
exemplo) ou em um navegador (caso seja um projeto web) ou outro local conforme a
configuração do projeto criado.
Unidade 3
Introdução ao Framework .NET
18
Frameworks de Desenvolvimento
Visão Geral

O Framework .NET é um framework de desenvolvimento criado pela Microsoft para a
criação de aplicações voltadas às plataformas Microsoft e outras. Entender o
funcionamento básico do Framework .NET é essencial pois todo o desenvolvimento de
aplicações utilizando esse framework se resume na utilização das classes que compõem o
mesmo.

Nesse capítulo veremos os componentes chaves do Framework .NET, assim como o papel
que cada um desempenha.
O que é o Framework .NET

O framework .NET possue dois componentes chaves:

O Common Language Runtime

A biblioteca de classes do .NET Framework

O Common Language Runtime (CLR) é o agente que gerencia as aplicações .NET em
tempo de execução. Ele fornece recursos chave como gerenciamento de memória, threads,
e gerenciamento de recursos. As aplicações que rodam sobre o CLR são conhecidas como
aplicações de código gerenciado (managed code), todas as demais são conhecidas como
aplicações de código não gerenciado (unmanaged code).

As bibliotecas do Framework .NET são um conjunto de classes reutilizáveis que fornecem
todas as funcionalidades que sua aplicação necessita. Essas bibliotecas permitem você
desenvolver tanto aplicações Windows como aplicações ASP.NET, ou mesmo aplicações
para dispositivos móveis Windows Mobile.

Common Language Runtime

A Common Language Runtime (CLR) é a máquina virtual do Framework .NET. Ela roda
em sistemas operacionais Windows (XP, Vista, Server, etc), e sua função é executar as
aplicações .NET compiladas em um formato bytecode denominado MSIL (Microsoft
Intermediate Language). Durante a execução, o CLR JIT (Just-in-time ) compila o
bytecode em linguagem de máquina nativo e executa a aplicação. Ou ainda, o código
MSIL pode já estar precompilado em código nativo, e nesse caso o JIT não é necessário, o
que aumenta o desempenho da aplicação.

O CLR oferece os seguinte serviços:

Gerenciamento de memória e garbage collection

Gerenciamento de thread
19
Frameworks de Desenvolvimento

Gerenciamento de exceções

Segurança

Os desenvolvedores .NET pode desenvolver aplicações usando qualquer linguagem .NET
como C#, VB.NET, ou C++. O bytecode MSIL permite a criação de aplicações .NET
portáveis para outras plataformas pelo fato de as mesmas só serem compiladas em
linguagem de máquina na hora de sua execução.

As aplicações .NET não são aplicações Win32 propriamente ditas (apesar de executarem
no ambiente Windows),razão pela qual o runtime Win32 não sabe como executá-las. O
Win32, ao identificar uma aplicação .NET, dispara o runtime .NET que, a partir desse
momento, assume o controle da aplicação no sentido mais amplo da palavra, porque,
dentre outras coisas, é ele quem vai cuidar do gerenciamento da memória via um
mecanismo de gerenciamento de memória chamado Garbage Collector (GC) ou coletor
de lixo, acerca do qual falaremos mais tarde. Esse gerenciamento da memória torna os
programas menos susceptíveis a erros. Mais ainda, o CLR como seu próprio nome o diz, é
compartilhado e, portanto, não temos um runtime para VB.NET, outro para C# etc. É o
mesmo para todo mundo.
Biblioteca de Classes do Framework .NET

A biblioteca de classes do Framework .NET permite a você desenvolver:

Aplicações console

Aplicações windows

Windows services

Aplicações ASP.NET

Web Services

Aplicações Windows Communication Foundation (WCF)

Aplicações Windows Presentation Foundation (WPF)

Aplicações Windows Workflow Foundation (WF)

As bibliotecas de classe são organizadas utilizando a hierarquia de namespaces. Por
exemplo, todas as classes que executam operação de IO estão localizadas no namespace
System.IO, e as classes que executam expressões regulares estão localizadas sob o
namespace System.Text.RegularExpressions.

As bibliotecas do Framework .NET estão divididas em duas partes:

Framework Class Library (FCL)
20
Frameworks de Desenvolvimento

Base Class Library (BCL)
A BCL é um subconjunto é um subconjunto de toda a biblioteca e contém um conjunto de
classes que fornecem funcionalidades básicas para suas aplicações. Algumas classes da BCL,
estão guardadas na DLL mscorlib.dll, System.dll, e System.core.dll. A BCL está disponível
em todas as linguagens suportadas pelo Framework .NET e encapsula todas funções comuns
como manipulação de arquivos, acesso a banco de dados, manipulação de graficos, e
documentos XML.
A FCL compõem toda a biblioteca e fornece as classes para desenvolver todos os diferentes
tipos de aplicações descritos acima.
Dificuldades encontradas no desenvolvimento de
sistemas para Windows antes do .NET
Algumas das dificuldades encontradas no desenvolvimento de sistemas Windows antes do
.NET são:
Complexidade associada a linguagens de programação de difícil sintaxe, e ainda as dores de
cabeça provocadas pelo gerenciamento da memória heap por parte do programador.
Pouca integração e reaproveitamento de código entre linguagens de programação diferentes;
ausência de implementação de mecanismo de herança entre linguagens diferentes.
Diversidade com pouca integração na resolução de problemas complexos, dificultando a
compreensão e o desenvolvimento dos sistemas.
Falta de portabilidade de código executável entre plataformas diferentes.
Vejamos a evolução histórica das ferramentas da Microsoft:
21
Frameworks de Desenvolvimento
Apenas para ilustrar um pouco a situação atual, vamos apresentar um pequeno estudo de caso.
Para simplificar o nosso problema, vamos considerar apenas as soluções Microsoft.
Imaginemos uma situação hipotética na qual é solicitada uma solução de home banking que
aceite requisições de um browser da Internet ou qualquer outro dispositivo como handheld,
telefone celular etc.; vejamos qual seria a resposta imediata dos recursos de software que eu
iria precisar:
1. Uma linguagem de programação para desenvolver as páginas dinâmicas: de cara, VBScript
ou JScript.
2. Precisamos desenvolver alguns objetos COM ou COM+ no servidor, mas por questões de
performance e poder de linguagem, escolhemos a linguagem C++, e claro, o compilador C++
do MS Visual Studio.
3. Vamos precisar de alguns componentes para executar no MS Queue server ou então no MS
transaction server, e escolhemos a linguagem Visual Basic porque temos pessoal que já fez
esse tipo de trabalho usando VB.
4. Bem, vamos falar o óbvio, mas precisamos também de Web designers com domínio de
HTML, Flash, ferramentas de editoração gráfica etc.
5. Ainda temos um problema para resolver, que é o fato de termos clientes heterogêneos que
não conseguem ler um formato padrão como uma Web page em HTML.
Ok, agora é o momento de correr atrás do pessoal com todas essas competências, tentar
gerenciar essa salada de tecnologias e linguagens de programação e, de quebra, fazer
funcionar tudo direitinho.
22
Frameworks de Desenvolvimento
E esta era uma situação bem comum no desenvolvimento de software até pouco tempo atrás:
ter de costurar uma série de linguagens + ferramentas + tecnologias + modelos de objetos +
linguagens de script vs. linguagens de programação completas + linguagens de marcação.
Usando o .NET podemos proporcionar uma solução alternativa, de menor complexidade de
implementação, mais integrada:
1. Uma linguagem de programação para desenvolver as páginas dinâmicas no servidor Web:
C# usando o Visual Studio.
2. Uma linguagem de programação para desenvolver objetos reusáveis, armazenados em uma
DLL no servidor: C# usando o Visual Studio.
3. Uma linguagem de marcação maleável o suficiente de sorte que permita mostrar o
conteúdo em diversos dispositivos: XML, gerado pelo C# ou pré-montado para alguns casos.
4. Todo o trabalho de formatação e transformação dos documentos XML gerados pela
solução de homebank será feito usando XSL para gerar a linguagem de marcação suportada
no lado cliente. Ah! Com que linguagem vamos fazer estas transformações? Com C# é claro!
Mas os nossos desenvolvedores têm um background muito forte em VB, de forma que nós
descartamos o C# como alternativa”. Não tem problema, tudo o que foi dito acima continua
válido, vamos mudar apenas a linguagem de C# para VB”. A plataforma .NET permite que
usemos a linguagem de programação da qual mais temos domínio e mesmo assim
continuamos a usufruir todo o seu potencial.
O exemplo anterior foi apenas para ilustrar o contexto atual de desenvolvimento de sistemas
complexos, onde temos de realmente fazer uma ginástica muito grande integrar todas as
partes constituintes da nossa solução. A boa notícia é que, como mostramos no exemplo, com
.NET esta situação está, digamos assim, findando esse problema, porque, como você pode ter
percebido, a sua solução caiu de três linguagens de programação para apenas uma, e o resto
das tecnologias que usamos (COM+, por exemplo) se integra perfeitamente com o restante da
solução.
Apenas falando no quesito da clareza e reutilização de código, algumas bibliotecas de classes,
como MFC (Microsoft Foundation Class), surgem nesse ínterim, mas têm como foco a
linguagem C/C++ e não podem ser usadas a partir do Power Builder, por exemplo, ou então
Delphi, que tem a sua própria biblioteca de componentes reutilizáveis. O que equivale a dizer
que essas bibliotecas não podem ser usadas a partir de qualquer linguagem de programação, o
que torna o reaproveitamento de código ainda mais difícil.
Mesmo tecnologias como COM e CORBA sempre apresentam os mesmos problemas de
dificuldade de aprendizado por causa de sua complexidade; ou então, mesmo quando
oferecem um modelo de objetos comum a ser usado por outras linguagens que não VB ou
C++,acabam esbarrando no fato de que cada linguagem de programação implementa os tipos
de uma forma diferente. E finalmente, quando achamos que conseguimos resolver os
problemas dos tipos, somos barrados porque não conseguimos programar relações de herança
entre linguagens diferentes.
23
Frameworks de Desenvolvimento
Paralelamente às iniciativas da Microsoft, em 1995 surge a linguagem JAVA (na verdade,
mais que uma linguagem, é uma plataforma de desenvolvimento) e, apesar de oferecer há
mais de dez anos a proposta de portabilidade de código executável, (leia-se, “compile uma
vez e rode em qualquer plataforma”), é “JAVA-cêntrica”, o que obriga o programador a
aprender uma nova linguagem se realmente quiser usufruir os recursos que ela oferece. Mas
você pode perguntar: “e .NET não nos obriga a aprender C#?” A resposta é não e saberemos
mais adiante como isso é feito.
A abordagem .NET
Citaremos a seguir algumas das características de .NET que visam a resolver os problemas
citados acima:
Independência de linguagem de programação: o que permite a implementação do mecanismo
de herança, controle de exceções e depuração entre linguagens de programação diferentes.
Reutilização de código legado: o que implica em reaproveitamento de código escrito usando
outras tecnologias como COM, COM+,ATL, DLLs e outras bibliotecas existentes.
Tempo de execução compartilhado: o “runtime” de .NET é compartilhado entre as diversas
linguagens que a suportam, o que quer dizer que não existe um runtime diferente para cada
linguagem que implementa .NET.
Sistemas auto-explicativos e controle de versões: cada peça de código .NET contém em si
mesma a informação necessária e suficiente de forma que o runtime não precise procurar no
registro do Windows mais informações sobre o programa que está sendo executado. O
runtime encontra essas informações no próprio sistema em questão e sabe qual a versão a ser
executada, sem acusar aqueles velhos conflitos de incompatibilidade ao registrar DLLs no
Windows.
Simplicidade na resolução de problemas complexos.
24
Frameworks de Desenvolvimento
Unidade 4
A Arquitetura .NET
Para melhor entendermos tudo o que temos dito até aqui, vamos falar um pouco da arquitetura
de .NET e os seus principais componentes.
CLR (Commom Language Runtime)
O CLR, ou tempo de execução compartilhado, é o ambiente de execução das aplicações
.NET. Como o leitor já deve ter atentado, as aplicações .NET não são aplicações Win32
propriamente ditas (apesar de executarem no ambiente Windows),razão pela qual o runtime
Win32 não sabe como executá-las. O Win32, ao identificar uma aplicação .NET, dispara o
runtime .NET que, a partir desse momento, assume o controle da aplicação no sentido mais
amplo da palavra, porque, dentre outras coisas, é ele quem vai cuidar do gerenciamento da
memória via um mecanismo de gerenciamento de memória chamado Garbage Collector (GC)
ou coletor de lixo, acerca do qual falaremos mais tarde. Esse gerenciamento da memória torna
os programas menos susceptíveis a erros. Mais ainda, o CLR como seu próprio nome o diz, é
compartilhado e, portanto, não temos um runtime para VB.NET, outro para C# etc. É o
mesmo para todo mundo.
CTS (Common Type System)
O CTS, ou Sistema Comum de Tipos, que também faz parte do CLR, define os tipos
suportados por .NET e as suas características. Cada linguagem que suporta .NET tem de,
necessariamente, suportar esses tipos. Apesar de que a especificação não demanda que todos
os tipos definidos no CTS sejam suportados pela linguagem, esses tipos podem ser um
subconjunto do CTS, ou ainda um superconjunto. No módulo dois falaremos mais a respeito
dos diferentes tipos especificados no CTS. Um conjunto de classes básicas que define todos
os tipos é implementado na CTS. Por exemplo: um tipo Enum deve derivar da classe System.
Enum e todas as linguagens devem implementar o tipo Enum dessa forma. Todo tipo deriva
da classe Object, porque em .NET tudo é um objeto e, portanto, todos os tipos devem ter
como raiz essa classe. E é dessa forma que os diversos tipos nas diversas linguagens são
implementados, obedecendo às regras definidas no CTS. Na .NET, e em C#
conseqüentemente, todos os tipos derivam de uma raiz comum: a classe Object, o que
equivale a dizer que todos os tipos são objetos, por definição.
25
Frameworks de Desenvolvimento
CLS (Common Language Specification)
O CLS, ou Especificação Comum da Linguagem, é um subconjunto do CTS, e define um
conjunto de regras que qualquer linguagem que implemente a .NET deve seguir a fim de que
o código gerado resultante da compilação de qualquer peça de software escrita na referida
linguagem seja perfeitamente entendido pelo runtime .NET. Seguir essas regras é um
imperativo porque, caso contrário, um dos grandes ganhos do .NET, que é a independência da
linguagem de programação e a sua interoperabilidade, fica comprometido. A grosso modo,
dizer que uma linguagem é compatível com o CLS significa dizer que mesmo quando esta é
sintaticamente diferente de qualquer outra que implemente .NET, semanticamente ela é igual,
porque na hora da compilação será gerado um código intermediário (e não código assembly
dependente da arquitetura do processador) equivalente para duas peças de código iguais,
porém escritas em linguagens diferentes. É importante entender esse conceito para não pensar
que o código desenvolvido em C# não pode interagir com código desenvolvido em VB ou
outras linguagens, porque mesmo estas sendo diferentes, todas são compatíveis com o CLS.
BCL (Base Classe Library)
Como era de se esperar, uma plataforma que promete facilitar o desenvolvimento de sistemas
precisa ter uma biblioteca de classes básica que alavanque a simplicidade e a rapidez no
desenvolvimento de sistemas. É este o objetivo da BCL (Biblioteca de Classes Base), oferecer
ao desenvolvedor uma biblioteca consistente de componentes de software reutilizáveis que
não apenas facilitem, mas também que acelerem o desenvolvimento de sistemas. Na BCL
encontramos classes que contemplam desde um novo sistema de janelas a bibliotecas de
entrada/saída, gráficos, sockets, gerenciamento da memória etc. Esta biblioteca de classes é
organizada hierarquicamente em uma estrutura conhecida como namespace. Ao desenvolver
um componente de software reusável, este precisa ser estruturado em um namespace para que
possa ser usado a partir de um outro programa externo. A seguir mostramos uma tabela com
alguns dos principais namespaces que fazem parte da BCL:
26
Frameworks de Desenvolvimento
27
Frameworks de Desenvolvimento
Unidade 5
Criando Aplicações com o
Visual Studio
O Visual Studio 2008 é um ambiente extremamente versátil e poderoso para o
desenvolvimento de aplicações .NET.
Técnicamente, é possível escrever aplicações .NET usando um editor de texto simples e um
compilador. Entretanto, o Visual Studio torna essa tarefa muito mais fácil e produtiva por
possuir um ambiente totalmente integrado e voltado à produtividade. Ele também
disponibiliza um depurador e tem suporte a IntelliSense.
Temos ainda a vantagem de trabalhar com todos os dados de forma integrada dentro de um
mesmo projeto, com suporte a versionamento e compilação distintas para ambientes de
produção e desenvolvimento, dando assim controle no gerenciamento do ciclo de vida da
aplicação.
Versões do Framework .NET e Visual Studio
A seguinte tabela mostra a relação entre a versão do Visual Studio e a versão do Framework
que contém o mesmo:
Versão do Framework
Versão Visual Studio
1.0
Visual Studio .NET 2002
1.1
Visual Studio .NET 2003
2.0
Visual Studio 2005
3.0
Disponibilizado com o Windows Vista
3.5
Visual Studio 2008

C om o Visual Studio 2008 é possível desenvolver para múltiplas versões do Framework
.NET: 2.0, 3.0 e 3.5. Permitindo a continuidade e migração de aplicações desenvolvidas em
28
Frameworks de Desenvolvimento
versões anteriores. Sem a necessidade de migrar toda a aplicação de uma só vez. Você pode
também, criar uma nova aplicação voltada a uma versão anterior do Framework, bastando
para isso indicar a versão desejada ao criar um novo projeto.
Conhecendo a IDE
Ao iniciar o Visual Studio 2008, temos acesso a sua interface:
Criando um Novo Projeto
Para criar um novo projeto selecione File > New > Project
Será exibida a caixa de diáligo New Project, que exibirá os templates de aplicações do Visual
Studio.
Um grande número de templates de projetos e itens de projeto já vem pré-instalados com o
Visual Studio. Esses templates aparecem como tipos de projetos dentro do menu File > New
Project. Você pode utilizar qualquer um desses templates para criar um projeto básico que
criará para você um conjunto mínimo de itens que sua aplicação necessita como classes,
29
Frameworks de Desenvolvimento
controles, e referências a bibliotecas do framework. Você pode usar os templates tanto para
criar aplicações desktop Windows Forms, como aplicações Web.
Os templates estão categorizados pela linguagem e pelo tipo de aplicação.
Um nome de projeto default é apresentado (WindowsFormsApplication1) no campo Name e
também:
Location: a pasta onde o projeto será salvo
Solution Name: o nome da solução, que por default tem o mesmo nome do projeto.
Entretanto, você pode modificar o nome da solução se você quiser que seja diferente.
Lembre-se que uma solução pode ter mais de um projeto.
Create directory for solution: se você desmarcar essa opção, uma solução não será criada para
o seu projeto.
Você também pode, no canto superior esquerdo, selecionar a versão do Framework para qual
você está desenvolvendo a aplicação:
30
Frameworks de Desenvolvimento
Selecione a linguagem Visual C#, nos templates “Windows Forms Application” e clique em
OK. Um novo projeto vazio será criado.
Componentes da IDE
Menu
A barra de menu contém os comandos do Visual Studio como o menu File, para criação de
novos projetos, abertura de projetos existentes, opção de salvar projetos formulários, etc.
31
Frameworks de Desenvolvimento
É possível de ser customizado em Tools > Customize.
Toolbar (Barra de Ferramentas)
Contém atalhos para muitos dos comandos mais utilizados. Assim como o menu também é
customizavel, bastando para isso clicar com o botão direito em qualquer toolbar existente e
abrirá uma lista de barras de ferramentas disponíveis, e ao final da lista, a opção de
customizar as mesmas.
Toolbox
A Toolbox contém todos os controles que você pode utilizar em suas aplicações. Você pode
arrastar os controles da toolbox para dentro do painel de design da sua aplicação.
Cada aba da toolbox contém controles agrupados para fins específicos. Você pode criar sua
própria tab para armazenar seus próprios controls. Para tanto basta clicar com o botão direito
na Toolbox e selecionar Add Tab.
32
Frameworks de Desenvolvimento
Para adicionar controles a Toolbox, clique com o botão direiton na aba em que você quer
adicioná-los e selecione a opção Choose Items. Abrirá a caixa de diálogo Choose Toolbox
Itens.
Você pode adicionar os seguintes tipos de controles à Toolbox:
Componentes do Framework .NET
33
Frameworks de Desenvolvimento
Componentes COM
Componentes WPF
Atividades de Workflow
Você também pode clicar no botão Browse e procurar pela DLL que contém os controles que
você quer adicionar a aplicação. Outra maneira de adicionar controles à Toolbox é arrastando
a DLL para dentro da Toolbox.
Você pode reposicionar a Toolbox arrastando e colocando ela dentro de um dos pontos de
ancoramento que aparecerão na tela:
Se você tiver problema de espaço em seu monitor, pode ainda, utilizar o botão Auto Hide para
ganhar algum espaço na tela.
34
Frameworks de Desenvolvimento
Solution Explorer
Na aba Solution Explorer, temos todos os arquivos e recursos utilizados em nosso projeto. A
solução pode conter um ou mais projetos. Os botões diponíveis na barra de ferramentas dessa
aba são:
Properties
Show All Files
Refresh
View Code
View Designer
View Class Diagram
Esses botões são sensíveis ao contexto, ou seja, alguns deles podem não estar visíveis
dependendo do ítem que estiver selecionado. Por exemplo, ao selecionar o nome do projeto,
os botões View Code e View Designer não são mostrados.
Para adicionar novos itens como Formulários ou Classes ao seu projeto, clique com o botão
direito sobre o nome do projeto no Solution Explorer, e selecione Add, e escolha o item a ser
adicionado:
35
Frameworks de Desenvolvimento
Você também pode adicionar projetos novos em File>Add New Project ou existentes em File
> Existing Project. Quando você tem mais de um projeto na aplicação, um dos projetos deve
ser marcado como StartUp Project. Que será o projeto que irá será depurado ao se pressionar
F5. Para alterar o projeto inicial, clique com o botão direito sobre o projeto que você deseja
que seja o inicial e selecione Set as Startup Project.
Properties
A janela de propriedades mostra as propriedades associadas ao diversos itens selecionados no
projeto (Windows Forms, controles, projetos, soluções etc).
A figura abaixo mostra a janela de propriedades de um objeto Windows Form. Por default as
propriedades são listadas por categoria, mas você pode optar por visualizá-las em ordem
36
Frameworks de Desenvolvimento
alfabética. Alternativamente, você pode escolher exibir os eventos relacionados ao objeto
selecionado.
Todos os valores default são exibidos em fonte normal, enquanto os valores que você alterar
são exibidos em negrito. Isso é muito útil para identificar rapidamente quais atributos você
mudou.
Você também pode usar a Properties window para exibir eventos. Para cada evento você pode
associar uma função já existente no projeto para gerencia-lo, ou então criar uma,
simplesmente dê um duplo clique na propriedade em que você quer criar o evento.
37
Frameworks de Desenvolvimento
Janela de Design
A janela de Design permite você visualizar e desenhar a interface da sua aplicação.
Dependendo do tipo de projeto que você estiver desenvolvendo, um tipo diferente de janela
aparecerá para você arrastar controles para ela.
Para alternar para o code-behind da aplicação, você pode tanto usar um duplo clique na
interface, ou usar um clique com o botão direito sobre o Solution Explorer e selecionar o item
View Code.
Janela de Código – Code View
Permite você visualizar e escrever a lógica da sua aplicação. Você pode alternar entre o modo
de design e o código clicando nas tabs.
Você pode organizar as tabs tanto horizontalmente como verticalmente, clicando com o botão
direito e selecionado New Horizontal Tab Group ou New Vertical Tab Group.
Criando um Hello World
Vamos criar nosso primeiro aplicativo Windows Form. Caso já se encontre no Visual Studio,
feche o projeto atual, se houver algum aberto, em File > Close Project. Vamos criar uma nova
aplicação Windows Form, vá em File > New Project, em Project Types, selecione Visual C#
> Windows, no campo Templates selecione Windows Forms Application, no campo name dê
o nome de HelloWorld e clique em Ok
38
Frameworks de Desenvolvimento
Na janela de Design, selecione o Form recém criado, e na janela Properties altere a
propriedade Text para Hello World.
Em seguida, altere a propriedade Name para frmHello.
Na Toolbox, abra a aba Common Controls e arraste um controle Button para dentro do Form.
Selecione o label recém criado, e na janela Properties altere a propriedade Text para “Clique
aqui” e a propriedade Name para btnOla.
Agora adicionaremos algumas funcionalidades ao Form. Na janela de Design, dê um duplo
clique sobre o botão recém criado. Abrirá a aba de edição do code-behind. Insira a seguinte
linha de comando:
MessageBox.Show("Hello world!");
O código completo deve ficar como o a seguir:
using
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
System.Linq;
System.Text;
System.Windows.Forms;
namespace HelloWorld
{
public partial class frmHello : Form
{
public frmHello()
{
InitializeComponent();
}
private void btnOla_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello world!");
}
}
}
Seu formulário deve ficar como o a seguir:
39
Frameworks de Desenvolvimento
Para executá-lo, vá em Debug > Start Debugging ou pressione F5 ou ainda, clique no botão
Start Debugging da barra de ferramentas do Visual Studio. A aplicação deve executar
corretamente, se não hover erros, abrindo o formulário, e ao clicar no botão aparecerá a
seguinte mensagem:
Criando uma Calculadora
Nesse exemplo vamos criar uma calculadora. Ela terá dois campos para a entrada dos
números a serem operados, um label para apresentação do resultado, e 5 cinco botões para
execução das operações de soma, subtração, multiplicação, adição e potênciação, e também
um botão para limpar os campos e resultado e um botão para fechar a calculadora.
Inicie o Visual Studio, se você já estiver como ele iniciado, salve o seu trabalho e feche o
projeto atual em File > Close Project.
40
Frameworks de Desenvolvimento
Crie um novo Projeto em File > New Project, em Project Types selecione Visual C# >
Windows, e em Templates selecione Windows Forms Application. No campo nome escreva
“Calculadora” e clique Ok.
Passo 1 – Ajustando o Formulário
Selecione o formulário recém criado, e altere as propriedades do mesmo na janela Properties
conforme a seguir:
Text: Calculadora
Name: frmCalculadora
Passo 2 – Posicionando os Controles
Arraste para o formulário apartir da Toolbox, aba Common Controls, os controles listados
abaixo alterando suas propriedades conforme a seguir:
Controle Label
Text: Primeiro Operador
Name: lblOperador1
Controle Textbox
Name: txtOperador1
Controle Label
Text: Segundo Operador
Name: lblOperador2
Controle Texbox:
Name: txtOperador2
Controle Label
Name: lblResultado
Text: 0
41
Frameworks de Desenvolvimento
Controle Button:
Text: +
Name: btnSomar
Controle Button:
Text: Name: btnSubtrair
Controle Button
Text: *
Name: btnMultiplicar
Controle Button
Text: /
Name: btnDividir
Controle Button
Text: Pot
Name: btnPotenciacao
Controle Button
Text: Limpar
Name: btnLimpar
Controle Button
Text: Sair
Name: btnSair
Ajuste a forma, disposição e tamanho de cada controle conforme for necessário e salve seu
projeto.
Seu formulário deve ficar parecido com o a seguir:
42
Frameworks de Desenvolvimento
Passo 3 – Adicionando Funcionalidades
Agora iremos adicionar algum código C# para adicionar as funcionalidades da nossa
calculadora.
Primeiro criaremos três variáveis auxiliares que receberão os valores dos Operadores 1 e 2, já
convertidos de String para Double, e uma variável Double para armazenar o resultado da
operação. E finalmente uma função que fará a conversão dos valores nos campos
txtOperador1 e txtOperador2 para double.
Clique em uma área sem controles do formulário com o botão direito, e selecione View Code.
Dentro do código C# do formulário, vamos inserir o código abaixo:
Primeiro vamos adicionar o código para cáculo da soma. Clique duas vezes sobre o botão “+”
e adicione o código abaixo ao evento Click do mesmo:
using
using
using
using
using
43
System;
System.Collections.Generic;
System.ComponentModel;
System.Data;
System.Drawing;
Frameworks de Desenvolvimento
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Calculadora
{
public partial class frmCalculadora : Form
{
double op1;
double op2;
double resultado;
public void converteEntradas() {
op1 = 0;
op2 = 0;
if (txtOperador1.Text != "")
{
Double.TryParse(txtOperador1.Text, out op1);
}
if (txtOperador2.Text != "")
{
Double.TryParse(txtOperador2.Text, out op2);
}
}
public frmCalculadora()
{
InitializeComponent();
}
}
}
Agora adicionaremos o código ao evento click do botão somar. Para isso, alterne para a aba
Form1.cs [Design] e clique duas vezes sobre o botão +, adicione o seguinte código:
private void btnSomar_Click(object sender, EventArgs
e)
{
converteEntradas();
resultado = op1 + op2;
lblResultado.Text = resultado.ToString();
}
Alterne novamente para o modo de Design e dê um duplo clique no botão “-“:
44
Frameworks de Desenvolvimento
private void btnSubtrair_Click(object sender,
EventArgs e)
{
converteEntradas();
resultado = op1 - op2;
lblResultado.Text = resultado.ToString();
}
Observe que esse procedimento é necessário, pois ao fazer isso o Visual Studio,
automaticamente liga a função sendo criada ao evento click do controle. O que pode ser
verificado na janela de propriedades, ao se clicar no botão Events
Da mesma forma para os demais botões com o código abaixo:
private void btnMultiplicar_Click(object sender,
EventArgs e)
{
converteEntradas();
resultado = op1 * op2;
lblResultado.Text = resultado.ToString();
}
private void btnDividir_Click(object sender, EventArgs
e)
{
converteEntradas();
resultado = op1 / op2;
lblResultado.Text = resultado.ToString();
}
private void btnPotenciacao_Click(object sender,
EventArgs e)
{
converteEntradas();
resultado = Math.Pow(op1, op2);
lblResultado.Text = resultado.ToString();
}
private void btnLimpar_Click(object sender, EventArgs
e)
{
txtOperador1.Text = "";
45
Frameworks de Desenvolvimento
txtOperador2.Text = "";
}
private void btnSair_Click(object sender, EventArgs e)
{
Application.Exit();
}
Salve o projeto e execute a aplicação pressionando F5.
46
Frameworks de Desenvolvimento
Unidade 6
Programação Orientada a Objetos
Introdução
A programação orientada a objetos (OOP) veio para ficar, sem dúvida nenhuma. Ela permite
que sistemas complexos sejam desenvolvidos com mais facilidade, tanto na implementação
inicial quanto na manutenção. O produto mais popular do Visual Studio até hoje tem sido o
Visual Basic. Porém, reclamava-se muito da ausência de um suporte mais completo a todos os
requisitos que caracterizavam uma linguagem de programação orientada a objetos (OOP).
Com a arquitetura .NET, a Microsoft parece ter resolvido atender ao clamor da comunidade
de desenvolvedores atacando em todos os flancos. Vários melhoramentos foram feitos no
Visual Basic, de forma que ele pode ser considerado agora como orientado a objetos; mas é
em C#, sem dúvida alguma, que se terá acesso a uma linguagem de programação que
implementa, de maneira simples e direta (sem as complicações do C++), todos os requisitos
de uma linguagem OOP em conjunto com uma forte tipagem de dados (um dos pontos fracos
do VB). Com isso, a programação torna-se mais sólida e muitos erros podem ser eliminados
ainda em tempo de compilação.
Por que OOP existe?
Antes de continuarmos, vamos voltar um pouco no tempo e entender de onde vem a idéia por
trás da programação orientada a objetos. O conceito predominante de programação antes de
OOP era a chamada programação procedural. Consistia basicamente em dividir a tarefa de
programação em pequenos blocos de código chamados de procedimentos (procedures, em
inglês), também conhecidos na época como sub-rotinas. Em todos os casos, o que se fazia,
basicamente, era escrever um trecho de código que manipulasse os valores de algumas
variáveis e desse algum tipo de retorno.
Exemplificando (código em português):
x = 0
Enquanto x < 10
47
Frameworks de Desenvolvimento
x = x + 1
Fim Enquanto
O exemplo acima é muito simples, mas bastante ilustrativo. Mostra que existem dados
(variáveis) e códigos que manipulam esses dados (estruturas de controle). Qual o
inconveniente disso? Supondo que x fosse um valor que tivesse de ser exibido na tela, seria
necessário acrescentar algum código que fizesse isso. Ou seja, x não era “capaz” de se “autoexibir” na tela. O código completo seria:
x = 0
Enquanto x < 10
x = x + 1
Fim Enquanto
PosicionarCursor 0,0
Imprimir x
Se fosse feita outra alteração no valor de x, você teria de executar novamente os comandos de
impressão para que o valor fosse atualizado na tela. O ponto a que queremos chegar é que
dados e códigos eram concebidos como elementos separados. Havia, inclusive, uma definição
que dizia: dados + código = programa.
Com a OOP, uma das idéias básicas era eliminar essa distância entre dados e código e fazer
com que ambos ficassem mais interligados. Ambos seriam capazes de interagir de forma mais
homogênea e autônoma. Primeiramente, expandiu-se a idéia de procedimento para a idéia de
classe. Uma classe permite que vários procedimentos e dados sejam armazenados dentro dela.
Os procedimentos passaram a chamar-se métodos e os dados passaram a chamar-se
propriedades. Mas não foi uma mera maquiagem e uma mudança de nome para a mesma
coisa. De fato, o conceito de classe mudou radicalmente a visão da programação. Uma classe
define como um objeto deve funcionar. Fazendo uma analogia clássica, é como o projeto de
uma casa: estabelece como as coisas têm de ser. A partir dessa planta, podem ser construídas
várias casas idênticas. Isso é chamado de instância em OOP. Quando dizemos instanciar uma
classe, significa colocar “no ar” um objeto baseado na descrição da classe. Vamos usar o
próprio Windows como referência. Uma das coisas mais comuns na interface do Windows é o
botão OK. Você provavelmente o verá na grande maioria das janelas que abrir. Observe que
ao clicar com o mouse sobre aquele botão, ele produz um efeito de forma que parece
realmente ter sido pressionado.
48
Frameworks de Desenvolvimento
Porém, não existem apenas botões OK. Você encontra botões dos mais variados tipos nas
mais diversas janelas. Na figura anterior, você nota que existem três botões idênticos, cada
qual com um título diferente. Internamente, a propriedade que define o rótulo do botão é
chamada de Text. Assim como existe Text, existem diversas outras propriedades. Uma delas é
Color, que define a cor do botão; outra define se o botão está pressionado ou não. Resumindo,
existem propriedades que definem diversos aspectos do botão. O grande detalhe é que, ao
alterar uma propriedade, obtém-se um efeito imediato.
Exemplificando em forma de código (fictício):
BotaoOk.Pressionado = Verdadeiro
Ou
BotaoOk.Pressionar
Ambos os códigos produzem um efeito imediato. Observe aqui duas coisas: primeiro, que a
propriedade ou método vêm sempre atrelados a um objeto. Segundo, que se parece muito com
a atribuição de uma variável no primeiro caso ou lembra meramente a execução de algum
procedimento no segundo código. Você poderia também ter os códigos inversos:
BotãoOk.Pressionado = Falso ou BotãoOk.Liberar
A grande mágica em OOP é que propriedades podem disparar a execução de métodos e
métodos podem alterar os valores de propriedades sem que você precise fazer nada para que
isso aconteça ao manipular o objeto. Isso faz com que os objetos tenham vida própria. Os
acadêmicos gostam de dizer que a OOP faz com que você programe “moldando” objetos
muito parecidos com a realidade. Bom, acho isso um exagero. Mas concordo que os
resultados que você vê são mais concretos, embora a programação por trás seja ainda mais
abstrata do que a procedural. Em relação a programação procedural e orientada a objetos, é
importante salientar que ambas não são inimigas e que a OOP não veio para aniquilar
ninguém. Pelo contrário, a OOP abraça e expande o conceito de programação procedural para
horizontes ainda mais amplos.
49
Frameworks de Desenvolvimento
Conceitos de encapsulamento, herança e
polimorfismo
OK, objetos têm propriedades que podem ser manipuladas e gerar resultados visíveis e
imediatos. Então vamos primeiramente entender a mecânica de funcionamento dos objetos.
Como já dissemos, ao alterar o valor de uma propriedade, códigos são executados de forma a
produzir um resultado visível. No exemplo do botão, qualquer modificação nas propriedades
Color ou Text produzirão efeitos imediatos. Porém, ao usar um objeto, você não “vê” o
código nem precisa conhecê-lo para criar um botão. Isto é chamado de encapsulamento.Os
códigos usados para alterar cores, títulos, forma e aspecto do botão ficam escondidos na
implementação da classe. Também era possível encapsular funcionalidade dentro da
programação procedural através da criação das chamadas bibliotecas de funções. Mas em
OOP, esse conceito vai um pouco além. Vamos entender por quê. Suponha que você não está
satisfeito e gostaria de criar botões redondos como os que você encontra no painel do Media
Player do Windows, por exemplo. Você precisa conhecer mais dois conceitos para poder
atingir esse resultado:
Herança e Polimorfismo.
Herança significa partir de algo já pronto e modificá-lo com o propósito de deixá-lo mais
adequado a determinada finalidade. Supondo que você tem uma classe botão com
propriedades básicas; você pode herdar aquelas características básicas e adicionar ainda mais
funcionalidade.O detalhe é que, ao “derivar” uma classe a partir de outra, você não precisa
conhecer o código da classe anterior. A sua nova classe não trará os códigos da classe pai.
Eles continuarão encapsulados lá e você poderá usá-los se quiser.O dado importante é que
você não precisa manipular os códigos da classe pai.
Como a intenção seria criar um botão com características de funcionamento diferentes, muitas
das propriedades anteriores passariam a funcionar de modo diferente. Observe à esquerda do
painel do Media Player que existem botões com os títulos de “Now Playing”, “Media Guide”,
“CD Audio” etc. É de se imaginar que exista uma propriedade Text para aquele tipo de botão
também. Ou seja, vamos assumir neste caso que existe a propriedade Text para todos os
botões do Windows. Mas por que alguns Texts são diferentes dos outros? Isso se chama
Polimorfismo. Ou seja, cada novo “descendente” de uma classe pode entender a propriedade
Text de uma forma diferente e aplicar seus próprios códigos de modo a redefinir seu
comportamento. Resumindo, Herança, Polimorfismo e Encapsulamento são os três
mecanismos básicos que uma linguagem deve comportar para ser considerada inteiramente
orientada a objetos.
50
Frameworks de Desenvolvimento
Orientação a eventos
Um tópico que não deve ser confundido com orientação a objetos é a orientação a eventos.
Uma linguagem de programação pode ser orientada a objetos sem ser orientada a eventos e
vice-versa. A união desses dois conceitos, entretanto, produz resultados muito mais
interessantes que os dois separadamente. Como o próprio nome sugere, uma linguagem
orientada a eventos é uma linguagem capaz de responder a determinados “acontecimentos”
dentro de um determinado ambiente. Os eventos podem ser muitos: o clique do mouse, uma
tecla pressionada, uma informação que chega pela placa de rede etc.
Em ambientes gráficos, isso tem uma importância essencial. O mouse, sem dúvida alguma,
foi o dispositivo que mais causou reviravolta no mundo da programação orientada a eventos.
No tempo das telas de texto, muito comuns no ambiente DOS, mainframes e versões mais
antigas de Unix, o principal dispositivo de entrada de dados era o teclado. Vejamos um
exemplo de programa com interface de texto:
Numa tela como essa, se o usuário quisesse pular de um campo para o outro, teria de usar o
teclado e necessariamente passar pelos campos dentro de uma determinada seqüência.Como
advento do mouse, passou a ser possível que o usuário se posicionasse em qualquer campo e
houve uma “quebra” de estratégia. Nos tempos da tela de texto, era o programador quem dava
as cartas e estabelecia a seqüência de operação de um programa. Hoje as coisas são diferentes,
o programa tem de estar preparado para responder a seqüência de eventos que o usuário achar
mais conveniente. Os sistemas operacionais também se tornaram multitarefa e várias ações
podem estar acontecendo ao mesmo tempo. Programar com orientação a objetos combinada
com orientação a eventos significa criar métodos que serão acionados quando determinadas
situações ocorrerem. Geralmente, esses métodos têm nomes como Obj_Click (Obj_Clicar),
Obj_KeyPress (Obj_PressionarTecla), assim facilitando sua identificação. Resumindo, o que
51
Frameworks de Desenvolvimento
fazemos é posicionar estrategicamente um punhado de códigos de programação em pontos do
programa que serão disparados em determinadas circunstâncias. A sensação que se tem é de
que a programação ficou mais “solta” e mais “descontrolada”, mas ocorre exatamente o
oposto.
Implementação prática dos conceitos
Vejamos agora, em termos de código, o que pode ser feito para criar classes em C#.
Conforme já foi visto no módulo 2, C# é uma linguagem inteiramente orientada a objetos, de
forma que tudo deve ser implementado dentro de classes. Não existem variáveis ou
procedimentos “soltos”. Apenas para relembrar, o esqueleto básico de uma classe deverá ter
mais ou menos o seguinte aspecto:
escopo class NomeClasse
{
// Propriedades
escopo tipo nome;
escopo tipo nome;
// Construtores
escopo NomeClasse
{
// Especificações
}
// Métodos
escopo tipo NomeMétodo
{
// Especificações
}
}
52
Frameworks de Desenvolvimento
Evidentemente, esse exemplo está muito simplificado, mas traz a idéia básica: você tem de
planejar quais serão as propriedades, os métodos, os construtores, destrutores e seus escopos e
tipos.
Exemplo:
public class Cadastro
{
// Propriedades
public string CPF;
public string NomeCliente;
// Construtores
public Cadastro( )
{
MessageBox.Show( "Eu sou o construtor 'default'!" );
}
public Cadastro( string fCPF, string fNome )
{
// Comandos de inicialização
this.CPF = fCPF;
this.NomeCliente = fNome;
MessageBox.Show( "Eu sou um construtor customizado
e recebi " + fCPF + " e " + fNome + " como parâmetros." );
}
// Métodos
public bool Gravou( )
53
Frameworks de Desenvolvimento
{
// Código para gravação
return true;
}
}
Em C#, a regra para definir um construtor é muito simples: basta criar um método cujo nome
seja idêntico ao da classe. Toda vez que uma instância da classe for criada, o construtor será
automaticamente disparado. Observe também que, no exemplo anterior, foram criados dois
construtores para a mesma classe. Isso, em OOP, é chamado de sobrecarga (overload) de
método. A palavra sobrecarga pode trazer a idéia de estresse ou excesso de trabalho, mas
nesse caso é um elemento que nos ajuda e muito! Quando um método é “sobrecarregado”, o
editor do Visual Studio dá uma indicação clara disso. Vamos tomar como exemplo o
MessageBox. Ao digitar MessageBox.Show, o editor mostra que existem doze alternativas
diferentes para o método Show:
O que diferencia um do outro é a combinação do número de parâmetros, seus nomes e tipos.
Isso é conhecido como assinatura do método. O compilador reconhecerá automaticamente
qual assinatura você está usando. No caso da nossa classe, podemos escolher qual construtor
será usado fornecendo a assinatura correta:
{
// Construtor 'default' é chamado
Cadastro Ficha1 = new Cadastro( );
// Construtor otimizado é chamado
Cadastro Ficha2 = new Cadastro( "123", "De Oliveira Quatro" );
}
54
Frameworks de Desenvolvimento
Um detalhe importante é que criamos duas instâncias da mesma classe e ambas jamais se
misturam. Outro detalhe é que o chamado construtor default, o qual não recebe nenhum
parâmetro, existe em todas as classes. Porém, se você criar um novo construtor customizado
com parâmetros, o construtor default é silenciosamente removido. No nosso exemplo, a
reescrita do construtor default se tornou obrigatória a partir do momento em que quisemos
usar a inicialização padrão de uma classe.
Vamos agora entender os escopos (visibilidade) de uma classe e de seus membros. Uma
propriedade (ou campo) ou método podem ser public, protected, private ou internal. Em C#,
eles são chamados de modificadores de acesso.
Veja os significados:
Quando você cria um objeto, muitos de seus elementos são visíveis e outros estão escondidos.
Fazendo uma comparação com o mundo real, quando usamos um carro, muitos de seus
elementos (ou propriedades) são facilmente acessíveis enquanto outros permanecem mais
bem-guardados. A velocidade, o nível do combustível, o câmbio, todos esses elementos são
visíveis externamente. Outros permanecem mais escondidos e são usados indiretamente: a
injeção eletrônica, as válvulas, os eixos de tração etc. Criar uma classe passa pela mesma
idéia. Na verdade, a criação de uma classe lida com dois alvos: existe uma parte pensada no
programador que usará a classe em seu sistema e outra pensada no usuário, que normalmente
verá apenas a “superfície” do objeto criado. Veremos o uso desses modificadores com
exemplos práticos e isso se tornará mais claro.
55
Frameworks de Desenvolvimento
Herança e Agregação
O trabalho de desenvolvimento de um único sistema pode resultar na criação e/ou utilização
de dezenas ou mesmo centenas de classes. Muitas dessas classes têm funcionalidades muito
distintas, mas outras se cruzam e se complementam. Por causa desses eventuais
“cruzamentos” de classes, é fundamentalmente necessário entender o modo como elas se
relacionam. Assim como na vida real com as mais diversas pessoas, duas classes podem se
relacionar baseada no “ser” e no “ter”. No caso do “ser”, diz-se que uma classe foi derivada
de outra e ambas têm uma relação de parentesco. Pelo outro lado, o “ter” especifica que uma
classe incorporou outra e ambas têm uma relação de
amizade.
Vamos tomar um exemplo da vida real: como se constrói um computador? Existem muitas
peças que formam uma máquina “completa” hoje em dia: processador, HD, monitor etc.
Observe que a Intel produz novos processadores a partir dos preexistentes. A partir disso,
nota-se uma linha genealógica: 8086, 286, 386, 486, Pentium, Pentium II e por aí vai. Cada
novo processador herda as características da geração anterior e agrega novos recursos e mais
potência. Então podemos dizer que temos uma classe onde cada novo processador é filho da
geração anterior. Conclusão: todos eles SÃO processadores.O relacionamento entre eles é
baseado em “ser”. Já um computador seria uma classe que agrega várias outras. Assim como
o exemplo do processador, HDs, Impressora e tantos outros periféricos também têm sua linha
evolutiva. A gente diz que um computador TEM memória, disco rígido etc. Ou seja, trata-se
de uma classe que incorpora diversas outras.O relacionamento do computador com os demais
elementos é do tipo “ter”. Fácil de entender na teoria, não é? Pois vejamos agora um pouco de
código:
class Processador
{
public double Megahertz;
public int AnoFabricacao;
}
class Intel386 : Processador
{
public Intel386( )
{
56
Frameworks de Desenvolvimento
Megahertz = 33.3;
AnoFabricacao = 1993;
}
}
class DiscoRigido
{
public int CapacidadeGB;
}
class Computador
{
Intel386 MeuProcessador;
DiscoRigido MeuHD;
public Computador( )
{
MeuHD.CapacidadeGB = 70;
}
}
No exemplo anterior, Intel386 é uma classe derivada a partir de Processador. DiscoRigido é
uma classe independente e Computador também. Na classe Computador, são agregadas as
classes DiscoRigido e Processador.
Criação de Propriedades
Vamos explorar agora um pouco mais as possibilidades de criação de propriedades. Os
exemplos anteriores foram muito simples. Uma propriedade, é preciso entender em primeiro
lugar, se parece muito com uma simples variável, mas é bem mais do que isso. Uma
57
Frameworks de Desenvolvimento
propriedade (também chamada de “atributo”, dependendo da forma como foi definida) é um
valor ao qual é associado um método.
Toda vez que for lido ou gravado o valor da propriedade, métodos podem entrar em ação.
Essas ações são definidas pelas palavras get e set.Na prática, pode- se dizer que uma
propriedade é composta de três elementos: um campo (local onde armazena-se o valor,
também chamado de atributo), um método de leitura (get) e um método de gravação (set).
Veja o exemplo da nossa classe Cadastro reescrita dentro dessas premissas:
class Cadastro2
{
protected string fCPF;
public string CPF
{
set
{
fCPF = value;
}
get
{
return fCPF;
}
}
}
Como dissemos anteriormente, temos três elementos. As variáveis fCPF e fNome são os campos
(fields) onde os valores são efetivamente armazenados. Observe que se trata de variáveis do
tipo protected, o que significa que só serão vistas pelas classes descendentes (lembre-se do
conceito de “ser”) e não serão manipuladas por outras classes (lembre-se do conceito de
“ter”). O set e o get, como você pode notar, servem para recuperar e gravar novos valores. A
palavra value é reservada no C# para receber o valor passado para a propriedade. Veja o
exemplo:
58
Frameworks de Desenvolvimento
InstanciaCadastro2.CPF = "123"; // Dispara o "set"
x = InstanciaCadastro2.CPF; // dispara o "get"
Para testar este código, sugerimos que você crie um projeto de teste bem simples,
apenas um formulário com um botão e escreva o código dentro do evento click desse botão.
Talvez você esteja se perguntando agora quem foi o maluco que resolveu complicar tanto a
programação. Mas o fato é que isso, acredite ou não, torna as coisas mais fáceis. Se você
tivesse de fazer com que um CPF fosse imediatamente validado ao ser atribuído, por
exemplo, ficaria muito mais fácil dessa forma. Ou seja, assim que o valor fosse informado, a
própria classe seria capaz de identificá-lo como válido ou não. No nosso estudo de caso,
desenvolveremos um exemplo
baseado nessa idéia.Uma das coisas que você pode fazer com uma propriedade e não
consegue com uma variável, por exemplo, é torná-la somente leitura ou somente gravação.
No caso de ter uma propriedade somente leitura, implemente apenas o método get. Se
implementar apenas o set, ela será apenas de escrita. No caso de não ser uma propriedade
“full” e apenas um campo (atributo), a forma seria:
public readonly string CampoSomenteLeitura
Métodos polimórficos
Vamos criar uma classe pensando em um método cuja implementação seria diferente na
classe pai e na classe filha. Ou seja, a implementação da classe filha será ligeiramente
diferente e melhorada em relação à versão pai. Nesse caso, toda vez que temos um método
que se modifica da classe pai para filho, esse método é chamado de virtual.
Em OOP, um método virtual se caracteriza pela capacidade do compilador de detectar
mudanças de acordo com o contexto da classe e viabilizar o polimorfismo. Em bom
português: é o método camaleão.
Vejamos este trecho de código para clarear um pouco mais:
class PrimeiraGeracao
59
Frameworks de Desenvolvimento
{
public virtual void Mensagem( string msg )
{
msg += " Primeira Geração ";
MessageBox.Show( msg );
}
}
class SegundaGeracao : PrimeiraGeracao
{
public override void Mensagem( string msg )
{
msg += " Segunda Geração ";
base.Mensagem( msg );
}
}
class TerceiraGeracao : SegundaGeracao
{
public override void Mensagem( string msg )
{
msg += " Terceira Geração ";
base.Mensagem( msg );
}
}
60
Frameworks de Desenvolvimento
Observe que na primeira geração, o método Mensagem é definido como virtual. Nas duas
gerações posteriores, ele é definido como override. Dentro de cada método override, observe a
presença da palavra-chave base. Ela é essencial para permitir que o polimorfismo aconteça.
Sua finalidade é acionar a codificação escrita na classe pai (o nível imediatamente anterior).
Apenas a Primeira Geração gera uma saída na tela. As outras classes apenas agregam mais
informação à
mensagem final. A terceira passa para segunda, que passa para a primeira, que efetivamente
imprime. Exemplo de utilização:
TerceiraGeracao teste = new TerceiraGeracao( );
teste.Mensagem( "Mecanismo de Herança: " );
A grande vantagem por trás disso tudo é que ao gerar uma nova versão do método, você não
precisa necessariamente conhecer o código da classe pai para fazer a nova implementação. Se
quiser, pode até mesmo descartar o que foi escrito anteriormente, basta não incluir a chamada
através da palavra- chave base. Existe também uma outra palavra-chave bastante importante
nesse processo de herança e polimorfismo. Essa palavra é this. A palavra this refere-se
sempre ao contexto atual. Na grande maioria dos casos, a palavra this pode ser omitida. Mas
quando existem coincidências entre nomes de variáveis ou parâmetros com campos ou
propriedades de uma classe, é conveniente usar this:
class ContextoPai
{
public string Nome; // this.Nome refere-se a este item
public ContextoPai( string Nome )
{
this.Nome = Nome;
}
}
Apenas para traçar um paralelo, o this em C# seria idêntico ao this em C++ e Java, idêntico ao
me em Visual Basic e idêntico ao self em Delphi.
61
Frameworks de Desenvolvimento
Um pouco de Concretismo e Abstracionismo
Bom, vamos dar alguns exemplos mais avançados de como criar métodos em classes. Uma
das coisas que mais massacram as almas dos programadores estabanados, quando eles se
deparam com OOP, é a necessidade primordial de planejamento. Muita gente simplesmente
senta na cadeira e começa a escrever, gerando um código que muitas vezes é complicado de
entender e dar manutenção. Para quem vai desenvolver classes, um mínimo de planejamento é
absolutamente indispensável no início. É como jogar xadrez. Se você não consegue pensar
nos lances seguintes, o xeque-mate (e neste caso o seu rei será o sacrificado) pode aparecer de
uma hora para outra. Baseado nessas premissas, não é exagero dizer que a OOP requer um
nível muito alto de abstração por parte do programador. Um nível de abstração tão alto que
ele pode simplesmente criar uma classe completamente vazia, oca, apenas para definir como
será o seu formato final ou de seus descendentes. O C# suporta abstração em classes através
de dois mecanismos: criação de classes e métodos abstratos e interfaces. Uma classe abstrata,
como o próprio nome sugere, não traz uma implementação concreta. Ela serve para dar forma
a um projeto de classe. Veja o código:
abstract class EntradaDeDados
{
public abstract string Conteudo( );
public abstract string Exibir( );
}
Normalmente, toda entrada de dados terá um conteúdo, o qual pode eventualmente ser
exibido. Isso é uma premissa. Criar uma classe abstrata significa definir premissas. Nada é
codificado concretamente na primeira geração da classe. As classes filhas (através de
override) é que definirão a funcionalidade de cada método ou propriedade. Se você tentar
instanciar uma classe abstrata, obterá um erro do compilador:
EntradaDeDados x = new EntradaDeDados( ); _ Cannot create an
instance of the
abstract class or interface 'EntradaDeDados'
62
Frameworks de Desenvolvimento
Na classe filha, você teria as implementações:
class EntradaDeOcorrencias : EntradaDeDados
{
public override string Conteudo( ) 81
{
// Implementação
return "";
}
public override string Exibir( )
{
// Implementação
return "";
}
}
Interfaces
O recurso de criação de interfaces segue mais ou menos o mesmo princípio dos métodos
abstratos: apenas define o formato de uma classe sem implementar seu código. Porém, há
uma característica que torna as interfaces bastante diferentes de simples classes abstratas: elas
fornecem subsídio para a criação de novas classes numa forma mais parecida com a
montagem de um quebra-cabeça. O C# não suporta herança múltipla. Isso significa que uma
classe filha só pode ter um única classe como pai. Interfaces permitem criar algo parecido
com herança múltipla em C++. Por definição, em OOP, Interfaces são coleções de métodos
abstratos relacionados semanticamente. Em bom português: peças de um quebra-cabeça que
podem ser encaixadas conforme a conveniência de quem estiver jogando... Observe que, para
efeito de padronização, é comum identificar os nomes das interfaces com I maiúsculo no
início. Vamos a um exemplo:
public interface ICodigoBarras
63
Frameworks de Desenvolvimento
{
void LeituraPadrao3of9( ); // Implicitamente abstrato
void LeituraPadraoEAN13( );
void MetodoIdentico( );
}
public interface IControleArmazenamento
{
void Localizador( );
void Categorizacao( );
void MetodoIdentico( );
}
public class Produto : ICodigoBarras, IControleArmazenamento
{
// Aqui viriam as implementações
public void LeituraPadrao3of9( )
{
// Implementação
}
public void LeituraPadraoEAN13( )
{
// Implementação
}
public void Localizador( )
{
// Implementação
}
64
Frameworks de Desenvolvimento
public void Categorizacao( )
{
// Implementação
}
// No caso de nomes coincidentes, implemente apenas uma vez
public void MetodoIdentico( )
{
// Implementação
}
}
A definição da classe produto seria resultante da agregação de métodos definidos em duas
interfaces diferentes. Você também pode agregar outros detalhes pertinentes à classe produto.
Também pode criar novas classes baseadas em uma classe pai combinada com várias
interfaces:
public class Produto : Cadastro, ICodigoBarras,
IcontroleArmazenamento
Selando as classes
Para selar este assunto de criação de classes com chave de ouro, a linguagem C# permite criar
classes “seladas”. Por definição, classes seladas não permitem nenhum tipo de herança ou
derivação. Simplesmente são classes que devem ser entendidas como terminadas. Exemplo de
código de classe selada:,
sealed class FimDePapo
{
public string UltimaPalavra;
}
65
Frameworks de Desenvolvimento
class AindaQueroMaisPapo : FimDePapo
{
// Erro de compilação:
// cannot inherit from sealed class 'FimDePapo'
}
Ferramentas de apoio
Se você se empolgar com a criação de objetos e de repente se vir às voltas com mil e uma
classes, existem algumas ferramentas no editor do Visual Studio que tornarão a sua vida mais
fácil. Para ter uma visão global dos objetos criados dentro da sua aplicação, clique com o
botão direito do mouse dentro do editor e selecione “Synchronize Class View”. Você verá no
canto superior direito da sua tela (essa posição pode variar) uma janela com todas as
definições de classes, mais ou menos com o seguinte formato:
66
Frameworks de Desenvolvimento
Ao clicar duas vezes sobre um método, propriedade ou classe, o editor posicionará o cursor
dentro do código correspondente. Uma vez dentro do código, se não estiver interessado em
visualizar o código de classes que considera que já esteja corretamente implementados, você
pode usar os sinais de + e – que ficam no canto da tela e “contrair” ou “expandir” os códigos
das classes. Veja o exemplo com a classe Processador contraída, exibida na Figura 3.7.
Tempo de vida dos objetos
Até agora, temos falado de criar objetos, mas também é igualmente importante saber como e
quando destruí-los. Vimos que para criar uma nova instância de uma classe basta usar a
palavra new:
x = new ClasseExemplo( )
O próprio runtime de .NET vai se encarregar de destruir o objeto quando ele não for mais
necessário. A pergunta é: como ele sabe que um objeto não é mais necessário? Resposta
simples e incompleta: o runtime libera a memória alocada pelo objeto quando não existe mais
nenhuma referência ligada ao objeto dentro do contexto corrente. Exemplo:
public static int Main( )
{
QualquerClasse x = new QualquerClasse( );
...
Return 0;
}
// se x é a única referência para "QualquerClasse"
// ela pode ser destruída quando termina seu escopo
67
Frameworks de Desenvolvimento
Existem diversos aspectos referentes a Garbage Collection (coleta de lixo) que estão fora do
escopo deste curso. Vamos nos deter em mostrar como programar a destruição de um objeto.
É muito comum necessitarmos que determinados processos ocorram quando um objeto é
finalizado. Os exemplos são muitos: liberação de recursos alocados como impressora ou porta
serial, fechamento de arquivos etc. Assim como temos em C# os construtores, também temos
os destrutores. Lembre-se de que a regra para a criação de um construtor é muito simples:
basta criar um método com o mesmo nome da classe. No caso do destrutor, basta também
criar um método com o mesmo nome da classe, mas precedido por um til (~). Exemplo:
class Teste
{
~Teste( )
{
// Aqui você escreve o código de liberação de recursos
// Base.Finalize( ) é chamado automaticamente em C#
68
Frameworks de Desenvolvimento
}
}
Evidentemente, se você achar conveniente que a liberação de recursos seja feita em algum
momento que não necessariamente seja o da destruição do objeto, você é inteiramente livre
para criar algum método que faça isso.
Tratamento de exceções
O tradicional termo tratamento de erros é agora chamado de tratamento de exceções. E
veremos que faz mais sentido. Em C#, o tratamento de exceções é feito de maneira muito
elegante e simples.O C# adota um estilo relativamente comum em outras linguagens, que é o
de tratar erros como objetos que encapsulam todas as informações que necessitamos para
resolvê-lo. Essa idéia é válida para todo o ambiente .NET e foi batizada como SEH
(Structured Exception Handling). A idéia básica é mais ou menos a seguinte: todo objeto que
representa uma exceção é derivado de System.Exception. Essa classe possui os seguintes
membros:
Exceções podem ser disparadas pelos mais diversos elementos. Podem ser disparadas a partir
de erros do sistema operacional, de erros de dispositivos, de inconsistências de dados.
Também podemos criar nossas próprias exceções. Vamos observar um exemplo de como
disparar uma exceção e como tratá-la com a nossa classe de Cadastramento e validação do
CPF:
69
Frameworks de Desenvolvimento
public class Cadastro
{
// Propriedades
public string CPF;
public string NomeCliente;
public Cadastro( string fCPF, string fNome )
{
// Inicialização
CPF = fCPF;
NomeCliente = fNome;
if ( CPF.Length != 11 )
{
// THROW é a palavra chave para gerar a exceção
throw new Exception( "CPF Inválido" );
}
}
}
Colocamos uma validação no construtor, de forma que se forem passados menos de 11
caracteres, o CPF é automaticamente considerado incorreto. Ao instanciar essa classe com um
parâmetro inválido, a classe irá disparar a exceção e o resultado na tela deverá ser uma tela
similar a esta:
70
Frameworks de Desenvolvimento
Observe que um dos detalhes importantes está na sentença “unhandled exception”.
Traduzindo: exceção não-tratada. A exceção foi disparada pela palavra chave throw e é
preciso que haja um bloco de código preparado para manipular a classe de erro retornada.O
formato de tratamento de uma exceção é o seguinte:
try
{
// Código sujeito a exceções
}
catch( TipoExcecao1 e )
{
// Tratamento para exceção tipo 1
}
catch( TipoExcecao2 e )
{
// Tratamento para exceção tipo 2
}
catch
{
// Tratamento para qualquer tipo de exceção
}
71
Frameworks de Desenvolvimento
finally
{
// Trecho que deve sempre ser executado, havendo ou não
exceção
}
A estrutura try..catch requer que exista pelo menos um bloco catch vazio. Os blocos de finally e
catch(exception) são opcionais. Nossa classe Cadastro deveria ser instanciada da seguinte forma:
try
{
Cadastro teste = new Cadastro( "123", "De Oliveira Quatro" );
}
catch
{
MessageBox.Show( "Impossível instanciar o objeto Cadastro" );
}
Como você deve ter observado no exemplo, entretanto, não existe uma pista clara de qual foi
o motivo que realmente fez a instanciação do objeto. Para termos um controle mais efetivo,
poderíamos usar o catch com uma exceção customizada. Vamos criar uma exceção que será
usada especificamente para o caso de encontrar um CPF inválido e colocar isso dentro de um
contexto com mais outras possibilidades de erro. O esboço do código ficaria desta forma:
// Criação das classes
public class eCPFInvalido : Exception{ }
public class Cadastro
{
// Campos
public string CPF;
72
Frameworks de Desenvolvimento
public string NomeCliente;
public Cadastro( string fCPF, string fNome )
{
// Inicialização
NomeCliente = fNome;
if ( CPF.Length != 11 )
{
throw new eCPFInvalido( );
}
else
{
CPF = fCPF;
}
}
}
// Código que irá testar o tratamento de exceções
// Insira-o dentro do evento click de um botão,
// por exemplo
try
{
int x;
int z = 0;
Cadastro teste = new Cadastro( "123", "De Oliveira Quatro" );
x = 3 / z; // Teste pôr esta linha antes da anterior
}
catch( eCPFInvalido Erro ) // Experimente inverter a ordem dos
catches
73
Frameworks de Desenvolvimento
{
MessageBox.Show( "CPF Inválido" );
}
catch( Exception Erro )
{
MessageBox.Show( "Impossível instanciar o objeto Cadastro: " +
Erro.Message );
}
finally
{
MessageBox.Show( "Sempre executado, haja erro ou não." );
}
Observe uma série de detalhes pertinentes ao exemplo anterior:
O catch( Exception Erro) é o trecho que captura toda e qualquer exceção. Ele é praticamente
igual a um catch vazio conforme demonstrado antes, por uma razão muito simples: Exception é
pai de todas as exceções. Qualquer exceção sempre se encaixará em Exception por causa
disso. A razão pela qual usamos Exception em vez de um catch vazio foi a intenção de exibir a
mensagem enviada pelo sistema na ocorrência do erro.
O bloco finally é executado sempre, haja erro ou não. Neste caso, ele é executado DEPOIS do
bloco catch que capturar a exceção. Se você tem o costume de programar em Delphi, vai notar
que essa ordem é invertida em C#.
Qualquer erro ocorrido dentro um bloco try desvia o fluxo de execução para o catch
correspondente e NÃO retorna o fluxo de execução para o ponto que originou o erro ou a
linha seguinte. Em outras palavras, não existe nada semelhante ao Resume, tão popular no
VB, por exemplo.
A ordem dos fatores altera (e muito) os resultados. Se você tentar, por exemplo, as inversões
sugeridas pelos comentários no exemplo anterior, vai perceber que, no caso de alterar a ordem
dos catches, você receberá um erro do compilador: “A previous catch clause already catches
all exceptions of this or a super type (‘System.Exception’)” (Uma cláusula catch anterior já
captura todas as exceções deste tipo ou de um tipo superior “System.Exception”). No caso de
inverter as linhas de código, você vai fazer com que diferentes catches sejam executados.
74
Frameworks de Desenvolvimento
Apenas um– e somente um – bloco catch é executado para cada tratamento de exceção (try).
No nosso estudo de caso, também daremos seguimento a este assunto e desenvolveremos
controles de exceções mais sofisticados.
Conversão de tipos (Typecasting)
Quase todas as linguagens de programação possuem recursos para compatibilização de dados.
No caso da OOP, isso é um tópico que requer um pouco mais de cuidados do que uma
simples conversão de números em strings e vice-versa. Em muitos casos, um objeto pode ser
passado como parâmetro e um método pode estar habilitado a lidar com classes bastante
diferentes. Primeiro vamos examinar em um sistema de herança linear, baseado no conceito
de “ser”:
Eis aqui agora um diagrama demonstrando o conceito de “ter”:
75
Frameworks de Desenvolvimento
A pergunta-chave para explicar o tópico de type cast de objetos seria: como posso criar um
método que seja capaz de receber um objeto como parâmetro, não importa qual seja e,
sabendo que alguns desses objetos têm o método “gravar” e outros não, por exemplo, como
fazer para que meu código seja inteligente o suficiente para saber com qual objeto está
lidando e realizar a ação da maneira mais adequada? Ok, vamos por partes. Seja qual for o
caso, teremos de fazer uso de dois operadores de typecast: is e as.O operador is permite que
você verifique se o objeto é de um tipo específico e retorna verdadeiro ou falso, de acordo
com o resultado do teste. Exemplo:
if ( p is Intel286 )
{
// instruções
}
Já o operador as permite usar uma classe como se ela fosse outra. Evidentemente, esse tipo de
“personalidade trocada” pode dar confusão e deve ser usada com cuidado. Como regra geral,
podemos dizer que quanto mais próximo for o parentesco entre duas classes, maiores as
chances de ter um typecast correto. Quanto mais distante, maior a possibilidade de erros no
seu typecast. Mas lembre- se que parentes próximos também podem brigar, portanto é mais
do que conveniente planejar bem um typecast! Veja um exemplo:
(p as Intel286).ModoProtegido = true;
Nesse caso, estamos fazendo um typecast no objeto p para usá-lo como um processador
Intel286. Se o typecast falhar, um objeto com valor nulo será retornado e uma exceção será
gerada. Vamos analisar os dois casos ilustrados no início deste tópico. O primeiro caso seria
mais simples, por se tratar de herança linear pura e simples. Bastaria criar um método que
recebesse como parâmetro a classe mais superior, no caso, a classe Processador. Veja o
código:
class Processador
{
public double Megahertz;
76
Frameworks de Desenvolvimento
public int AnoFabricacao;
}
class Intel8086 : Processador
{
public Intel8086( )
{
Megahertz = 4.77;
AnoFabricacao = 1981;
}
}
class Intel286 : Intel8086
{
public bool ModoProtegido = false;
public Intel286( )
{
Megahertz = 20.0;
AnoFabricacao = 1984;
}
}
Observe que a partir da geração do 286, foi adicionado um novo campo indicando que o
processador dispõe de um recurso chamado “Modo Protegido” e cujo valor padrão é false.
Caso queiramos ativar o modo protegido de um processador através de uma classe externa,
poderíamos escrever uma classe com o seguinte formato:
class VerificarModoProtegido
{
public void AtivarModoProtegido( Processador p )
77
Frameworks de Desenvolvimento
{
if ( p is Intel286 )
{
// observe o type cast nesta linha:
(p as Intel286).ModoProtegido = true;
MessageBox.Show( "Modo protegido foi ativado" );
}
if ( p is Intel8086 )
{
MessageBox.Show( "Modo protegido não disponível" );
}
}
}
Vamos agora escrever um código que acionaria tudo de vez. Observe que esse código possui
um “truque”:
Intel8086 p8086 = new Intel8086( );
Intel386 p386 = new Intel386( );
VerificarModoProtegido Modo = new VerificarModoProtegido( );
// É fácil prever a saída desta linha:
Modo.AtivarModoProtegido( p8086 );
// Mas o que você acha que vai acontecer nesta aqui?
Modo.AtivarModoProtegido( p386 );
A primeira linha, obviamente, responderá que o processador não possui modo protegido.
Porém, já que nossa classe prevê apenas processadores 8086 e 286, como ela irá se comportar
recebendo como parâmetro um 386? Resposta: ela acionará ambos os “ifs”. Ou seja, ela
78
Frameworks de Desenvolvimento
ativará o modo protegido, informará que o mesmo foi ativado e logo em seguida dirá que o
processador não possui modo protegido!
Nossa classe anterior, portanto, teria de ser reescrita e ficaria mais consistente
desta forma:
class VerificarModoProtegido
{
public void AtivarModoProtegido( Processador p )
{
if ( p is Intel286 )
{
// observe o type cast nesta linha:
(p as Intel286).ModoProtegido = true;
MessageBox.Show( "Modo protegido foi desativado" );
}
else if ( p is Intel8086 )
{
MessageBox.Show( "Modo protegido não disponível" );
}
}
}
Você conseguiu enxergar a diferença? Todo e qualquer detalhe em programação pode ser
crucial! É muito fácil deixar “bugs” no código... Agora que sabemos como tratar objetos em
herança linear, como proceder em relação a objetos que não necessariamente têm
“parentesco” entre si? Eis aqui o grande detalhe: todos os objetos têm parentesco, sim. Todos
eles são filhos de System.Object. Não precisa fazer exame de DNA, pode acreditar nisso! Veja
este exemplo de código:
79
Frameworks de Desenvolvimento
public void QualquerObjeto( System.Object o )
{
// Diferentes comparações e typecasts podem ser usados
}
Resumindo, o mesmo raciocínio aplicado a herança linear também se aplica a objetos não
lineares; afinal, todos os objetos são descendentes de um mesmo ramo. Basta que o parâmetro
que receberá os objetos seja definido como System.Object.
Resumo
Neste módulo você foi exposto a uma série de conceitos e técnicas. Dominar a Programação
Orientada a Objetos dentro dos atuais ambientes de desenvolvimento é absolutamente
essencial. Você aprendeu todos os conceitos essenciais de OOP (Polimorfismo,
Encapsulamento, Herança) e viu de que forma eles são implementados e como se aplicam em
C#. Aprendeu também a diferença entre orientação a eventos e orientação a objetos. Vimos
também como construir classes, métodos e propriedades. Outras informações importantes
como tratamento de exceções, interfaces, e type casting completaram o repertório básico de
informações sobre OOP de que você precisa para programar de maneira consistente nessa
tecnologia.
80
Frameworks de Desenvolvimento
Unidade 7
Segurança em Aplicações .NET
O Common Language Runtime e o Framework .NET fornecem muitas classes e serviços que
permitem aos programadores escrever código para aplicações seguras. Esses componentes
permitem aos administradores customizar o acesso que a aplicação terá a recursos
protegidos. O framework também fornece classes e serviços que facilitam o uso de
criptografia e segurança por definição de papéis de usuário.
Utilização de Strong Names
Strong Name é uma tecnologia baseada em criptografia introduzida pela plataforma .NET e
traz consigo muitas possibilidades para as aplicações .NET. Uma delas é o aumento da
segurança no desenvolvimento de aplicações.
Imagine que você precise criar um conjunto de componentes que gerenciam a área de
recursos humanos de uma determinada empresa. Entre esses componentes, vamos ter um
chamado Salario, que dado o nome do funcionário, valor base do salário e a quantidade de
horas extras que o funcionário realizou no mês, retorná o valor líquido que a empresa deverá
pagar a ele.
Para ilustrar isso, temos um projeto do tipo Class Library, chamado de RegrasDeNegocio.
Dentro deste projeto, criamos uma classe chamada Salario, que possuirá apenas o método
chamado de Calcular, que receberá os parâmetros mencionados acima. Traduzindo tudo isso
em código, teremos algo como:
public class Salario
{
public decimal Calcular(string nomeDoFuncionario, decimal
valorBase, decimal horasExtras)
{
return valorBase + horasExtras;
}
}
Note que não há nenhuma complexidade envolvida para não desviarmos o foco. Como
sabemos, este projeto dará origem à uma DLL, que poderá ser utilizada por várias aplicações
que rodam dentro da empresa. Como já era de se esperar, vamos referenciá-la em um projeto
chamado AplicacaoDeRH, que utilizará esse componente recém criado para calcular os
salários de seus respectivos funcionários. Com isso, o código de consumo na aplicação final
81
Frameworks de Desenvolvimento
é algo parecido com isso:
Console.WriteLine(new Salario().Calcular("Julio Cesar",
1000.00M, 250.00M));
Dá mesma forma que antes, vamos manter a simplicidade aqui. Depois deste software (EXE
+ DLL) instalado na máquina do responsável pelo RH da empresa, eu chego até o diretório
físico onde ele está instalado. Copio esses dois arquivos para minha máquina para começar a
analisar como esse componente e aplicação foram desenvolvidos. Como sabemos, dentro de
qualquer assembly .NET, temos apenas código IL, que é um código ainda decompilável.
Podemos utilizar o Reflector para isso e, consequentemente, visualizar tudo o que eles
possuem (classes, métodos, parâmetros, etc.).
A partir de agora, vamos explorar a vulnerabilidade. Como eu conheço toda a estrutura que o
componente (DLL) tem, nada impede de eu criar um projeto no Visual Studio .NET, com o
mesmo nome, com os mesmos tipos e os mesmos parâmetros. Com isso, eu vou manipular o
corpo do método Calcular, verificando se o funcionário que está sendo calculado o salário
sou eu, e se for, multiplico a quantidade de horas extras por 2, para que eu possa ganhar um
valor maior do que realmente deveria.
public class Salario
{
public decimal Calcular(string nomeDoFuncionario, decimal
valorBase, decimal horasExtras)
{
if (nomeDoFuncionario == "Julio Cesar")
horasExtras *= 2;
return valorBase + horasExtras;
}
}
Depois de compilado, isso dará origem à uma - nova - DLL com o mesmo nome. De alguma
forma, eu chego até o computador do responsável pelo RH da empresa, e substituo
fisicamente a DLL anterior por essa DLL que acabamos de desenvolver, e que viola a regra
de negócio, pois manipula o resultado para beneficiar um funcionário específico. Com isso,
quando o responsável pelo RH for calcular o meu salário, ele me pagará duas vezes o valor
das minhas horas extras. Se ele confia cegamente no software que dá o resultado, estou
sendo beneficiado, a empresa prejudicada e dificilmente alguém encontrará o problema.
A importância do StrongName
Todo e qualquer assembly possui algumas características que ajudam ao runtime determinar
a sua identidade. A identidade de qualquer assembly .NET é composta por quatro
82
Frameworks de Desenvolvimento
informações, a saber: nome, versão, cultura e uma chave pública. O nome nada mais é que o
nome do assembly, desconsiderando a sua extensão. A versão é o número em que o projeto
se encontra, e que por padrão é 1.0. Já a cultura determina se o assembly é sensitivo à
alguma cultura e, finalmente, a chave pública, qual falaremos mais adiante.
Podemos utilizar várias ferramentas para conseguir visualizar essas informações. No nosso
caso, se abrirmos dentro do Reflector o componente que criamos inicialmente, aquele que
possui o código legal, poderemos comprovar essas características que ajudam a identificar o
assembly:
RegrasDeNegocio, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null
Quando criamos a assembly ilegal, com o código que multiplica a quantidade de horas extras
por dois, poderemos notar que o resultado será idêntico, ou seja, não há nada que diferencie a
identidade dos dois assemblies. Sendo assim, a substituição física é o suficiente para
comprometer a regra de cálculo de salário, já que para a aplicação que a consome, acaba
sendo o mesmo componente. Se repararmos melhor, entre as quatro informações que
compõem a identidade do assembly, uma delas é chamada de PublicKeyToken, e que está
nula (não definida). É justamente nela que está a solução para o nosso problema.
Dentro do .NET Framework existem dois tipos de assemblies: os que são fracamente
nomeados e os que são fortemente nomeados. Aqueles que são fracamente nomeados (que é
o padrão para todos os projetos .NET), são estruturalmente idênticos, possuindo o mesmo
formato e os mesmos tipos definidos, mas como está, dá margem para esse tipo de problema.
Isso acontece porque quando efetuamos a referência do componente RegrasDeNegocio.dll na
aplicação AplicacaoDeRH.exe, o .NET injeta no manifesto da AplicacaoDeRH, informações
pertinentes ao assembly de regras de negócio. Se analisarmos o manifesto do EXE, veremos
a seguinte informação:
83
Frameworks de Desenvolvimento
Na imagem acima, podemos verificar que dentro da AplicacaoDeRH há uma referência para o
componente RegrasDeNegocio, que inclui o nome e a versão dele. Como até então o
componente ilegal possui a mesma identidade, a aplicação consome ele sem maiores
problemas, não sabendo que se trata de um componente malicioso.
Para resolver o nosso problema, vamos recorrer aos assemblies fortemente nomeados (strong
names). A única e principal diferença em relações aos assemblies fracamente nomeados, é a
atribuição de uma chave única, que não se repetirá em nenhum lugar do mundo. A Microsoft
criou esse recurso, desde a primeira versão do .NET Framework, que utiliza um par de chaves
(pública e privada) para garantir a unicidade do assembly. Antes de ver como elas funcionam,
vamos primeiramente entender como gerá-la. O .NET Framework fornece uma ferramenta
chamada SN.exe, que é responsável por gerar e manipular essas chaves. Para gerar a nossa
chave, podemos executar o seguinte comando (através do prompt do Visual Studio .NET):
SN -k MinhasChaves.snk
O arquivo gerado possui as duas chaves, a pública e a privada e você pode nomear o arquivo
da forma que quiser. Com o par de chaves gerado, podemos criar um segundo arquivo para
acomodar somente a chave pública, mas em um primeiro momento, isso é desnecessário. A
ideia aqui é somente visualizarmos o que temos como chave pública:
SN -p MinhasChaves.snk MinhaChavePublica.snk
Para visualizarmos a chave pública, podemos utilizar o seguinte comando:
SN -tp MinhaChavePublica.snk
Public key is
00240000048000009400000006020000002400005253413100040000010001
00f1589e575d9c20
cc36a0fb7245d74c8d69ddc26a0c92ebee5e65dba7c94a6583701176cc5a8f
d795e11d7e366c49
a19f3ae28509fa8961e6eca103353fe98168a402dc35001b98d9d5325f6121
bde11bc698f268a3
e7e338b950b565be26e371c2550dfaee54f9ef8993dc476f60b2ab5ad69d5a
e832ddd7e35e43ad
6daafae2
Public key token is 0b8510fcd7fd739a
Só que o arquivo snk por si só não funciona. Você precisa vinculá-lo ao assembly qual deseja
assinar. Para isso, você pode abrir o arquivo AssemblyInfo.cs, e adicionar o atributo
AssemblyKeyFileAttribute, que recebe o caminho físico até o arquivo que contém o par de
chaves, e que no nosso exemplo é MinhasChaves.snk.
[assembly: AssemblyKeyFile(@"C:\MinhasChaves.snk")]
Ao compilar o assembly com a chave vinculada, veremos que a identidade do assembly já
mudará. Ao vincular a chave criada acima no nosso componente RegrasDeNegocio, a
identidade irá aparecer da seguinte forma:
84
Frameworks de Desenvolvimento
RegrasDeNegocio, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=0b8510fcd7fd739a
A única e essencial diferença é que agora a propriedade PublicKeyToken reflete exatamente a
nossa chave pública, que está contida no arquivo MinhasChaves.snk vinculado ao
componente. A partir de agora, as aplicações que referenciarem o componente
RegrasDeNegocio, guardarão além do nome e versão do mesmo, a chave pública que o
identifica. Depois dessas alterações, se visualizarmos o manifesto da aplicação
AplicacaoDeRH, teremos o seguinte resultado:
Com isso, qualquer pessoa maliciosa que tente refazer o assembly, por mais que ela se atente
a criar toda a estrutura de tipos e métodos, definir o mesmo nome de assembly, e ainda,
assinar com um outro strong name, ela jamais conseguirá reproduzir a mesma identidade e,
consequentemente, não conseguirá mais alterar o componente que está instalado no cliente. É
importante dizer que fisicamente, a substituição ainda poderá ocorrer, mas quando a
aplicacação AplicacaoDeRH tentar acessar algum recurso do assembly RegrasDeNegocio,
uma exceção será disparada, informando que o assembly solicitado não corresponde aquele
que foi inicialmente referenciado.
Observação: Toda essa segurança pode continuar vulnerável se você deixar o arquivo com a
chave privada em mãos erradas. Se a pessoa maliciosa conseguir ter acesso a esse arquivo, ela
irá gerar o assembly idêntico como ela já fazia, mas ao invés de criar um novo par de chaves
para assinar o assembly, ela utilizará o mesmo que você utilizou para assinar o seu, que é o
verdadeiro, e com isso todo o problema volta a acontecer.
Para finalizar, vamos entender como todo esse mecanismo funciona e como o runtime do
.NET Framework assegura isso. Quando geramos a chave a partir do utilitário SN.exe, um par
de chaves é adicionado no arquivo MinhasChaves.snk. Quando compilamos o projeto com
esse arquivo vinculado a ele, o .NET gera um hash do componente utilizando o algoritmo
SHA1 e assina esse hash com a chave privada. O resultado deste processo é adicionado no
próprio assembly, incluindo também a sua chave pública, que está matematicamente
relacionada à chave privada. A imagem abaixo ilustra esse processo:
85
Frameworks de Desenvolvimento
Como vimos acima, quando o componente é referenciado na aplicação que o utiliza, a chave
pública também é adicionada à aplicação. Durante a execução, o .NET Framework irá aplicar
o mesmo algoritmo de hash no conteúdo do componente (DLL) e dará origem à um novo
hash e a chave pública embutida na aplicação que consome aquele componente, será utilizada
para extrair o conteúdo (já "hasheado") que está embutido na DLL do componente. Para
determinar se a DLL é a mesma ou não, o resultado do hash deve ser igual, do contrário, a
DLL foi substituída e, felizmente, uma exceção será disparada, evitando assim de consumir
um componente ilegal. A imagem abaixo ilustra esse processo:
Ao assinar uma aplicação/componente com um strong name, podemos tirar proveito de várias
funcionalidades, como por exemplo, o refinamento de segurança, a instalação no GAC, que
por sua vez possibilita a centralização, execução lado a lado de múltiplas versões de um
mesmo componente, etc. Mas um dos principais benefícios fornecidos por ele, é a unicidade
do componente, evitando que alguém consiga reproduzí-lo e, consequentemente, colocar em
risco a execução e a confiabilidade das aplicações que a consomem.
SQL Injection
A Injeção de SQL, mais conhecida através do termo americano SQL Injection, é um tipo de
ameaça de segurança que se aproveita de falhas em sistemas que interagem com bases de
dados via SQL. A injeção de SQL ocorre quando o atacante consegue inserir uma série de
instruções SQL dentro de uma consulta (query) através da manipulação das entrada de dados
de uma aplicação.
Para nos prevenirmos contra esse tipo de ataque, o ASP.NET fornece o objeto SqlCommand,
junto com a estrutura SqlParameter. Juntos, eles fazem a validação e ajustes nos dados que o
usuário envia e que venham a compor o comando SQL.
Exemplo de utilização:
86
Frameworks de Desenvolvimento
// cria um novo comando SQL
SqlCommand cmd = new SqlCommand("SELECT * FROM usuario WHERE
usuario=@usuario AND senha=@senha", conn);
// cria os parametros do comando
SqlParameter[] parametro = new SqlParameter[2];
parametro[0] = new SqlParameter("usuario", txtUsuario.Text);
parametro[1] = new SqlParameter("senha", txtSenha.Text);
// substitui parametros no comando
cmd.Parameters.AddRange(parametro);
87
Frameworks de Desenvolvimento
Unidade 8
Acessando Dados com ADO
O ADO.NET é um conjunto de classes que você pode utilizar para manipular dados, e
especificamente desenhado para gerenciar conexões em um ambiente desconectado. Além de
ser uma boa opção para aplicações web, o ADO.NET utiliza o formato XML para transmissão
de dados entre a aplicação e o banco de dados.
É composto de duas camadas, uma conectada e outra desconectada.
Camada Desconectada
A camada desconectada consiste em um número de classes para armazenamento de dados e
relações. A classe DataSet é a classe principal de aramazenamento de dados em cachê de
memória. Contém uma coleção ou mais de objetos DataTable que são compostos de linhas e
colunas de dados, chave primária, chave estrangeira, constraints, e informações sobre os
relacionamentos dos dados nos objetos DataTable. Você pode imaginar a classe DataSet
como uma representação em memória do banco de dados.
Camada Conectada
A camada conectada é responsável pelo tráfego de dados entre a aplicação e a fonte de dados.
A camada conectada é específica para cada banco de dados, como o SQL Server ou arquivo
XML. A camada conectada é também conhecida como provedora de dados e o ADO.NET já
vem com alguns provedores de dados prontos para uso, incluindo:
SQL Server .NET Framework Data Provider. Para acesso a bases SQL Server 7.0 e
versões posteriores.
OLE DB .NET Framework Data Provider. Para acessar qualquer fonte OLE DB que
você tenha um provedor OLE DB.
ODBC .NET Framework Data Provider. Para acessar qualquer fonte ODBC para qual
você prossua um driver ODBC.
Um grande número de terceiros,incluindo IBM e ORACLE, fornecem implementações de
Data Providers para o Framework .NET.
88
Frameworks de Desenvolvimento
ADO Object Model
Camada Desconectada
A camada desconectada é independente da fonte de dados é pode ser usada para
gerenciamento da informação em memória. Em função disso, pode ser usada com múltiplas
fontes de dados, ou dados XML, ou para gerenciar dados locais da aplicação. Opcionalmente,
você pode conectar a alguma fonte de dados usando a camada conectada.
É composta das seguintes classes, encontradas no namespace System.Data:
Tipo
Descrição
Constraint
Representa uma restrição que rege um ou mais objetos
DataColumn. Uma constraint é uma regra que é usada para
manter a integridade dos dados em uma tabela. A classe abstrata
Constraint tem duas classes derivadas que são usadas para chaves
primárias e/ou colunas de valores únicos utilizando a classe
UniqueConstraint. A classe base abstrata Constraint também
contem a ação a ser executada sobre os dados de uma tabela filha
quando os dados de uma tabela paid é apagada usando a classe
ForeignKeyConstraint.
DataColumn
Representa uma simples coluna de um DataTable, múltiplos
objetos DataColumn representam a estrutura de um DataTable.
DataRelation
Representa uma relação pai/filho entre dois objetos DataTable.
Um objeto DataRelation é unido a um numero igual de objetos
DataColumn de dois objetos DataTable diferentes. O bjeto
DataRelation permite a navegação entre tabelas relacionadas.
DataRow
Representa um registro de dado em um objeto DataTable.
DataSet
Esse é o container geral de objetos que representa um objeto
database na memória,consistindo de um ou mais objetos
DataTable e zero ou mais objetos DataRelation. Esse classe é
serializavel.
DataTable
Representa uma tabela de dados em memória. A estrutura é
composta de um ou mais objetos DataColumn, e a informação é
salva em objetos DataRow. Essa classe é serializavel e pode ser
transportada via rede.
89
Frameworks de Desenvolvimento
DataTableReader
Obtem o conteúdo de um mais objetos DataTable na forma de um
ou mais read-only, forward-only result sets.
DataView
Representa uma visão customizada de um DataTable, que pode
ser utilizado para ordenar, filtrar, procurar, editar, e navegar.
Camada Conectada
A camada conectada, fornece um link entre a fonte de dados e a camada desconectada. Os
tipos básicos, encontrados no namespace System.Data.Common estão listados abaixo.
A camada conectada inclui as classes DataAdapter, Connection, Command e DataReader.
Que são Data Providers desenhados para manipulação de dados e para rápida acessos leitura
de dados, forward-only, read-only.O objeto Commandpermite acesso a comandos do banco
de dados, permite retornar dados ao banco, modificar informação, executar stored procedures,
e enviar ou receber parâmetros. A classe DataReader fornece um stream de dados de alta
performance. E a classe DataAdapter fornece a ponte entre o objeto DataSet e a fonte de
dados. A classe DataAdapter utiliza o objeto Command para executar comandos SQL na
fonte de dados tanto para caregar o DataSet como para reconciliar as mudanças que foram
feitas no objeto DataSet, de volta para banco.
DBCommand
Representa um comando SQL ou stored procedure a ser executada
no banco de dados. Esse tipo é normalmente dividido em quatro
diferente grupos, um para seleção de dados, um para inserção, um
para atualização e um quarto para exclusão.
DbConnection
Representa a conexão à fonte de dados e se conecta a ela a partir de
uma connection string.
DbDataAdapter
Representa uma conexão a um banco de dados e a um conjunto de
comandos SQL que são usados para preencher um DataSet e/ou um
DataTable, e atualizar a fonte de dados.Esse objeto é um mediador
entre cliente e servidor, e usa um objeto de conexão e comando para
executar suas tarefas.
DbDataReader
Lê um stream de registros de um data source (forward-only, readonly).
Os tipos listados são tipos abstratos e precisam ser herdados. Você precisa utilizar os
seguintes tipos para implementações específicas de banco de dados:
90
Frameworks de Desenvolvimento
Para uso com SQL Server .NET Data Provider, você precisa das classes
SqlDataAdapter, SqlDataReader, SqlCommand, e SqlConnection, encontrados no
namespace System.Data.SqlClient.
Para uso com OLE DB .NET Data Provider, você tem OleDbDataAdapter,
OleDbDataReader, OleDbCommand, e OleDbConnection, todas sob o namespace
System.Data.OleDb.
Para uso com ODBC .NET Data Provider, você tem OdbcDataAdapter,
OdbcDataReader, OdbcCommand e OdbcConnection, todas sob o namespace
System.Data.Odbc.
Para uso com Oracle .NET Data Provider, você em OracleDataAdapter,
OracleDataReader, OracleCommand, and OracleConnection, todas sob o namespace
System.Data.OracleClient. Você pode utilizar essas classes para os bancos Oracle
versão 8.1.7 ou mais recentes.
Observação: você não pode misturar os tipos da camada conectada. Todos os tipos utilizados
para gerenciar dados em uma determinada fonte, devem vir do mesmo .NET Data Provider.
Contectando a um Banco de Dados
Criando um Banco de Dados
Crie um novo projeto em File > New Web Site, selecione o template ASP.NET Web Site, de
o nome de WebSite3, utiliza a linguagen “Visual C#”, e clique em Ok.
No Solution Explorer, sobre a pasta App_Data, clique em “Add New Item...” , selecione “Sql
Server Database”, utilize o nome Database.mdf, e clique em Add.
Na aba Server Explorer ( View >Server Explorer ), abra expanda o ramo Database.mdf e
clique com o botão direito sobre o item Tables:
91
Frameworks de Desenvolvimento
Clique com o botão direito, selecione “Add New Table”, e insira a seguinte definição:
Clique com o botão direito sobre a linha id, e selecione a opção Set Primary Key, e na aba
Properties marque a opção IsIdentity com Yes:
92
Frameworks de Desenvolvimento
Clique em File > Save Table, nomeie a tabela como Contatos e clique Ok.
Criando um Formulário de Inserção de Dados
Na aba Solution Explorer, clique sobre a página Default.aspx e abra para edição no modo
Source. Criaremos um formulário de entrada de dados para os campos nome, email, telefone,
e um botão salvar que executará a entrada dos dados.
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Inserção de Dados</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table style="width: 100%;">
<tr>
<td>Nome: </td>
<td>
<asp:TextBox ID="txtNome"
runat="server"></asp:TextBox>
</td>
93
Frameworks de Desenvolvimento
</tr>
<tr>
<td>
EMail:
</td>
<td>
<asp:TextBox ID="txtEMail"
runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td>
Telefone:
</td>
<td>
<asp:TextBox ID="txtTelefone"
runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td>
&nbsp;
</td>
<td>
<asp:Button ID="btnSalvar" runat="server"
Text="Salvar" />
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
No modo de Design, clique duas vezes sobre o botão Salvar do formulário e inclua os
namespaces na página:
using System.Data.SqlClient;
O código para inserção:
94
Frameworks de Desenvolvimento
using
using
using
using
using
using
using
using
using
using
using
using
System;
System.Configuration;
System.Data;
System.Linq;
System.Web;
System.Web.Security;
System.Web.UI;
System.Web.UI.HtmlControls;
System.Web.UI.WebControls;
System.Web.UI.WebControls.WebParts;
System.Xml.Linq;
System.Data.SqlClient;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSalvar_Click(object sender, EventArgs e)
{
// inicializa conexão ao banco
// C:\sites\WebSite3\App_Data\Database.mdf
// altere conforme a localização da sua aplicação
SqlConnection conn = new SqlConnection(@"Data
Source=.\SQLEXPRESS;AttachDbFilename=C:\sites\WebSite3\App_Dat
a\Database.mdf;Integrated Security=True;User Instance=True");
conn.Open();
// cria um novo comando SQL
SqlCommand cmd = new SqlCommand( "INSERT INTO Contatos
(nome, email, telefone) VALUES ( @nome, @email, @telefone )",
conn);
// cria os parametros do comando
SqlParameter[] parametro = new SqlParameter[3];
parametro[0] = new SqlParameter("nome", txtNome.Text);
parametro[1] = new SqlParameter("email",
txtEMail.Text);
parametro[2] = new SqlParameter("telefone",
txtTelefone.Text);
// substitui parametros no comando
cmd.Parameters.AddRange(parametro);
// executa comando SQL no banco
cmd.ExecuteNonQuery();
// fecha conexao
95
Frameworks de Desenvolvimento
conn.Close();
Response.Redirect("Default.aspx");
}
}
Salve e execute a página em Debug > Start Debugging, e insira alguns registros.
OBSERVAÇÃO: para obter a string de conexão do banco, na aba Server Explorer, clique
com o botão direito sobre o banco de dados, selecione Properties, e copie a string que se
encontra na propriedade Connection String.
Criando uma Listagem de Dados
Para a listagem utilizaremos o controle de dados DataGrid, que recebe um DataReader como
fonte de dados. No solution Explorer, sobre a localização da aplicação, clique com o botão
direito e selecione a opção “Add New Item”, template Web Form, nomeie o mesmo como
listagem.aspx, linguagem C#,e marque a opção “Place code in a separate file”.
Abra o arquivo listagem.aspx para edição, no modo Source, e insira um controle GridView a
partir da aba Data da Toolbox, e altere o nome do mesmo para gvListagem.
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="listagem.aspx.cs" Inherits="listagem" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Listagem</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="gvListagem" runat="server">
</asp:GridView>
</div>
</form>
</body>
</html>
96
Frameworks de Desenvolvimento
Clique com o botão direito sobre o código e selecione “View Code” e insira o seguinte código
no evento Page_Load, tomando cuidado de importar o namespace “using
System.Data.SqlClient;”.
using
using
using
using
using
using
using
using
using
using
using
using
using
System;
System.Collections;
System.Configuration;
System.Data;
System.Linq;
System.Web;
System.Web.Security;
System.Web.UI;
System.Web.UI.HtmlControls;
System.Web.UI.WebControls;
System.Web.UI.WebControls.WebParts;
System.Xml.Linq;
System.Data.SqlClient;
public partial class listagem : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// inicializa conexão ao banco
// C:\sites\WebSite3\App_Data\Database.mdf
// altere conforme a localização da sua aplicação
SqlConnection conn = new SqlConnection(@"Data
Source=.\SQLEXPRESS;AttachDbFilename=C:\sites\WebSite3\App_Dat
a\Database.mdf;Integrated Security=True;User Instance=True");
conn.Open();
// cria um novo comando SQL
SqlCommand cmd = new SqlCommand("SELECT * FROM
Contatos", conn);
// cria um novo DataAdapter apartir do comando SQL
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
// cria um DataSet para leitura dos dados
DataSet ds = new DataSet();
// preenche o DataSet
adapter.Fill(ds);
// liga o DataSet a GridView
97
Frameworks de Desenvolvimento
gvListagem.DataSource = ds;
gvListagem.DataBind();
// fecha a conexão
conn.Close();
}
}
Salve e execute a página em Debug > Start Debugging.
98
Frameworks de Desenvolvimento
Unidade 9
Depurando Aplicações no Visual Studio
Quando você desenvolve aplicações, você pode encontrar diversos tipos diferentes de erros.
Antes de solucioná-los você tem que identificar o tipo de erro e tratá-lo apropriadamente.
Existem 3 tipos de erros que você tem que lidar ao desenvolver um aplicativo: erro de sintaxe,
erros de runtime, e erros de semântica.
Erros de Sintaxe (Syntax Errors)
Os erros de sintaxe precisam ser solucionados para que o compilador possa compilar a
aplicação. Eles se referem a estrutura e as regras associadas aos comandos da linguagem e
aplicação. Por exemplo, se você tentar utilizar o seguinte comando:
if( this.isPostBack)
{
// bloco de instruções
}
E esquecer de fechar o par de parênteses ( ) ou chaves { }, um erro de sintaxe ocorre. O
Visual Studio alerta você sobre esses erros indicando no código enquanto você desenvolve.
Erros em tempo de execução (runtime)
São erros que ocorrem quando a aplicação está sendo executada. São também conhecidos
como exceções. Por exemplo, se uma aplicação espera que um determinado arquivo esteja
disponível em algum servidor de uma rede, mas ele não é encontrado pela aplicação, será
gerado um erro em tempo de execução (exception). Esse tipo de erro deve ser gerenciado pela
própria aplicação.
Erros de Semântica
São erros mais difíceis de localizar pois sua aplicação irá executar e não será emitido
nenhuma notificação. Mesmo assim, sua aplicação não executa a tarefa esperada. Por
exemplo, seu programa exibe um formulário de entrada com os dados de um cliente e são
salvos sem erro nenhum. Mas ao visualizar novamente a informação, alguns dados não
aparecem corretamente ou não foi salvo. Isso significa que a semântica da aplicação não está
correta.
99
Frameworks de Desenvolvimento
A Classe Debug
A classe Debug oferece métodos e propriedades que podem ajudar você a depurar seu código
exibindo informaçõese verificando seu código com declarações no código. Usando a classe
Debug, você tem a garantia de um código robusto sem afetar a performance e tamanho do
código do seu produto na release final. Isso por que os códigos de depuração da classe não
são compilados com o programa na versão Release da aplicação. A classe Debug é disponível
globalmente na aplicação importando o namespace System.Diagnostics. Não há necessidade
de instanciar a classe, ela não tem construtores, e você não pode herdar a mesma pois é do
tipo sealed.
Métodos da Classe Debug
Método
Descrição
Debug.Write
Escreve a string que você determinar, ou
escreve a saída de um método ToString de
um objeto .
Debug.WriteLine
Escreve uma linha de texto de sua escolha,
ou escreve a saída do método toString de
um Objeto.
Debug.WriteIf
Para escrever uma string
condicionalmente.
Debug.Print
Para gerar a saída de uma linha de texto
formatado.
Debug.Assert
Para exibir uma mensagem se uma
determinada condição for falsa.
Habilitando a Depuração
Você deve habilitar a depuração caso você deseje depurar a sua aplicação. Isso é feito no
arquivo web.config. Dentro do mesmo você precisa localizar o elemento compilation e
alterar o atributo debug para true.
<configuration>
<system.web>
<compilation debug="true">
...
</system.web>
<configuration>
100
Frameworks de Desenvolvimento
Adicionando BreakPoints
O Visual Studio nos fornece o recurso de BreakPoints, que são nada mais do que pontos de
parada da execução de uma aplicação.
Você pode colocar ou remover em qualquer ponto do seu código C# um Break Point
pressionando a tecla F9, ou a partir do menu Debug > Toggle Breakpoint, ou ainda sobre a
linha de código clicando o botão direito opção Breakpoint. Ou ainda, clicando sobre a bolinha
vermelha que marca o Break Point.
Executando a Aplicação em Modo de Depuração
Para executar sua aplicação em modo de debug, você deve pressionar F5 ou clicar em Start
Debugging no menu Debug. Se a depuração não estiver habilitada, você será perguntado se
quer habilitar o modo de depuração pela caixa de diálogo abaixo. Basta clicar em Ok para
habilitar a depuração. Isso irá modificar o arquivo web.config.
Execução Passo a Passo
Quando o depurador encontra uma linha com um breakpoint, a execução é suspensa. Você
pode então executar sua aplicação passo a passo e examinar a lógica de sua aplicação.
101
Frameworks de Desenvolvimento
Pressione F10 ou clique em Step Over no menu Debug, se você quer que a linha atual seja
executada sem entrar no código da instrução que está sendo executada, como um método na
mesma classe ou em uma classe externa. A execução irá parar na próxima linha de código.
Pressione F11 ou clique na opção Step Into do menu Debug se você quiser entrar no código
da instrução da linha atual, se houver algum. Por default, propriedades são normalmente não
usam esse tipo de execução por não conter código sobre elas.
Usando a Janela de Depuração
O Depurador do Visual Studio oferece diversas janelas, coletivamente conhecidas como
variable windows que exibem informações sobre as variáveis enquanto você está depurando.
Cada janela tem uma grid de três colunas: Name, Value e Type. A coluna nome mostra os
nomes das variáveis adicionadas automaticamente nas janelas Auto e Locals.
Na janela Watch, a coluna Name é onde você adiciona suas próprias variáveis ou expressões.
As colunas Value e Type exibem o valor e o tipo de variável ou resultado correspondente.
Você pode editar o valor da variável na coluna Value.
Exibindo a Janela Window
No menu Debug, selecione Windows e então o nome da janela que você quer abrir. Você
pode escolher Autos, Locals, Watch ou Watch1 até Watch4. Para exibir esses itens, o
depurador deve estar sendo executado ou no modo break.
Depuração Remota
Para você executar depuração remota, você deve usar o programa Remote Debugging
Monitor ou msvsmon.exe, que é uma aplicação à qual o Visual Studio se conecta.
Por default, o Remote Debugging Monitor roda como uma aplicação Windows, você pode
configurá-lo para rodar como serviço caso queira que ele seja executado em um servidor
remoto. Você pode executar o assistente a partir do menu Start, pasta Tools.
Depois de iniciar o depurador remoto, você deve configurar os ambientes em ambas as
máquinas. Você também deve levar em consideração, as questões de seguranças relacionadas
ao acesso remoto.
Tracing
Tracing é o processo de receber informação sobre a execução da aplicação em tempo de
execução. É uma maneira de monitorar a sua aplicação. Essa informação pode lhe auxiliar a
identificar problemas ou analisar performance, de uma maneira que não afeta a
aplicação.Tracing normalmente é utilizado em ambiente de produção em que não é possível
executar depuração.
102
Frameworks de Desenvolvimento
Você pode utilizar o tracing para:
Ter um diagnóstico das informações de uma requisição a uma página ASP.NET
Escrever instruções de depuração diretamente no código.
Descobrir o código no qual a sua aplicação percorreu.
Classe TraceContext
É a classe usada para escrever mensagens em uma página ou no trace log em memória.
Métodos da Classe TraceContext:
Write : escreve uma mensagem de trace no log
Warn : similar ao método Write, porém as mensagens aparecem em vermelho.
Ambos os métodos possuem 3 overloads, todos os 3 possuem uma mensagem de tracing, e
adicionalmente um nome de categoria, e um parâmetro to tipo Exception que indica que você
pode informar um erro capturado ou uma exceção definida pelo usuário.
Exemplo:
Trace.Warn("Atenção");
Trace.Write("Mensagem de Trace");
Trace.Write("Categoria", "Mensagem de Trace");
Trace.Write("Categoria", "Mensagem de Trace", new
Exception("mensagem da exceção"));
Saída:
O parâmetro trace permite você classificar a saída do Trace por categoria alterando o código:
<%@ Page ... Trace="True" TraceMode="SortByCategory" %>
103
Frameworks de Desenvolvimento
Alternativamente você também pode utilizar SortByTime.
Você pode utilizar a propriedade IsEnable do TraceContext para alterar o estado do tracing
dinamicamente ou verificar seu estado:
// habilitando o tracing no código
Trace.isEnabled = true;
// verificando seu estado
if (Trace.IsEnabled)
{
Trace.Write("Tracing está habilitado!");
}
Habilitando o Tracing em uma Aplicação Web
Você pode utilizar o seguinte código para ativar o Tracing a nível de página:
<%@ Page Language="C#" Trace="true" ... %>
Ou a nível de aplicação, alterando o arquivo web.config:
<configuration>
...
<system.web>
<trace enabled=”true” />
...
</system.web>
</configuration>
Dados do Trace
As informações do trace a nível de página são adicionadas ao final da página .aspx em que
estiver habilitado.
Categorias do Trace
Os dados do Trace são divididos em diversas categorias conforme listado:
104
Frameworks de Desenvolvimento
Categoria
Descrição
Request Details
Informação sobre a requisição: identificação da sessão (ID),
tempo da requisição, tipo de requisição, e status.
Trace Information
Saídas padrão e customizadas de trace. A coluna From First(s)
contem o tempo total desde a execução até o trace acontecer, e a
coluna From Last(s) mostra o tempo restante.
Os tempos aqui são importantes para se ter um perfil e para
identificar os métodos que mais demoram para responder.
Control Tree
Lista de todos os itens que estão na página, junto com o
tamanho de cada uma.
É uma representação da ASP.NET Control Tree. Mostra cada
controle, seu ID único, tipo, números de bytes que utiliza para
ser renderizado, e o número de bytes que ocupa na ViewState e
ControlState.
Session State
Informação sobre os valores armazenados na sessão (Session),
se houver algum.
Application State
Informação sobre os valores armazenados na Application, se
houver algum.
Headers Collection
Lista de requisição e header de resposta.
Form Collection
Lista de controles e seus valores, do formulário que foi enviado.
Querystring
Collection
Lista de valores passados na URL.
Server Variables
Lista de toda as variáveis do servidor e seus valores.
105
Frameworks de Desenvolvimento
Unidade 10
Compilando, Testando e Distribuindo
Aplicações .NET
Depois de pronta sua aplicação precisa ser distribuida para todos que querem ou precisam
usá-la. Para usar a sua aplicação, o único requisito para o computador do cliente é que tenha
instalado o .NET Framework. Este pode ser instalado diretamente do site da Microsoft, ou ser
disponibilizado com sua aplicação no pacote de instalação. Ele também é disponível através
do Windows Update e futuramente deve vir junto com todos os sistemas operacionais da
Microsoft.
Então, tendo o .NET Framework instalado na máquina, para sua aplicação funcionar basta
você copiar o arquivo executável para a máquina em questão e executá-lo. No entanto essa
prática não é muito recomendada, é mais elegante criar um pacote de instalação para instalar
o programa, permitindo assim também sua possivel desinstalação através do Painel de
Controle, Adicionar/Remover programas.
Criando um Projeto de Instalação
Para esse exemplo, utilizaremos o projeto da Calculadora desenvolvido nessa apostila. Com
seu projeto aberto, no menu File clique aponte em New e clique em New Project.
Na janela New Project, em Project Type, selecione Other Project types > Setup and
Deployment Projects.
106
Frameworks de Desenvolvimento
Repare em Templates nas seguites opções:

Setup Project: cria um programa de instalação que usa o Windows Installer.

Web Setup Project: usa o Windows Installer e um Servidor Web para disponibilidar a
aplicação.

Merge Module Project: cria um arquivo de instalação do tipo msm que pode ser usado por
outras aplicações.

Cab Project: usado quando você precisa de arquivos de instalação com tamanho
especifico. Se por exemplo sua aplicação tem 30MB e você quer disponibiliza-la na
internet, pode criar 3 arquivos de 10MB para facilitar o download.

Smart Device CAB Project: usado para criação de projeto instalação para dispositivos
móveis.

Setup Wizard: é um assistente, através dele você pode criar os tipos citados acima só que
de maneira simplificada.
Selecione Setup Wizard.
Em Solution, selecione Add to Solution como a imagem:
107
Frameworks de Desenvolvimento
Isso adiciona o projeto a solução que esta aberta no Visual Studio, se estiver marcado Create
new Solution, o projeto aberto é fechado e é criado um novo projeto.
Em Name você pode dar uma nome para seu projeto de instalação. Por hora, mantena o nome
padrão e clique em OK. O Assistente será inicializado.
108
Frameworks de Desenvolvimento
Clique em Next.
109
Frameworks de Desenvolvimento
Nesse passo você deve informar o tipo de aplicação, se Windows ou Web. Nesse caso,
mantenha a opção Windows application selecionada.
Clique em Next.
110
Frameworks de Desenvolvimento
Selecione as opções Content Files from Calculadora e Primary output Files from
Calculadora. Isso inclui na instalação arquivos EXE e DLL do projeto.
Se tiver arquivos adicionais para serem adicionados ao projeto como o arquivo do banco de
dados do Access ou algum TXT com informações sobre o projeto clique em Add para
adicionar o arquivo no passo 4 do assistente.
111
Frameworks de Desenvolvimento
Clique em Next para prosseguir.
112
Frameworks de Desenvolvimento
Clique em Finish.
O Visual Studio adiciona um novo projeto na solução chamado Setup1, como você pode ver
no Solution Explorer.
O File System Editor também aparece como mostra a figura.
113
Frameworks de Desenvolvimento
Você usa o File System Editor para adicionar arquivos no seu projeto de instalação e criar os
atalhos do menu Iniciar e Desktop para sua aplicação.
Clique em Setup1 na janela Solution Explorer e veja as propriedades disponíveis na janela
Properties.
A propriedade Author e Manufacturer são geralmente preenchidas com o nome da companhia
que desenvolve o software, seus valores também são usados para construir o caminho padrão
onde será instalado o programa. Uma vez instalado o programa a propriedade Author é
exibida nas informações de suporte em Adicionar/Remover Programas no Painel de Controle.
A propriedade Title é o nome do programa de instalação e a propriedade Version permite
especificar informações sobre a versão do seu programa de instalação. As propriedades
Product Code contém informações geradas pelo Visual Studio que permitem identificar
individualmente distribuições do seu programa.
Atenção, estas propriedades dizem respeito ao programa de instalação e não a aplicação
Formularios.
Na janela Solution Explorer, clique com o botão direito do mouse sobre Setup1 e clique e em
Properties.
É exibida a caixa de diálogo Setup1 Property Pages. Esta caixa de diálogo permite que você
altere algumas das opções escolhidas no assistênte (Setup Wizard) caso necessário e
customize algumas configurações adicionais que não estavam disponíveis no assistente.
114
Frameworks de Desenvolvimento
A caixa Output File Name especifica o nome do arquivo da instalação. Geralmente ele
contém a extensão .msi por ser usado pelo Windows Installer.
A caixa de seleção Package Files contém 3 opções:

As Loose Uncompressed Files: cria arquivos descompactados dentro da pasta de
instalação.

In Setup File: é a que cria o arquivo msi.

Cabinet Files(s): gera os arquivos cab na pasta de instalação.
A caixa de seleção Compression permite escolher a otimização da compactação dos arquivos
de intalação, a maior parte dos programadores escolhe Optimized for Size, que prioriza
diminuir o tamanho dos arquivos de instalação.
Clique em OK.
Em Build > Configuration Manager, altere a opção Debug para Release:
115
Frameworks de Desenvolvimento
Quando estamos criando nossa aplicação é importante que esta caixa de seleção esteja
marcada com Debug para que possamos usar as ferramentas de depuração de erros do Visual
Studio. Com o Debug marcado o programa é compilado com informações extras para permitir
a depuração dos erros, essas informações não são necessárias quando estamos
disponibilizando nossa aplicação e também ocasionam perda de performance na nossa
aplicação.
Na janela Solution Explorer, clique com o botão direito do mouse em Setup1, selecione View,
clique em Launch Condition.
É aberta a página Launch Condition.
Na janela Properties a propriedade InstallUrl é setada com uma página na Internet que
possibilita o download e instalação do .NET Framework, como sabe, necessário para sua
aplicação funcionar.
116
Frameworks de Desenvolvimento
Por padrão sempre que é inicializado a instalação é verificado se o .NET Framework esta
instalado na máquina em questão ou não. Se não estiver ele usa essa propriedade, a InstallUrl
para fazer o download e instalação do arquivo Dotnetfx.exe, que instala o .NET Framework.
Antes de iniciar o download e instalação da Internet ele emite uma mensagem, o contéudo
desta mensagem está na propriedade Message.
Você pode disponibilizar o .NET Framework junto com sua instalação, para que não seja
necessário baixar o arquivo da internet. Para isso você muda a propriedade InstallUrl para o
caminho da sua instalação e se desejar muda a propriedade Message para um mensagem mais
apropriada. Será necessário copiar então o arquivo Dotnetfx.exe para a pasta de instalação do
seu programa ou para a pasta que você indicar em InstallUrl.
Vamos deixar como está, para fazer o download se necessário.
Na janela Solution Explorer, clique com o botão direito sobre Setup1, depois clique em
Build.
No Windows Explorer localize a pasta do projeto Setup1, ela foi especificada quando você
criou o projeto e entre na pasta Release.
Eis os arquivos necessários para a instalação do seu projeto, você pode copiados em um CD
para disponibilizar a instalação do seu programa, como citado anteriormente você pode copiar
para esta pasta também o arquivo Dotnetfx.exe para disponibilizar junto a instalação do .NET
Framework.
117
Frameworks de Desenvolvimento
118

Documentos relacionados