0% acharam este documento útil (0 voto)
10 visualizações109 páginas

Easy-Net 016 Tfdxzasg

O artigo apresenta o LINQ to XML, um recurso do .NET Framework que simplifica a leitura e escrita de dados em formato XML utilizando a linguagem C#. Ele discute a complexidade da manipulação de XML e como o LINQ to XML oferece uma abordagem mais eficiente e menos trabalhosa em comparação com métodos tradicionais como o DOM. Exemplos de uso e a estrutura de documentos XML são fornecidos para ilustrar as funcionalidades do LINQ to XML.

Enviado por

Osmar
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
10 visualizações109 páginas

Easy-Net 016 Tfdxzasg

O artigo apresenta o LINQ to XML, um recurso do .NET Framework que simplifica a leitura e escrita de dados em formato XML utilizando a linguagem C#. Ele discute a complexidade da manipulação de XML e como o LINQ to XML oferece uma abordagem mais eficiente e menos trabalhosa em comparação com métodos tradicionais como o DOM. Exemplos de uso e a estrutura de documentos XML são fornecidos para ilustrar as funcionalidades do LINQ to XML.

Enviado por

Osmar
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 109

Introdução à LINQ - Parte

2
Este artigo tem o objetivo de demonstrar,
em termos gerais, como o recurso do .NET
Framework denominado LINQ To XML pode
ser utilizado em operações envolvendo a
leitura e / ou escrita de informações no
formato XML, empregando-se para isto a
linguagem C#.

De que se trata o artigo

Este artigo tem o objetivo de demonstrar, em termos gerais, como o recurso


do .NET Framework denominado LINQ To XML pode ser utilizado em
operações envolvendo a leitura e / ou escrita de informações no formato
XML, empregando-se para isto a linguagem C#. Language Integrated Query
(LINQ) é um recurso da plataforma .NET que permite, basicamente, a
realização execução de consultas (queries) e outros tipos operações sobre
agrupamentos de dados. Tais agrupamentos podem ser representados por
coleções de objetos, entidades correspondentes a estruturas de dados de um
banco SQL Server, documentos XML ou, ainda, Datasets obtidos através das
classes de acesso a dados do ADO.NET. A extensão conhecida como LINQ to
XML é utilizada na manipulação de dados no formato XML, disponibilizando
uma série de recursos que simplificam a realização de operações de escrita e
leitura.

Em que situação o tema é útil

A manipulação de dados em XML tende a ser uma tarefa trabalhosa, haja vista
a necessidade de se efetuarem numerosas operações para o tratamento de
informações dispostas em uma estrutura hierárquica. Em virtude disto, não é
fato raro que funcionalidades destinadas à manipulação de XML sejam
implementadas através de extensos trechos de código. Procurando oferecer
uma alternativa que reduza a complexidade inerente a este tipo de processo, a
plataforma .NET disponibiliza o mecanismo denominado LINQ to XML para
a realização de operações sobre dados no formato XML.

LINQ to XML

O tratamento de dados no formato XML representa um tipo de atividade


frequente no dia-a-dia de desenvolvedores de software. XML é um dos
padrões mais empregados para o intercâmbio de informações atualmente,
sendo ainda comum o seu uso sob a forma de arquivos de configurações ou,
mesmo, na persistência de informações dispostas segundo algum grau de
hierarquia. Importante ressaltar que existem, inclusive dentro do próprio .NET
Framework, diversas técnicas para a manipulação de dados neste formato. No
entanto, embora muitos dos mecanismos disponíveis para se tratar XML
apresentem benefícios, os mesmos também acrescentam uma maior
complexidade no desenvolvimento. LINQ to XML é uma tecnologia que visa
facilitar a implementação de processos que envolvem a utilização de XML,
disponibilizando para isto uma série de recursos para a realização de
operações sobre dados hierárquicos.

O formato XML (sigla em inglês para Extensible Markup Language) é um


padrão aberto para a geração de documentos hierárquicos, contando com uma
ampla utilização por parte de aplicações computacionais dos mais variados
tipos. Trata-se de uma especificação que também é fruto de trabalhos do W3C
(simplificação em inglês de World Wide Web Consortium), tendo surgido
ainda no final da década de 1990.

O uso de informações em XML se faz presente em situações como processos


de integração entre soluções de softwares via Web Services, no conteúdo de
sites da Internet, em softwares convencionais instalados em computadores,
dentro de dispositivos móveis etc.

A larga aceitação de XML se deve, entre outros fatores, à simplicidade deste


formato e aos esforços para com a padronização desta linguagem. Contribui
em muito para isto, ainda, o total suporte oferecido a este padrão pelas
principais linguagens de programação e sistemas operacionais. Levando tais
fatos em consideração, numerosas técnicas para a manipulação de dados em
XML foram concebidas.

Um exemplo disto é o mecanismo conhecido DOM (Document Object


Model). Trata-se de uma convenção composta por um conjunto de regras que
possibilitam, por sua vez, a navegação pela hierarquia de um documento
XML: isso acontece, normalmente, sob a forma de uma estrutura que se
assemelha a uma "árvore", com objetos dependendo uns dos outros e estando
dispostos em vários níveis. Muitas plataformas de desenvolvimento contam
com bibliotecas compatíveis com o padrão DOM, incluindo-se também nisto
o .NET Framework.

Contudo, manipular informações em XML por meio de DOM tende a ser,


muitas vezes, uma tarefa trabalhosa, podendo resultar extensos trechos de
código ao longo de uma solução de software.

Na edição anterior iniciou-se a discussão sobre LINQ, com isto sendo feito
por meio da demonstração de como consultas poderiam ser efetuadas sobre
coleções de objetos (LINQ to Objects). Neste novo artigo será explicado como
a manipulação de informações no formato XML pode ser simplificada com
LINQ, empregando-se neste caso o recurso conhecido como LINQ to XML.

A fim de se cumprir com este objetivo, serão demonstrados exemplos de


como se proceder com a leitura e a escrita de informações em XML. Serão
utilizadas, assim, algumas das classes que LINQ disponibiliza para atividades
deste gênero, bem como discutidos conceitos relacionados a tais práticas.

Estrutura geral de um documento


XML
Assim como a linguagem HTML (Hypertext Markup Language), XML é um
formato baseado em marcações (tags). No entanto, diferentemente de HTML
em que existe um conjunto padrão de tags, XML é na verdade uma
metalinguagem, ou seja, um conjunto de regras para a criação de uma nova
linguagem: não existem tags pré-definidas, com as marcações sendo
estipuladas conforme uma demanda específica.

Documentos em XML são formados por um conjunto de elementos (nodes),


sendo que as relações de dependência entre estes últimos se estabelecem por
meio de níveis de hierarquia. Um elemento, por sua vez, é constituído por uma
tag e seu respectivo conteúdo. Quanto ao conteúdo, um elemento pode estar
vazio, possuir atributos ou, mesmo, conter um agrupamento de outros
elementos. Já um atributo é formado por um par constituído por um nome e
um valor correspondente (com este último entre aspas), sendo que estes dois
itens encontram-se separados por um sinal de “=” (“igual”).

Na Listagem 1 encontra-se um exemplo simples de um documento XML


contendo algumas informações sobre países.

Listagem 1. Exemplo de documento XML

<?xml version="1.0" encoding="utf-8">


<Continentes>
<Continente>
<Nome>Europa</Nome>
<Paises>
<Pais Sigla="ALE">
<Nome>Alemanha</Nome>
<Capital>Berlim</Capital>
</Pais>
<Pais Sigla="ING">
<Nome>Inglaterra</Nome>
<Capital>Londres</Capital>
</Pais>
</Paises>
</Continente>
</Continentes>

A primeira linha contida no documento de exemplo é uma declaração que


estará presente em qualquer documento XML. Dentro da mesma podem ser
notados os seguintes atributos:

• version: indica qual versão padrão da especificação XML está sendo


empregada (no exemplo está sendo empregada a versão 1.0);

• encoding: define o conjunto padrão de caracteres adotado para o documento


XML (neste caso, UTF-8).

Nota do DevMan

Encodings são especificações que definem um conjunto de caracteres capazes


de serem suportados. Exemplos disto são padrões como o ASCII, UTF-8, UTF
-16 e UTF-32. O UTF-8 (sigla em inglês para 8-bit Unicode Transformation F
ormat) é um tipo de codificação que engloba uma larga faixa de caracteres, faz
endo uso para isto de 1 a 4 conjuntos de 8 bits (octeto) para a representação de
símbolos.

As diversas tags (Continentes, Continente, Países, Pais, Nome e Capital)


definidas ao longo do documento XML representam os elementos que formam
o mesmo. Considerando o exemplo fornecido, é possível que um elemento
possua elementos-filho (caso de Continentes, Continente, Países e Pais) ou,
mesmo, que apresente apenas texto em seu conteúdo (tags Nome e Capital).
Além disso, está sendo demonstrado ainda como se empregam atributos
(Sigla) dentro da tag que define um elemento (Pais).

Exemplos de uso de XML


A seguir são listados alguns exemplos bem conhecidos de utilização do
formato XML:

• Arquivos de configuração dentro da plataforma .NET (extensão .config).


Estruturas deste tipo contam com parâmetros que podem ser configurados
através da edição de um arquivo no formato XML, dispensando assim a
necessidade de recompilação de uma aplicação;

• Nota fiscal eletrônica: trata-se uma exigência governamental, sendo que


operações de entrada ou saída envolvendo mercadorias e serviços são
repassadas a órgãos governamentais. Documentos XML são utilizados para a
transmissão de tais informações;

• WSDL (Web Services Description Language): trata-se de um padrão que


utiliza XML, tendo por finalidade descrever as funcionalidades oferecidas por
Web Services;

• XSD (XML Schema Definition): outra especificação baseada em XML. É


usada na definição de regras de validação e de tipos de dados presentes em
documentos XML;

• SOAP (Simple Object Access Protocol): protocolo XML empregado em


trocas de mensagens entre Web Services e consumidores destes tipos de
serviços.

LINQ to XML: uma visão geral


LINQ to XML integra o .NET Framework desde a versão 3.5, permitindo a
realização de operações em memória sobre informações no formato XML.
Conforme já mencionado, a introdução deste mecanismo na plataforma .NET
teve como objetivo primário simplificar operações envolvendo XML. Antes,
isto era normalmente realizado por meio de bibliotecas que empregavam o
padrão DOM (Document Object Model), resultando muitas vezes em extensos
e complexos trechos de código.

Elementos que constituem um documento XML são representados, ao se


utilizar LINQ to XML, como uma árvore em que se estabelece uma relação de
hierarquia entre elementos-pai e filhos correspondentes. A isto se dá o nome
de XML tree. É esta noção de árvore que serve de base para aplicação dos
variados mecanismos presentes em LINQ to XML.

As diversas funcionalidades oferecidas encontram-se dentro do namespace


System.Linq.Xml, com as mesmas tornando possíveis operações como a
leitura e geração de arquivos XML, assim como criação, alteração, execução
de consultas e validações sobre XML trees na memória. O uso de LINQ to
XML gira em torno das seguintes classes básicas:

• XDocument;

• XElement;

• XAttribute.

O tipo XDocument representa um documento XML. O mesmo conta com


métodos que permitem a realização de operações sobre arquivos (escrita e
leitura), navegação pelos diferentes nodes (elementos) de um documento
XML e ainda a inclusão, modificação ou exclusão de elementos.

Já a classe XElement corresponde a elementos pertencentes a um documento


XML. Através deste tipo é possível a navegação para níveis inferiores da
hierarquia de um elemento, assim como a alteração, inclusão ou mesmo
exclusão de elementos-filhos.

XAttribute, por sua vez, é um tipo que equivale a um atributo dentro de um


elemento XML. Geralmente, instâncias desta classe são vinculadas a objetos
do tipo XElement.

Geração e leitura de informações


com LINQ to XML
A gravação de informações empregando LINQ to XML se faz, basicamente,
através da utilização de classes como XDocument, XElement, XAttribute e
XDeclaration (esta última corresponde à declaração no início de um arquivo
XML). Na Listagem 2 encontra-se um exemplo de geração de um documento
XML (em memória) empregando LINQ; como resultado de tal operação, seria
obtido um conjunto de informações equivalente ao XML descrito
anteriormente.

Listagem 2. Gerando um documento com LINQ to XML

...

XDocument xmldoc = new XDocument(


new XDeclaration("1.0", "utf-8", ""),
new XElement("Continentes",
new XElement("Continente",
new XElement("Nome", "Europa"),
new XElement("Paises",
new XElement("Pais",
new XAttribute("Sigla", "ALE"),
new XElement("Nome", "Alemanha"),
new XElement("Capital", "Berlim")),
new XElement("Pais",
new XAttribute("Sigla", "ING"),
new XElement("Nome", "Inglaterra"),
new XElement("Capital", "Londres"))
)
)
)
);

...

Inicialmente, gera-se uma instância de XDocument, invocando-se o construtor


desta classe que recebe 2 parâmetros: o primeiro deles é um objeto do tipo
XDeclaration, ao passo que o segundo parâmetro é uma instância da classe
XElement.

Ao se instanciar um objeto invocando o construtor de XDeclaration estão


sendo fornecidos como parâmetros a versão da especificação XML utilizada
(1.0), o tipo de enconding (UTF-8) e o terceiro valor informado é uma string
em branco. Este último parâmetro corresponde ao valor do atributo
standalone, sendo que o preenchimento disto só tem relevância quando se
emprega um esquema (DTD) definindo a estrutura do documento XML que se
está manipulando.

O segundo parâmetro passado ao construtor de XDocument é uma instância


da classe XElement, sendo que no XML resultante isto corresponderá a um
elemento de nome Continentes. O construtor utilizado para XElement ao
longo dos exemplos apresentados neste artigo recebe 2 parâmetros. O
primeiro deles seria o nome do elemento XML. Já o segundo é um array do
tipo object marcado com a palavra-chave params: esta instrução indica que o
parâmetro em questão pode receber um número variável de itens (há casos em
que se utiliza apenas um item como uma string, com outros nos quais
informam-se vários objetos do tipo XElement, por exemplo).

Dentro do elemento de nome Continentes constará também um elemento-filho


chamado Continente (criado através de XElement). Este último, por sua vez,
conterá os elementos Nome e Países, também gerados por meio de instâncias
de XElement.

No interior do elemento Países existirão ainda dois elementos-filho. Estes


últimos são compostos pelo atributo Sigla (gerado por meio de uma instância
da classe XAttribute) e pelos elementos Nome e Capital (criados através de
XElement).

Nota do DevMan

DTD (do inglês Document Type Definition) é um tipo de arquivo que pode co
nter as regras que definem a estrutura de um documento contendo marcações.
Trata-se de um recurso que pode ser empregado tanto com XML, quanto com
a linguagem XHTML (formato que mescla características de HTML com XM
L).

A Listagem 3 apresenta o equivalente em DOM ao código em LINQ to XML


já demonstrado nesta seção. Para isto, estão sendo empregadas as classes
XmlDocument, XmlDeclaration, XmlElement e XmlAttribute, as quais
encontram-se no namespace System.Xml. Ao se utilizar este conjunto de
tipos, elementos, atributos e declarações devem ser gerados a partir de
métodos disponibilizados por XmlDocument (CreateElement, CreateAttribute
e CreateXmlDeclaration).

Observando este exemplo, torna-se bastante perceptível o fato de que o uso de


DOM tende a ser uma tarefa bem mais trabalhosa e complexa. A comparação
destas duas abordagens permite concluir que uso de LINQ, levando em conta
um esforço relativamente menor, pode simplificar processos que envolvam a
manipulação de XML.

Listagem 3. Gerando um documento XML utilizando DOM

...
XmlDocument xmldoc = new XmlDocument();
XmlDeclaration xmldec = xmldoc.CreateXmlDeclaration(
"1.0", "utf-8", "");
xmldoc.AppendChild(xmldec);

XmlElement continentes = xmldoc.CreateElement("Continentes");

XmlElement europa = xmldoc.CreateElement("Continente");


XmlElement nomeEuropa = xmldoc.CreateElement("Nome");
nomeEuropa.InnerText = "Europa";
europa.AppendChild(nomeEuropa);

XmlElement paises = xmldoc.CreateElement("Paises");

XmlElement alemanha = xmldoc.CreateElement("Pais");


XmlAttribute siglaAlemanha = xmldoc.CreateAttribute("Sigla");
siglaAlemanha.Value = "ALE";
alemanha.Attributes.Append(siglaAlemanha);
XmlElement nomeAlemanha = xmldoc.CreateElement("Nome");
nomeAlemanha.InnerText = "Alemanha";
alemanha.AppendChild(nomeAlemanha);
XmlElement capitalAlemanha = xmldoc.CreateElement("Capital");
capitalAlemanha.InnerText = "Berlim";
alemanha.AppendChild(capitalAlemanha);
paises.AppendChild(alemanha);

XmlElement inglaterra = xmldoc.CreateElement("Pais");


XmlAttribute siglaInglaterra = xmldoc.CreateAttribute("Sigla");
siglaInglaterra.Value = "ING";
inglaterra.Attributes.Append(siglaInglaterra);
XmlElement nomeInglaterra = xmldoc.CreateElement("Nome");
nomeInglaterra.InnerText = "Inglaterra";
inglaterra.AppendChild(nomeInglaterra);
XmlElement capitalInglaterra = xmldoc.CreateElement("Capital");
capitalInglaterra.InnerText = "Londres";
inglaterra.AppendChild(capitalInglaterra);
paises.AppendChild(inglaterra);

europa.AppendChild(paises);
continentes.AppendChild(europa);
xmldoc.AppendChild(continentes);

...

A consulta de informações empregando LINQ to XML também é feita


utilizando-se funcionalidades das classes XDocument, XElement e
XAttribute. Este mecanismo de tratamento de XML pode ser combinado com
queries escritas em LINQ to Objects, de maneira a tornar mais ágeis ainda
tarefas que envolvam a leitura de dados. A Listagem 4 apresenta um exemplo
desta prática, baseando-se também no documento XML de países que já foi
comentado anteriormente.

Listagem 4. Efetuando uma consulta com LINQ to XML

...

var dadosPaises =
(from e in xmldoc.Element("Continentes")
.Element("Continente").Element("Paises")
.Elements("Pais")
select new
{
Nome = e.Element("Nome").Value,
Capital = e.Element("Capital").Value
});
foreach (var pais in dadosPaises)
{
string nome = pais.Nome;
string capital = pais.Capital;

...

...

As classes XDocument e XElement possuem em comum os seguintes


métodos:

• Element: permite a seleção de um elemento simples (que não se repete)


dentro de um trecho de dados em XML;

• Elements: possibilita que sejam selecionados diversos elementos que


possuam um mesmo nome a partir de um agrupamento XML.

As chamadas sucessivas aos métodos Element e Elements a partir do objeto


XDocument representado pela variável xmldoc permitem, por sua vez, que se
navegue pela estrutura do documento XML, selecionando-se através de uma
query em LINQ informações de países. Dentro da cláusula select um tipo
anônimo está sendo gerado, sendo que Nome e Capital são preenchidas com
os valores que constam na propriedade Value dos elementos XML
equivalentes. Por fim, as informações resultantes são consumidas dentro da
instrução foreach.

Exemplo de utilização de LINQ to


XML
A aplicação apresentada neste artigo foi desenvolvida no .NET Framework
4.0, por meio da utilização do Microsoft Visual Studio 2010 Ultimate Edition,
sendo que o conteúdo da mesma poderá ser baixado a partir do site da revista.
O exemplo demonstrado a seguir tem por finalidade principal demonstrar a
utilização do recurso LINQ to XML, expondo alguns exemplos de como se
empregar este mecanismo na manipulação de dados no formato XML.
A fim de se cumprir com este objetivo, será construída uma aplicação em
Windows Forms para a manipulação de uma agenda de contatos em empresas.
A partir disto, instruções em LINQ to XML serão empregadas para a escrita
de um arquivo contendo a relação de contatos, assim como para a posterior
leitura de tais informações.

Para se criar o projeto de testes será necessário, dentro do Visual Studio,


acessar o menu File, opção New, subopção Project. Dentro da tela New
Project (Figura 1) deve-se selecionar o template Windows Forms
Application, preenchendo o campo Name com o nome da aplicação a ser
gerada (“TesteLinqToXml”, neste caso); no campo Location é possível ainda
se definir o diretório no qual serão criados os arquivos para este projeto.

Figura 1. Criando um projeto Windows Forms Application para testes

Criação das classes para


manipulação de contatos
Uma vez que tenha sido criada a aplicação TesteLinqToXml, será necessário
prosseguir com a especificação das classes a serem utilizadas na manipulação
de informações sobre contatos.

Primeiramente será criada a classe AgendaWriter. Isto será feito clicando-se,


dentro do Solution Explorer, com o botão direito do mouse sobre o projeto
TesteLinqToXml; na sequência seleciona-se a opção Add, subopção New
Item. Aparecerá neste momento a tela indicada pela Figura 2, sendo
necessário preencher o campo Name com “AgendaWriter.cs”, visando com
isto gerar o arquivo que conterá as definições do tipo AgendaWriter.

Figura 2. Criando o arquivo para implementação da classe AgendaWriter

O tipo AgendaWriter (Listagem 5) é uma classe estática, ou seja, não serão


geradas instâncias para a utilização do mesmo aonde se empregar esta
estrutura. Tem por função gerar um arquivo de nome “agenda.xml”, o qual
armazenará informações de empresas e de pessoas que possam atuar como
contatos dentro das mesmas: isto acontece por meio da invocação do método
público GerarXmlAgenda.

Listagem 5. Classe AgendaWriter

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace TesteLinqToXml
{
public static class AgendaWriter
{
private static XElement CriarElementoEmpresa(
string codigo,
string nome,
string cidade,
string estado)
{
return new XElement("Empresa",
new XAttribute("Codigo", codigo),
new XElement("Nome", nome),
new XElement("Cidade", cidade),
new XElement("Estado", estado));
}

private static XElement CriarElementoContato(


string nome,
string departamento,
string telefone,
string email)
{
return new XElement("Contato",
new XElement("Nome", nome),
new XElement("Departamento", departamento),
new XElement("Telefone", telefone),
new XElement("Email", email));
}

private static void AssociarContatosComEmpresa(


XElement empresa, params XElement[] contatos)
{
empresa.Add(new XElement("Contatos", contatos));
}

public static void GerarXmlAgenda()


{
XElement empresas = new XElement("Empresas");

XDocument xmldoc = new XDocument(


new XDeclaration("1.0", "utf-8", ""));
xmldoc.Add(empresas);

XElement acmesp = CriarElementoEmpresa(


"ACME-SP", "INDÚSTRIAS ACME LTDA.",
"São Paulo", "SP");
AssociarContatosComEmpresa(acmesp,
CriarElementoContato("JOSÉ DA SILVA", "VENDAS",
"(11) 4004-5005", "[email protected]"),
CriarElementoContato("JOÃO DE OLIVEIRA",
"MARKETING",
"(11) 4004-6006", "[email protected]"));
empresas.Add(acmesp);

XElement acmebh = CriarElementoEmpresa(


"ACME-BH", "INDÚSTRIAS ACME LTDA.",
"Belo Horizonte", "MG");
AssociarContatosComEmpresa(acmebh,
CriarElementoContato("MARIA MARTINS", "VENDAS",
"(31) 3003-4004", "[email protected]"));
empresas.Add(acmebh);

XElement linhas_aereasrj = CriarElementoEmpresa(


"LINHAS_AEREAS-RJ", "LINHAS AÉREAS BRASILEIRAS
S.A.",
"Belo Horizonte", "MG");
AssociarContatosComEmpresa(linhas_aereasrj,
CriarElementoContato("JOAQUIM REIS", "ATENDIMENTO",
"(21) 2002-3003",
"[email protected]"));
empresas.Add(linhas_aereasrj);

xmldoc.Save("agenda.xml");
}
}
}

GerarXmlAgenda está montando um arquivo XML a partir de uma instância


do tipo XDocument (variável xmldoc), invocando para isto o método Save. O
nome de arquivo informado não possui um caminho, de modo que com isto
está se esperando que o documento seja gerado no mesmo diretório em que se
encontra o executável.

A variável xmldoc conta com um elemento principal de nome Empresas


(gerado a partir de uma instância de XElement). Elementos-filhos (de nome
Empresa) também obtidos a partir de objetos XElement serão adicionados a
este elemento-pai.

O método CriarElementoEmpresa retorna como resultado uma instância do


tipo XElement, com esta última contendo informações que caracterizam uma
empresa e que foram geradas a partir de outros objetos XElement e de uma
instância de XAttribute (neste caso, um código identificador da empresa em
questão).

CriarElementoContato é um método que gera as informações em XML


referentes a um contato dentro de uma empresa, contando com um elemento
principal do tipo XElement, além de elementos-filhos desta mesma classe. Já
o método AssociarContatosComEmpresa vincula elementos que representam
contatos às empresas aos quais os mesmos estão relacionados, ou seja, é
estabelecida com isto uma ligação entre instâncias da classe XElement.

Prosseguindo com a implementação do projeto TesteLinqToXml, será criada


neste momento a classe Contato. Para isto deve-se clicar, dentro do Solution
Explorer, com o botão direito do mouse sobre o projeto TesteLinqToXml,
escolhendo-se em seguida no menu de atalho a opção Add, subopção New
Item. Neste momento será exibida a tela Add New Item (Figura 3); preencher
o campo Name com “Contato.cs”, a fim de se gerar o arquivo para
implementação do tipo Contato.

Figura 3. Criando o arquivo para implementação da classe Contato

Na Listagem 6 está a definição da classe Contato, a qual conterá dados como


nome do contato, departamento, telefone e e-mail. Todas essas características
de um contato serão implementadas através de propriedades correspondentes.

Listagem 6. Classe Contato

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TesteLinqToXml
{
public class Contato
{
public string Nome { get; set; }
public string Departamento { get; set; }
public string Telefone { get; set; }
public string Email { get; set; }
}
}

Continuando a construção do projeto de exemplo, será necessário proceder


agora com a criação da classe Empresa. Assim como aconteceu com a classe
Contato, deve-se clicar com o botão direito do mouse sobre o projeto
TesteLinqToXml, selecionando então Add > New Item. Aparecerá então a tela
Add New Item (Figura 4); o campo Name será preenchido com o texto
“Empresa.cs”, a fim de se gerar o arquivo para implementação da classe
Empresa.

Figura 4. Criando o arquivo para implementação da classe Empresa

Na Listagem 7 encontra-se a definição da classe Empresa.


Listagem 7. Classe Empresa

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TesteLinqToXml
{
public class Empresa
{
public string Codigo { get; set; }
public string Nome { get; set; }
public string Cidade { get; set; }
public string Estado { get; set; }

private List<Contato> _Contatos;

public List<Contato> Contatos


{
get { return _Contatos; }
}

public Empresa()
{
_Contatos = new List<Contato>();
}
}
}

A propriedade Contatos é somente leitura, retornando ao ser acessada uma


lista do tipo List contendo instâncias da classe Contato e que está vinculada ao
atributo privado _Contatos. Já a variável _Contatos é inicializada ao se criar
uma nova instância de Empresa, sendo que isto é feito a partir do construtor
desta classe.

List faz uso do tipo genérico List o qual, por sua vez, deriva de IEnumerable.
T representa, para a classe List e a interface IEnumerable, qualquer tipo válido
dentro do .NET Framework. No caso da classe Empresa, utilizou-se Contato
como tipo base para a definição da coleção em questão.

Por fim, deve-se gerar o tipo (AgendaReader) que efetuará a leitura do


arquivo XML e devolverá as informações de contatos presentes em tal
documento. Repetindo os mesmos procedimentos já realizados com as outras
3 classes, deverá ser adicionado um arquivo de nome “AgendaReader.cs” ao
projeto TesteLinqToXml conforme indicado na Figura 5.

Figura 5. Criando o arquivo para implementação da classe AgendaReader

A Listagem 8 apresenta a implementação da classe AgendaReader.

Listagem 8. Classe AgendaReader

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace TesteLinqToXml
{
public class AgendaReader
{
private XDocument _xmlAgenda;

private List<string> _CodigosEmpresas;

public List<string> CodigosEmpresas


{
get { return _CodigosEmpresas; }
}

public void Inicializar()


{
_xmlAgenda = XDocument.Load("agenda.xml");
_CodigosEmpresas =
(from e in _xmlAgenda.Element("Empresas")
.Elements("Empresa")
select e.Attribute("Codigo").Value).ToList();
}

public Empresa ObterInformacoesEmpresa(


string codigoEmpresa)
{
Empresa empresa =
(from e in _xmlAgenda.Element("Empresas")
.Elements("Empresa")
where e.Attribute("Codigo").Value == codigoEmpresa
select new Empresa()
{
Codigo = e.Attribute("Codigo").Value,
Nome = e.Element("Nome").Value,
Cidade = e.Element("Cidade").Value,
Estado = e.Element("Estado").Value
}).First();
empresa.Contatos.AddRange(
ObterContatosEmpresa(codigoEmpresa));

return empresa;
}

private List<Contato> ObterContatosEmpresa(


string codigoEmpresa)
{
var dadosEmpresa =
(from e in _xmlAgenda.Element("Empresas")
.Elements("Empresa")
where e.Attribute("Codigo").Value == codigoEmpresa
select e).First();

return
(from e in dadosEmpresa.
Element("Contatos").Elements("Contato")
select new Contato()
{
Nome = e.Element("Nome").Value,
Departamento = e.Element("Departamento").Value,
Telefone = e.Element("Telefone").Value,
Email = e.Element("Email").Value
}).ToList();
}
}
}

Dentro do método Inicializar do tipo AgendaReader é gerada uma nova


instância de XDocument, a partir da chamada ao método Load, passando-se
como parâmetro a este o nome do arquivo XML a ser carregado (não se
especificou um caminho, de forma que a aplicação buscará um arquivo no
diretório em que a mesma se encontra). Além disso, está sendo executada uma
query em LINQ, de maneira a se gerar uma lista de strings com todos os
códigos de empresa (atributo privado _CodigosEmpresas), com tal coleção
sendo retornada através da propriedade CodigosEmpresas.

Já o método ObterInformacoesEmpresa recebe como parâmetro um código de


empresa, retornando através de uma query escrita em LINQ um objeto do tipo
Empresa; para isto, está se partindo da variável _xmlAgenda e, por meio dos
métodos Element e Elements, navegando-se até os elementos XML de nome
Empresa. A cláusula where da consulta acessa o atributo Codigo de cada um
destes elementos, de maneira a se filtrar apenas a empresa cujo código
coincida ao valor informado como parâmetro.

O método ObterContatosEmpresa possui algumas similaridades com


ObterInformacoesEmpresa. O mesmo recebe como parâmetro um código de
empresa, realizando uma primeira consulta em LINQ para se obter os dados
XML da organização que se está buscando. Na sequência, uma nova consulta
LINQ é efetuada, selecionando-se via invocação dos métodos Element e
Elements elementos de nome Contato. Finalmente, a instrução select new
procede com a geração de instâncias do tipo Contato, acessando para isso
elementos XML (via propriedade Value de objetos XElement) que
correspondem às informações que caracterizam um contato.

Implementação das telas para


testes
Uma vez que o processo de codificação das classes contendo informações de
contatos tenha finalizado, deve-se prosseguir com a montagem do formulário
que permitirá a consulta a dados de contatos. Isto será feito clicando-se com o
botão direito do mouse sobre o projeto TesteLinqToXml, selecionando então
Add > New Item. Surgirá então a tela Add New Item (Figura 6); o campo
Name será preenchido com o texto “FormConsultaAgenda.cs”, a fim de se
gerarem os arquivos correspondentes ao formulário FormConsultaAgenda.

Figura 6. Criando o arquivo para implementação do formulário


FormConsultaAgenda

A Figura 7 equivale, em termos gerais, a um exemplo de como poderá ficar


tal formulário ao fim dos procedimentos mencionados nesta seção. Esta
imagem foi gerada dentro do Visual Studio, a partir do editor visual desta
ferramenta.
Figura 7. Formulário de consulta em modo Design com todos os controles já
configurados

Deverá ser alterado, por meio da janela Properties do Visual Studio, a


propriedade Text de FormConsultaAgenda para “Teste de utilização de LINQ
to XML - Consulta”.

Nota: Para efeitos de simplificação, serão omitidos deste artigo os valores de


propriedades de controles que definam tamanhos (Size, por exemplo) ou pos
icionamento (Location, por exemplo). O código-fonte da aplicação de exempl
o poderá ser baixado a partir do site da revista. Além disso, todos os tipos de
controles visuais aqui utilizados (Label, TextBox, GroupBox, DataGridView, Bu
tton) podem ser encontrados, dentro do Visual Studio, na seção “All Window
s Forms” da janela Toolbox.

Neste momento, será necessário adicionar ao formulário 2 controles do tipo


GroupBox (o primeiro na parte superior e o segundo na seqüência a este).
A Tabela 1 lista os conteúdos das propriedades Name e Text para cada
controle.

Propriedade Name Propriedade Text


grpDadosEmpresa Dados da Empresa
grpContatos Contatos
Tabela 1. Propriedades a serem preenchidas para controles dentro de
FormConsultaAgenda

No interior do controle grpDadosEmpresa deverão ser adicionados os


controles do tipo Label listados na Tabela 2. Dentro desta última já estão
definidos também os respectivos valores para as propriedades Name e Text de
cada componente. Importante ressaltar que tais controles funcionarão como
legendas para a exibição de informações obtidas a partir do uso de LINQ.

Propriedade Name Propriedade Text


lblSelecaoEmpresa Selecione um código de empresa:
lblNomeEmpresa Nome da Empresa
lblCidade Cidade
lblEstado Estado

Tabela 2. Labels a serem utilizados como legendas dentro de


grpDadosEmpresa

Completando o preenchimento do controle grpDadosEmpresa, deverão ser


adicionados a este GroupBox os componentes listados na Tabela 3. Estes
serão utilizados para exibir informações de empresas obtidas a partir de LINQ.
Todos os controles TextBox tiveram suas propriedades ReadOnly
configuradas como “true”.

Tipo de Controle Propriedade Name


ListBox lstSelecaoEmpresa
TextBox txtNomeEmpresa
TextBox txtCidade
TextBox txtEstado

Tabela 3. Labels que serão utilizados para exibição de informações de


empresas

Já dentro do GroupBox grpContatos (que teve sua propriedade Text


configurada para “Contatos”), será necessário adicionar um controle
DataGridView cuja propriedade Name será grdContatos.

Uma vez que as propriedades visuais do formulário tenham sido consideradas,


deve-se proceder com a implementação do código-fonte para a consulta a
dados que constam no XML Considerando que o arquivo
FormConsultaAgenda.cs esteja em modo Design, pode-se acessar para isto o
menu View e na sequência a opção Code; um procedimento equivalente a este
consiste em se pressionar a tecla F7.

Na Listagem 9 encontra-se a variável privada do tipo AgendaReader que


deverá ser declarada dentro das definições de FormConsultaAgenda.

Listagem 9. Declaração de variável privada dentro de FormConsultaAgenda

...

public partial class FormConsultaAgenda : Form


{
private AgendaReader _agenda;

...

Novamente com o arquivo FormConsultaAgenda.cs no modo Design no


Visual Studio, selecionar o formulário clicando em uma área na qual não
exista nenhum controle visual para, em seguida, acessar o botão Events da
janela Properties (o mesmo possui como ícone o desenho de um “raio”); a
partir disto, selecionar o evento Shown e no campo para digitação que se abre
efetuar um duplo clique. Este evento é executado na primeira vez que o
formulário for exibido, sendo que a implementação do mesmo consta
na Listagem 10. O objetivo do mesmo dentro de FormConsultaAgenda é
inicializar um objeto do tipo AgendaReader, de maneira que o mesmo será
utilizado para a consulta a informações de empresas e contatos. Além disso, o
ListBox que serve para a filtragem de dados de empresas tem seus valores
possíveis preenchidos através da invocação do método AddRange.

Listagem 10. Evento FormConsultaAgenda_Shown

...

private void FormConsultaAgenda_Shown(object sender,


EventArgs e)
{
_agenda = new AgendaReader();
_agenda.Inicializar();

lstSelecaoEmpresa.Items.AddRange(
_agenda.CodigosEmpresas.ToArray());
lstSelecaoEmpresa.SelectedIndex = -1;

}
...

Da mesma maneira que se configurou o evento Shown para o formulário (por


meio do botão Events da janela Properties), será necessário também definir o
evento SelectedIndexChanged para o controle lstSelecaoEmpresa. Este
procedimento tem por finalidade efetuar a pesquisa de informações e contatos
de empresas (via método ObterInformacoesEmpresa de AgendaReader) ao se
selecionar um código a partir do ListBox. Uma vez obtida uma instância do
tipo Empresa, as propriedades da mesma são utilizadas para o preenchimento
de dados da empresa em questão e dos contatos correspondentes (Listagem
11).

Listagem 11. Evento lstSelecaoEmpresa_SelectedIndexChanged

...

private void lstSelecaoEmpresa_SelectedIndexChanged(


object sender, EventArgs e)
{
Empresa empresa = _agenda.ObterInformacoesEmpresa(
lstSelecaoEmpresa.SelectedItem.ToString());

txtNomeEmpresa.Text = empresa.Nome;
txtCidade.Text = empresa.Cidade;
txtEstado.Text = empresa.Estado;

grdContatos.DataSource = empresa.Contatos;
grdContatos.Columns["Nome"].Width = 200;
grdContatos.Columns["Email"].Width = 200;
}

...

Concluída a implementação do formulário de consulta à agenda de contatos,


será preciso renomear o formulário principal da aplicação. Isto é feito, dentro
da janela Solution Explorer, clicando-se com o botão direito sobre o arquivo
Form1.cs e selecionando a opção Rename: altera-se então tal nome de arquivo
para FormPrincipal.cs. Tal procedimento fará com que o nome da classe que
corresponde ao formulário principal da aplicação passe a ser FormPrincipal.
Além disso, alterar por meio da janela Properties do Visual Studio a
propriedade Text de FormPrincipal para “Teste de utilização de LINQ to
XML”.
Constarão dentro de FormPrincipal os controles do tipo Button mencionados
na Tabela 4, na qual foram listados ainda os conteúdos das propriedades
Name e Text para tais componentes.

Propriedade Name Propriedade Text


btnGerarArquivo Gerar Arquivo de Contatos
btnCarregarArquivo Carregar Arquivo de Contatos
btnSair Sair

Tabela 4. Controles a serem configurados em FormPrincipal

Para gerar o método que implementará o evento Click do botão


btnGerarArquivo existem dois caminhos possíveis:

• Efetuando-se um duplo clique sobre o botão btnGerarArquivo, com o


arquivo FormPrincipal.cs em modo Design dentro do Visual Studio;

• Com o arquivo FormPrincipal.cs no modo Design no Visual Studio,


selecionar o botão btnGerarArquivo e, em seguida, acessar o botão Events da
janela Properties (o mesmo possui como ícone o desenho de um “raio”); a
partir disto, selecionar o evento Click e no campo para digitação que se abre
efetuar um duplo clique.

Em ambas as situações será gerado um método de nome


btnGerarArquivo_Click, o qual corresponde à implementação do evento Click
para o botão btnGerarArquivo (Listagem 12). Dentro de
btnGerarArquivo_Click invoca-se a operação GerarXmlAgenda do tipo
AgendaWriter, com esta última sendo responsável por gerar o arquivo XML
empregando recursos de LINQ to XML (conforme já especificado
anteriormente). Ao término da montagem do arquivo, uma mensagem é
exibida ao usuário por meio do método Show de MessageBox.

Listagem 12. Evento btnGerarArquivo_Click

...

private void btnGerarArquivo_Click(object sender, EventArgs e)


{
AgendaWriter.GerarXmlAgenda();
MessageBox.Show("Arquivo XML de agenda gerado com sucesso!");
}

...
Já o botão btnCarregarArquivo tem por objetivo exibir a tela de consulta às
informações da agenda. Para isto, o formulário invocado necessitará do
arquivo agencia.xml, sendo que o mesmo só será exibido caso este documento
realmente exista no diretório em que se encontra a aplicação de testes
(Listagem 13): esta checagem é feita por meio do método Exists da classe
File (namespace System.IO). Ao final do evento Click, caso não existam
restrições, o formulário FormConsultaAgenda é acionado por meio do método
ShowModal.

Listagem 13. Evento btnCarregarArquivo_Click

...

private void btnCarregarArquivo_Click(object sender, EventArgs e)


{
if (!File.Exists("agenda.xml"))
{
MessageBox.Show("Arquivo XML de agenda não encontrado!");
return;
}

FormConsultaAgenda formConsulta = new FormConsultaAgenda();


formConsulta.ShowDialog();
}

...

O botão “Sair”, representado dentro de FormPrincipal pelo controle btnSair,


também deverá ter seu evento Click configurado, a fim de que dentro deste
último se feche o formulário de testes, encerrando a aplicação. A
implementação de tal evento se faz através do mesmo procedimento adotado
com os outros dois controles Button, sendo que o método btnSair_Click
(Listagem 14) será gerado como resultado desta ação. No interior de
btnSair_Click invoca-se o método Close, definido na classe básica Form (da
qual FormPrincipal herda): é esta instrução que fará com que o formulário de
testes seja fechado.

Listagem 14. Evento btnSair_Click

...

private void btnSair_Click(object sender, EventArgs e)


{
Close();
}

...

A Figura 8 apresenta a estrutura do projeto TesteLinqToXml ao término da


implementação das classes que constituem o mesmo.

Figura 8. Estrutura do projeto TesteLinqToXml

Executando a aplicação de testes


A execução do projeto TesteLinqToXml pode ser feita, dentro do Visual
Studio, acessando-se o menu Debug, opção Start Debugging. Outra forma de
se chegar a isto é utilizando a tecla de atalho F5 dentro da IDE do Visual
Studio. Uma vez que esta ação tenha sido disparada, será exibida a tela
indicada pela Figura 9.
Figura 9. Tela inicial que é exibida ao se executar o projeto
TesteLinqToXML

Ao se clicar no botão “Gerar Arquivo de Contatos”, será exibida a mensagem


indicada na Figura 10 caso a geração do documento XML de contatos
aconteça normalmente. Já na Figura 11 consta um exemplo de como será o
arquivo resultante.

Figura 10. Geração com sucesso de arquivo XML


Figura 11. Arquivo XML contendo contatos

A execução da opção “Carregar Arquivo de Contatos” terá como resultado a


exibição do formulário de consulta à agenda. Dentro deste último, a seleção de
um código de empresa carregará informações e contatos da mesma (Figura
12).

Já a Figura 7 demonstra um exemplo de consulta que foi efetuada no


formulário de testes. Digitou-se o texto “EN” no campo “Texto a ser
pesquisado”, retornando-se como resultado da pesquisa apenas produtos cujos
nomes possuem esta sequência de caracteres em seus respectivos conteúdos.
Figura 12. Consulta a informações de contatos que estão em XML

Conclusão
O uso de XML está disseminado pelos mais variados tipos de aplicações de
software. Arquivos neste formato constituem um importante meio de
integração entre sistemas. Diante de fatos como este, é mais do que certo que
o desenvolvimento de novas soluções computacionais envolva, de alguma
forma, a utilização de informações neste padrão.

LINQ to XML é um recurso que integra o .NET Framework, disponibilizando


diversas opções que buscam facilitar tarefas envolvendo a manipulação de
XML. Do modo como este mecanismo foi estruturado é possível, inclusive,
que queries escritas em LINQ to Objects sejam aplicadas sobre agrupamentos
de elementos XML. A combinação destas duas técnicas pode em muito
simplificar a leitura de informações em XML. Logo, pode-se considerar como
um dos grandes benefícios do uso de LINQ to XML a possibilidade de se
obterem, através da sua aplicação, construções de código mais enxutas e, por
consequência direta disto, mais fáceis de serem compreendidas e mantidas.
Links

LINQ
http://msdn.microsoft.com/en-us/netframework/aa904594

LINQ to XML
http://msdn.microsoft.com/en-us/library/bb387098.aspx

por Renato Jose


Guru .net e tecnologias MS

Introdução ao Data Bindin


g no WPF
O artigo apresenta o recurso de Data
Binding presente na tecnologia WPF -
Windows Presentation Foundation, sua
utilização básica na criação de interfaces de
usuário para facilitar o vínculo dos dados
apresentados, reduzindo o código fonte do
aplicativo, tornando-o mais enxuto e
elegante.
De que se trata o artigo

O artigo apresenta o recurso de Data Binding presente na tecnologia WPF –


Windows Presentation Foundation, sua utilização básica na criação de
interfaces de usuário para facilitar o vínculo dos dados apresentados,
reduzindo o código fonte do aplicativo, tornando-o mais enxuto e elegante. O
Data Binding pode ser utilizado para somente visualizações, como interações
com Banco de Dados, coleções, elementos da própria interface de usuário ou
propriedades de classes.

Em que situação o tema é útil

O Data Binding é útil para criar projetos de softwares mais flexíveis, aplicar
conceitos de vínculo de dados, possibilitar um desenvolvimento mais
produtivo e com códigos mais enxutos. Elimina a necessidade de se escrever
dezenas de linhas de código para apresentar dados ao usuário, recuperar
alterações e enviar a uma classe de acesso a dados, por exemplo.

Introdução ao Data Binding no WPF

O artigo inicia com a definição do que é o Data Binding no contexto da


tecnologia WPF, para que é usado, quais seus benefícios. Posteriormente são
apresentadas as formas possíveis de utilização do Data Binding. Durante a
apresentação dos conceitos do Data Binding são mostrados pequenos trechos
de código com exemplos da aplicação do conceito. Na parte prática, veremos
um exemplo de uso de Data Binding com banco de dados e Entity Framework.

O Data Binding não é uma total novidade para os desenvolvedores .NET. Ele
tem acompanhado e auxiliado muito no desenvolvimento de aplicativos em
Windows Forms e também ASP.NET, porém em WPF ele foi melhorado
muito em questão de funcionalidades e performance. Seu conceito básico
ainda é o mesmo: vincular dados de uma fonte para um destino, ou seja, ao
contrário de você ter que alimentar seus controles na interface de usuário um a
um via código, ou então percorrer coleções via código e jogar dados em um
ListView ou DataGrid, o Data Binding permite que você apenas informe de
onde ele deve obter o valor para ser alimentado em algum lugar específico.

Imagine que você tenha uma ListView em seu formulário e você possui em
seu código uma coleção de dados em memória. Ao invés de percorrer esta
coleção criando um ListViewItem para cada iteração percorrida, você possa
fazer algo mais prático como simplesmente dizer: “ListView, obtenha seus
itens daqui, mantenha seus valores atualizados e formate-os para ficar assim.”.
O Data Binding fornece esta funcionalidade e muito mais ainda.
O Data Binding possui como sua classe principal a Binding, que é responsável
por vincular as propriedades do objeto de fonte com as propriedades do objeto
de destino de forma a manter um canal de comunicação aberto entre estes,
permitindo a sincronização de dados e atualização de um objeto a partir do
outro conforme configuração definida.

Data Binding via código fonte


Apesar do XAML ser a codificação mais importante em WPF, o Data Binding
não é exclusivo dele, podendo ser utilizado no código fonte normalmente.
Vamos supor que tenhamos um TreeView em nosso formulário principal
chamado treeView e abaixo dele tenhamos um TextBlock. Agora desejamos
que no momento em que for selecionado um item na TreeView seu texto seja
visualizado no TextBlock. Para implementarmos esta funcionalidade,
utilizaremos o Data Binding via código fonte (C#).

Para o melhor entendimento, na Listagem 1 está apresentada a codificação do


formulário com os controles mencionados já adicionados e formatados.

Listagem 1. Formulário MainWindow.xaml – Código XAML

01 <Window x:Class="ListBoxBinding.MainWindow"
02
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
03 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
04 Title="MainWindow" Height="350" Width="525">
05 <Grid>
06 <Grid.RowDefinitions>
07 <RowDefinition Height="*" />
08 <RowDefinition Height="*" />
09 </Grid.RowDefinitions>
10 <TreeView x:Name="treeView" Margin="20">
11 <TreeViewItem Header="Item Pai 1">
12 <TreeViewItem Header="Item Filho 1" />
13 <TreeViewItem Header="Item Filho 2" />
14 <TreeViewItem Header="Item Filho 3" />
15 </TreeViewItem>
16 <TreeViewItem Header="Item Pai 2">
17 <TreeViewItem Header="Item Filho 4" />
18 </TreeViewItem>
19 <TreeViewItem Header="Item Pai 3" />
20 </TreeView>
21 <TextBlock x:Name="textBlock" Grid.Row="1" Height="20"
Width="100"
22 HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="20,10"/>
23 </Grid>
24 </Window>

Na inicialização do nosso formulário padrão, no código fonte (C#) após a


chamada do método InitializeComponent() podemos implementar o vínculo
conforme informado na Listagem 2.

Listagem 2. Criando o Data Binding

01 public partial class MainWindow : Window


02 {
03 public MainWindow()
04 {
05 InitializeComponent();
06 //Criando o objeto binding
07 Binding binding = new Binding();
08 //Informando o objeto fonte.
09 binding.Source = treeView;
10 //Informando a propriedade do objeto fonte que será
vinculada.
11 binding.Path = new PropertyPath("SelectedItem.Header");
12 //Informando no objeto de destino, a propriedade que
será
13 //alimentada conforme a propriedade fonte, e que o fará.
14 textBlock.SetBinding(TextBlock.TextProperty, binding);
15 }
16 }

Como pode ser verificado no código da Listagem 2, inicialmente é criada a


instância da classe Binding que será responsável por vincular os dados entre
os controles da tela. Após temos a informação da propriedade Source do
objeto binding que informa a fonte de dados a ser pesquisada, de onde vamos
ler o valor que queremos vincular a outro controle. Nesta propriedade
podemos vincular qualquer objeto do .NET, incluindo coleções, arquivos
XML ou classes que contenham acesso a banco de dados.

Temos na linha 11 a alimentação da propriedade Path. Esta propriedade é


onde informamos qual informação do item fonte desejamos verificar / buscar /
vincular. Em nosso caso, estamos vinculando a propriedade
SelectedItem.Header a qual retorna o texto do nosso item selecionado na
TreeView.
Até este ponto configuramos o nosso objeto binding com o objeto fonte, ou
origem, porém ainda nos resta informar o objeto e a propriedade de destino a
qual será vinculada esta propriedade de origem. Para isto temos em apenas
uma linha (14) o código necessário. O controle TextBlock, assim como os
demais controles visuais do WPF, possui o método chamado SetBinding o
qual nos permite fazer o vínculo de uma determinada propriedade deste objeto
com um Binding, que por sua vez deverá estar já alimentado com as
propriedades do objeto fonte (Source e Path).

O primeiro parâmetro que temos para este método é a DependencyProperty,


que é um tipo de propriedade específica definida no controle, possui a
característica de manter o vínculo com outra propriedade e manter o
sincronismo de seus dados através de uma “notificação de alteração”. O
segundo parâmetro é o próprio objeto binding, o qual contém as informações
do objeto e propriedade fonte a serem verificadas.

Após ter realizado este vínculo, ao executarmos o nosso formulário e


selecionarmos um item do TreeView, o TextBlock apresentará o texto
correspondente ao item selecionado.

Data Binding via XAML


Já vimos como podemos implementar o Data Binding via código fonte de
nossa aplicação. No entanto, o Data Binding poderia ser implementado sem a
necessidade de nenhum código fonte C# informado. A implementação do
Data Binding via XAML é muito simples e fácil de ser feita. Vamos tomar o
mesmo exemplo apresentado anteriormente e vamos excluir todo o código
implementado no fonte do nosso formulário. Agora vamos ao arquivo XAML
incluir o Data Binding nele, conforme pode ser verificado na Listagem 3.

Listagem 3. Criando o Data Binding via XAML

01 <Window x:Class="ListBoxBinding.MainWindow"
02
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
03 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
04 Title="MainWindow" Height="350" Width="525">
05 <Grid>
06 <Grid.RowDefinitions>
07 <RowDefinition Height="*" />
08 <RowDefinition Height="*" />
09 </Grid.RowDefinitions>
10 <TreeView x:Name="treeView" Margin="20">
11 <TreeViewItem Header="Item Pai 1">
12 <TreeViewItem Header="Item Filho 1" />
13 <TreeViewItem Header="Item Filho 2" />
14 <TreeViewItem Header="Item Filho 3" />
15 </TreeViewItem>
16 <TreeViewItem Header="Item Pai 2">
17 <TreeViewItem Header="Item Filho 4" />
18 </TreeViewItem>
19 <TreeViewItem Header="Item Pai 3" />
20 </TreeView>
21 <TextBlock x:Name="textBlock" Grid.Row="1" Height="20"
Width="100"
22 HorizontalAlignment="Left"
VerticalAlignment="Top"
23 Margin="20,10"
24 Text="{Binding ElementName=treeView,
Path=SelectedItem.Header}"/>
25 </Grid>
26 </Window>

Vejam como é muito simples e prático utilizar o Data Binding no XAML. Em


apenas uma linha adicionada ao arquivo (linha 24, em negrito) conseguimos
eliminar 4 linhas do exemplo anterior e não ter nada a mais no código fonte do
formulário.

Devemos sempre vincular o Binding na propriedade de destino, ou seja, que


receberá o valor da propriedade de origem. Para implementar o Binding
devemos abrir uma “chave” assim como fizemos com métodos em C#,
incluindo a declaração Binding que se analisarmos é o nome da classe que
utilizamos no código fonte no exemplo anterior. Após declarar o Binding
podemos perceber uma pequena diferença entre a ligação criada no código
fonte C# com a versão em XAML, que é a propriedade ElementName. Nesta
propriedade devemos alimentar o nome do objeto de origem ao qual queremos
vincular. Já a opção Path tem o objetivo de informar qual propriedade do
objeto (controle) de origem será lida, que em nosso caso é a propriedade
SelectedItem.Header. Então finalizamos o Binding fechando a “chave”.

Mas por que no código fonte usamos a propriedade Source e no XAML


usamos a propriedade ElementName? Na verdade a propriedade
ElementName é o método mais simples que é disponibilizado
declarativamente para o XAML em WPF, mas também temos a possibilidade
de utilizar a propriedade Source, porém esta somente é possível no WPF 4,
introduzido com o .NET Framework 4. Veja no código da Listagem 4 a
utilização do Binding com a propriedade Source. A propriedade
ElementName permite realizar a ligação com um elemento presente no
XAML de uma forma mais fácil.

Listagem 4. Data Binding com a propriedade Source

01 Text="{Binding Source={x:Reference treeView},


Path=SelectedItem.Header}"/>

Para utilizar o Binding com a propriedade Source você deverá ter informado a
propriedade x:Name da TreeView, pois caso você tenha informado o nome
através da propriedade Name apenas, na compilação de seu formulário você
receberá uma exception informando que o provider não conseguiu encontrar o
objeto com o nome especificado.

Data Binding com classes de


domínio
Até este ponto vimos como utilizar o Data Binding para vincular controles de
formulários em WPF, porém muitas vezes o que temos que vincular a um
controle do formulário não é outro controle, e sim dados provenientes de
outras classes que não são nativas do .NET, ou seja, classes que nós mesmos
criamos para abstrair informações que desejamos controlar em nosso sistema,
também conhecidas como classes de domínio, ou ainda, classes de negócio.

Podemos vincular qualquer dado através do Data Binding. Vamos supor que
temos uma classe chamada Produto em nossa aplicação conforme a Listagem
5. Ainda em nossa aplicação, temos um formulário básico conforme Figura 1,
o qual contém o código XAML da Listagem 6, onde são apresentadas as
informações detalhadas de cada Produto. Para fins de exemplo, no evento de
inicialização do nosso formulário vamos criar um novo produto para
podermos vincular os dados. Em uma aplicação real você provavelmente faria
a chamada de um método de consulta de um produto a partir de uma coleção
filtrando pelo código do mesmo, por exemplo. O código da instância do nosso
novo Produto é apresentado na Listagem 7.

Tendo nosso ambiente preparado, podemos vincular os dados do nosso objeto


produto no formulário. Temos várias possibilidades de realizar esta tarefa,
mas vamos abordar a propriedade DataContext de nosso formulário a qual
acredito ser a mais prática. Na Listagem 8 temos o vínculo dos dados através
do Data Binding, utilizando sintaxe já conhecida no XAML, a qual não difere
muito de um vínculo com outros controles, com a principal diferença que não
estamos informando o objeto de origem e apenas a propriedade que será
vinculada em cada TextBox.
Listagem 5. Classe Produto

01 public class Produto


02 {
03 public int Código { get; set; }
04 public string Nome { get; set; }
05 public float Valor { get; set; }
06 public float QuantidadeEstoque { get; set; }
07 }

Figura 1. Formulário Produto

Listagem 6. Código XAML - Formulário Produto

01 <Window x:Class="ListBoxBinding.frmProduto"
02
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
03 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
04 Title="Produto" Height="300" Width="400">
05 <Grid>
06 <Grid.RowDefinitions>
07 <RowDefinition Height="35" />
08 <RowDefinition Height="35" />
09 <RowDefinition Height="35" />
10 <RowDefinition Height="35" />
11 <RowDefinition Height="35" />
12 <RowDefinition Height="*" />
13 </Grid.RowDefinitions>
14 <Grid.ColumnDefinitions>
15 <ColumnDefinition Width="130" />
16 <ColumnDefinition Width="*" />
17 </Grid.ColumnDefinitions>
18 <TextBlock Text="Código:" Grid.Column="0" Grid.Row="0"
Margin="5"
19 HorizontalAlignment="Left"
VerticalAlignment="Center" />
20 <TextBlock Text="Nome:" Grid.Column="0" Grid.Row="1"
Margin="5"
21 HorizontalAlignment="Left"
VerticalAlignment="Center"/>
22 <TextBlock Text="Valor:" Grid.Column="0" Grid.Row="2"
Margin="5"
23 HorizontalAlignment="Left"
VerticalAlignment="Center" />
24 <TextBlock Text="Quantidade Estoque:" Grid.Column="0"
Grid.Row="3" Margin="5"
25 HorizontalAlignment="Left"
VerticalAlignment="Center" />
26 <TextBox x:Name="txtCodigo" Grid.Column="1" Grid.Row="0"
27 HorizontalAlignment="Left"
VerticalAlignment="Center"
28 Margin="5" Width="100" />
29 <TextBox x:Name="txtNome" Grid.Column="1" Grid.Row="1"
30 HorizontalAlignment="Left"
VerticalAlignment="Center"
31 Margin="5" Width="220" />
32 <TextBox x:Name="txtValor" Grid.Column="1" Grid.Row="2"
33 HorizontalAlignment="Left"
VerticalAlignment="Center"
34 Margin="5" Width="75" />
35 <TextBox x:Name="txtQtd" Grid.Column="1" Grid.Row="3"
36 HorizontalAlignment="Left"
VerticalAlignment="Center"
37 Margin="5" Width="75" />
38 </Grid>
39 </Window>

Listagem 7. Criando um novo Produto

01 public partial class frmProduto : Window


02 {
03 Produto produto;
04 public frmProduto()
05 {
06 InitializeComponent();
07 produto = new Produto();
08 produto.Código = 1;
09 produto.Nome = "Camiseta";
10 produto.Valor = 35;
11 produto.QuantidadeEstoque = 20;
12 }
13 }

Listagem 8. Adicionando o Binding nos TextBoxes

01 <TextBox x:Name="txtCodigo" Grid.Column="1" Grid.Row="0"


02 HorizontalAlignment="Left" VerticalAlignment="Center"
03 Margin="5" Width="100" Text="{Binding Path=Código}" />
04 <TextBox x:Name="txtNome" Grid.Column="1" Grid.Row="1"
05 HorizontalAlignment="Left" VerticalAlignment="Center"
06 Margin="5" Width="220" Text="{Binding Path=Nome}" />
07 <TextBox x:Name="txtValor" Grid.Column="1" Grid.Row="2"
08 HorizontalAlignment="Left" VerticalAlignment="Center"
09 Margin="5" Width="75" Text="{Binding Path=Valor}" />
10 <TextBox x:Name="txtQtd" Grid.Column="1" Grid.Row="3"
11 HorizontalAlignment="Left" VerticalAlignment="Center"
12 Margin="5" Width="75" Text="{Binding
Path=QuantidadeEstoque}" />

Podemos verificar na Listagem 8 que estamos informando as propriedades de


nossa classe Produto na propriedade Path do Data Binding, assim como
quando informamos propriedades de outro controle nos exemplos anteriores.
Já temos as propriedades de nossa classe vinculadas aos TextBoxes, porém
está faltando apenas informar de que objeto serão buscadas estas
propriedades. Neste ponto é onde utilizaremos a propriedade DataContext.

DataContext serve para atribuir uma fonte de dados comum a todos os


controles filhos de um determinado container. Em nosso caso, por exemplo,
podemos verificar que todos os TextBoxes contidos dentro da Grid estão se
referindo às propriedades do mesmo objeto fonte, que para nós é o objeto
produto criado no evento de inicialização do formulário. Para não precisarmos
informar para cada TextBox de onde deverá buscar a propriedade, podemos
informar a propriedade DataContext de nosso formulário, assim
compartilhando o objeto fonte com todos os filhos da mesma. Na Listagem
9 podemos verificar a alimentação da propriedade DataContext de nosso
formulário com o objeto produto que é o fonte. Esta alimentação é realizada
no construtor de nosso formulário.

Listagem 9. Alimentando o DataContext


01 public frmProduto()
02 {
03 InitializeComponent();
04 produto = new Produto();
05 produto.Código = 1;
06 produto.Nome = "Camiseta";
07 produto.Valor = 35;
07 produto.QuantidadeEstoque = 20;
08 this.DataContext = produto;
09 }

Após termos realizado a atribuição do DataContext, podemos executar nosso


código e o formulário já estará com os dados do produto exibidos e
vinculados. Como o DataContext utilizado é o do formulário, sempre que
você instanciar um Binding sem informar o Source ou ElementName o WPF o
considerará como o source (fonte). Caso você deseje ter mais de um objeto
fonte em um formulário, poderá especificar em qual controle será alimentado
o DataContext. Por exemplo, se você desejar vincular o objeto produto
somente no TextBox txtCodigo poderá fazê-lo informando somente em sua
propriedade DataContext o objeto produto e não na propriedade do
formulário, como apresentamos no exemplo, e assim com qualquer elemento
ou controle em seu formulário.

O Data Binding também permite uma configuração de atualização de dados


entre o objeto fonte e o objeto de destino. Podemos informar quatro tipos
(Modos) de configuração de sincronização de dados entre os objetos
vinculados, são eles:

• OneWay: Quando informada esta opção a propriedade de origem (source)


atualiza a propriedade de destino (target). Se em nosso exemplo alterarmos
uma propriedade do objeto produto e esta forma de sincronização estiver
habilitada, a propriedade de destino (Text do TextBox) será atualizada
automaticamente. Porém o contrário não acontece, quando a propriedade de
destino for alterada a propriedade fonte não será atualizada com o novo valor.
Esta opção é interessante para definir propriedades somente leitura;

• TwoWay: Esta forma faz com que qualquer alteração, independente de ser
na propriedade fonte ou na propriedade destino, implica na atualização da
outra. Mantém seus objetos sempre sincronizados com os mesmos valores de
propriedades (as vinculadas);

• OneWayToSource: É o mesmo que atribuir a opção OneWay de forma


inversa. Neste caso somente é atualizada a propriedade fonte quando a
propriedade destino é alterada, o contrário não é verdadeiro;
• OneTime: Esta opção tem o mesmo comportamento da opção OneWay,
porém mais simplificada, pois somente atualiza a informação da propriedade
de destino uma vez e depois não realiza mais atualizações.

Estas definições de atualizações de propriedades são atribuídas conforme


a Listagem 10.

Listagem 10. Atribuindo o Mode

01 <TextBox x:Name="txtCodigo" Grid.Column="1" Grid.Row="0"


02 HorizontalAlignment="Left" VerticalAlignment="Center"
03 Margin="5" Width="100" Text="{Binding Path=Código,
Mode=OneWay}" />

Data Binding com coleções


Mais uma funcionalidade importante que podemos verificar no Data Binding é
a possibilidade de utilizarmos ele em objetos de coleções, como List, para que
possamos vincular a um controle que possua uma característica deste tipo de
apresentação de dados, como por exemplo, um DataGrid.

Para vincularmos os dados de uma coleção para ser apresentada em um


controle, o princípio é o mesmo, basta informarmos um objeto fonte para o
controle da coleção de dados. Na Listagem 11 temos um DataGrid em nosso
formulário. Neste DataGrid desejamos apresentar uma coleção (List) de
objetos baseados em nossa classe Produto. Para criar a nossa lista temos o
código informado na Listagem 12. Para facilitar a criação de uma lista e
incluir dados, foi adicionado o método preencheLista(), o qual adiciona 10
produtos à nossa lista.

Se desejarmos apenas apresentar os dados de forma que o WPF organize


automaticamente os dados em nossa DataGrid, basta alimentarmos a
propriedade ItemSource do mesmo com o objeto de nossa coleção. Esta seria
a forma mais simples de implementar um Data Binding de forma automática.
Note que para permitir o DataGrid criar as colunas de forma automática,
temos que informar a propriedade AutoGenerateColumns com valor True.

Listagem 11. Adicionando o DataGrid

<Window>
...
<Grid>
...
<DataGrid x:Name="dataGrid" Grid.Row="4" Grid.ColumnSpan="2"
AutoGenerateColumns="True"
IsReadOnly="True">
</DataGrid>
</Grid>
</Window>

Listagem 12. Criando e preenchendo a Lista de Produtos

01 public partial class frmProduto : Window


02 {
03 public Produto produto;
04 public List<Produto> produtos;
05 public frmProduto()
06 {
07 InitializeComponent();
08 produto = new Produto();
09 produto.Código = 1;
10 produto.Nome = "Camiseta";
11 produto.Valor = 35;
12 produto.QuantidadeEstoque = 20;
13 this.DataContext = produto;
14 preencheLista();
15 dataGrid.ItemsSource = produtos;
16 }
17 public void preencheLista()
18 {
19 produtos = new List<Produto>();
20 for (int i = 1; i < 11; i++)
21 {
22 Produto p = new Produto()
23 {
24 Código = i,
25 Nome = "Produto " + i.ToString(),
26 Valor = float.Parse((i*5).ToString()),
27 QuantidadeEstoque =
float.Parse((i*2).ToString())
28 };
29 produtos.Add(p);
30 }
31 }
32 }
Porém o que acontece em muitos casos é que não desejamos visualizar todos
os dados de nossa classe no DataGrid e desta forma podemos utilizar o Data
Binding para nos auxiliar a vincular os dados (propriedades) que realmente
desejamos visualizar. A Listagem 13 mostra como apresentar o código e o
nome de cada produto da lista. Neste caso, como estamos definindo as colunas
que queremos em nosso DataGrid, devemos informar a propriedade
AutoGenerateColumns com valor False, caso contrário, o DataGrid irá criar as
colunas que definimos mais as colunas para cada propriedade da classe
Produto.

Listagem 13. Definindo propriedades com Binding

01 <DataGrid x:Name="dataGrid" Grid.Row="4" Grid.ColumnSpan="2"


AutoGenerateColumns="False"
02 IsReadOnly="True">
03 <DataGrid.Columns>
04 <DataGridTextColumn Binding="{Binding Path=Código}"
Header="Código" />
05 <DataGridTextColumn Binding="{Binding Path=Nome}"
Header="Nome" />
06 </DataGrid.Columns>
07 </DataGrid>

Agora que já vimos todos os fundamentos relativos ao uso de Data Binding,


vamos a um exemplo mais prático e funcional, usando banco de dados.

Projeto de exemplo
Antes de começarmos, para este exemplo prático, vamos utilizar o banco de
dados VentoNorte, o qual já foi muitas vezes utilizado nos artigos aqui da
Devmedia. Este banco de dados é uma versão brasileira para o banco de dados
padrão do SQL Server, o Northwind, com estruturação em português. O banco
se encontra junto com o código fonte para download deste artigo.

Este projeto de exemplo que iremos desenvolver terá como objetivo


apresentar uma lista de produtos gravados na base de dados. Ao selecionarmos
um dos produtos da lista, apresentaremos os detalhes do mesmo.

Primeiramente crie um novo projeto no Visual Studio. Estou utilizando o


Visual Studio 2010, porém pode ser utilizado o Visual Studio 2008, assim
como suas versões Express Edition. Utilizaremos o template WPF
Application, então selecione este na lista de templates e nomeie seu projeto a
seu critério, conforme Figura 2.
Figura 2. Template de projeto

Após a inicialização de nosso projeto no Visual Studio teremos o nosso


formulário MainWindow.xaml apresentado na tela, conforme Figura 3. Antes
de iniciarmos a criação de nosso formulário vamos adicionar em nosso projeto
um modelo para conexão com o banco de dados VentoNorte. Para esta tarefa
tornar-se mais simples e também produtiva, iremos utilizar o Entity
Framework para gerar nosso modelo de acesso a dados. Então, sobre o nome
do projeto, na Solution Explorer, clique com o botão direito do mouse e
selecione a opção Add > New Item. O Visual Studio apresentará a tela para
seleção do novo item que desejamos incluir. Na parte esquerda da tela,
selecione a opção Data, e então na parte direita estará listada a opção
ADO.NET Entity Data Model. Selecione-a e dê o nome de VentoNorte (ou
qualquer outro como preferir), conforme Figura 4.
Figura 3. Formulário Padrão MainWindow.xaml

Figura 4. Adicionando um Entity Data Model

Neste ponto o Wizard do Entity Framework será iniciado e apresentará duas


opções para gerar o modelo. No nosso exemplo iremos utilizar a opção
Generate from database, a qual gera o modelo com base em um banco de
dados já existente (Figura 5). Selecione esta opção e clique em Next. O
próximo passo é criarmos uma conexão com o banco de dados, para isto
selecione a opção New Connection. Agora, precisamos informar o endereço
de nosso servidor de banco de dados SQL Server (no meu caso é um servidor
local) e o nome de nossa base de dados que é VentoNorte (Figura 6). Para ter
certeza de sua configuração, clique na opção Test Connection. Se os dados
inseridos estiverem corretos, você receberá a mensagem Test connection
succeeded, conforme Figura 7. Caso tenha configurado corretamente, clique
em OK. Agora retornamos para a tela do Wizard, onde a ConnectionString é
apresentada e é mostrada a opção “Save entity connection sttings in
App.Config as”, que quando marcada salvará a nossa connection String no
arquivo de configuração App.Config com o nome especificado na caixa de
texto. Podemos deixar marcado com o valor sugerido pelo Visual Studio
(Figura 8). Clique em Next.

Figura 5. Wizard para criação do Entity Data Model


Figura 6. Propriedades de conexão

Figura 7. Teste de conexão


Figura 8. Configurando o acesso a dados

Agora o Wizard apresentará a lista das tabelas presentes no banco VentoNorte


e solicitará quais desejamos conectar. Em nosso exemplo iremos utilizar
apenas a tabela Produtos, conforme demonstrado na Figura 9. Para concluir o
assistente e gerar nosso modelo, clique em Finish. Neste momento temos em
nossa Solution Explorer o arquivo VentoNorte.edmx adicionado, o qual será
nosso modelo de acesso a dados.
Figura 9. Selecionando as tabelas do banco de dados

Preparando a interface de usuário


Nosso próximo passo é configurar a interface com o usuário, a tela. No
formulário MainWindow.xaml ajuste a propriedade Title colocando como
título da tela Lista de Produtos. Neste nosso formulário iremos incluir uma
ListBox para apresentar todos os produtos da base de dados e ao lado da
ListBox, os campos detalhados para apresentação de um produto, conforme
será selecionado na ListBox. Na Listagem 14 temos todo o código XAML do
formulário.

Listagem 14. Configurando o formulário

01 <Window x:Class="DataBindingBasico.MainWindow"
02
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
03 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
04 Title="Lista de Produtos" Height="350" Width="525">
05 <Grid>
06 <Grid.ColumnDefinitions>
07 <ColumnDefinition />
08 <ColumnDefinition Width="2*" />
09 </Grid.ColumnDefinitions>
10 <ListBox Margin="10" ItemsSource="{Binding Path=Produtos}"
Name="lstProdutos"
11 HorizontalAlignment="Stretch" Grid.Column="0"
12 SelectionChanged="lstProdutos_SelectionChanged">
13 <ListBox.ItemTemplate>
14 <DataTemplate>
15 <StackPanel Orientation="Horizontal">
16 <TextBlock Text="{Binding Path=ProdID}" />
17 <TextBlock Text=" - " />
18 <TextBlock Text="{Binding Path=ProdName}"
/>
19 </StackPanel>
20 </DataTemplate>
21 </ListBox.ItemTemplate>
22 </ListBox>
23 <Grid Grid.Column="1" x:Name="dgvDetalhes">
24 <Grid.ColumnDefinitions>
25 <ColumnDefinition />
26 <ColumnDefinition Width="2*" />
27 </Grid.ColumnDefinitions>
28 <Grid.RowDefinitions>
29 <RowDefinition />
30 <RowDefinition />
31 <RowDefinition />
32 <RowDefinition />
33 <RowDefinition />
34 <RowDefinition />
35 <RowDefinition />
36 </Grid.RowDefinitions>
37 <TextBlock Text="ID:" Grid.Column="0" Grid.Row="0"
HorizontalAlignment="Left"
38 Margin="5" VerticalAlignment="Center" />
39 <TextBlock Text="Nome:" Grid.Column="0" Grid.Row="1"
HorizontalAlignment="Left"
40 Margin="5" VerticalAlignment="Center" />
41 <TextBlock Text="Fornecedor:" Grid.Column="0"
Grid.Row="2" HorizontalAlignment="Left"
42 Margin="5" VerticalAlignment="Center" />
43 <TextBlock Text="Grupo:" Grid.Column="0" Grid.Row="3"
HorizontalAlignment="Left"
44 Margin="5" VerticalAlignment="Center" />
45 <TextBlock Text="Preço:" Grid.Column="0" Grid.Row="4"
HorizontalAlignment="Left"
46 Margin="5" VerticalAlignment="Center" />
47 <TextBlock Text="Estoque:" Grid.Column="0"
Grid.Row="5" HorizontalAlignment="Left"
48 Margin="5" VerticalAlignment="Center" />
49 <TextBlock Text="Descontinuado:" Grid.Column="0"
Grid.Row="6" HorizontalAlignment="Left"
50 Margin="5" VerticalAlignment="Center" />
51 <TextBox Grid.Column="1" Grid.Row="0" Text="{Binding
Path=ProdID, Mode=OneWay}"
52 Margin="10" Width="50"
HorizontalAlignment="Left" IsReadOnly="True" />
53 <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding
Path=ProdName, Mode=OneWay}"
54 Margin="10" IsReadOnly="True" />
55 <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding
Path=FornID, Mode=OneWay}"
56 Margin="10" Width="50"
HorizontalAlignment="Left" IsReadOnly="True" />
57 <TextBox Grid.Column="1" Grid.Row="3" Text="{Binding
Path=GrupoID, Mode=OneWay}"
58 Margin="10" Width="50"
HorizontalAlignment="Left" IsReadOnly="True" />
59 <TextBox Grid.Column="1" Grid.Row="4" Text="{Binding
Path=ProdPreco, Mode=OneWay}"
60 Margin="10" Width="100"
HorizontalAlignment="Left" IsReadOnly="True" />
61 <TextBox Grid.Column="1" Grid.Row="5" Text="{Binding
Path=ProdEstoque, Mode=OneWay}"
62 Margin="10" Width="100"
HorizontalAlignment="Left" IsReadOnly="True" />
63 <CheckBox Grid.Column="1" Grid.Row="6"
IsChecked="{Binding Path=ProdDescontinuado, Mode=OneWay}"
64 HorizontalAlignment="Center"
VerticalAlignment="Center" IsEnabled="False"/>
65 </Grid>
66 </Grid>
67</Window>

Na Listagem 14 temos inicialmente na linha 05 a tag da Grid que é


adicionada por padrão pelo Visual Studio. Nesta grid definimos duas colunas,
sendo a segunda coluna duas vezes o tamanho da primeira, conforme linhas de
6 a 9. Após definirmos as colunas da grid, incluímos a nossa ListBox (linha
10) e utilizamos a primeira instância de Binding do código, a qual será
responsável por ligar em nossa ListBox o objeto de fonte Produtos. Se
verificarmos nosso banco de dados veremos que Produtos é o nome dado à
nossa tabela de produtos e é exatamente isto que estamos ligando em nossa
ListBox, estamos dizendo a ela que sua fonte de dados é a tabela produtos.

Como não queremos que a nossa ListBox apresente todos os campos da tabela
produtos e sim somente o código e a descrição, incluímos um DataTemplate
para ela (linha 14), que serve para definir como os dados devem ser
apresentados na Listbox. Em nosso caso, incluímos um StackPanel para
arranjar três TextBlocks de forma horizontal, sendo o primeiro vinculado à
coluna ProdID da tabela Produtos, através do DataBinding, o segundo
TextBlock contendo uma string para somente incluir um separador entre
código e nome e o terceiro TextBlock vinculado ao campo ProdName da
tabela Produtos, também através do Data Binding.

Na linha 23 incluímos uma nova Grid que estará contida dentro da coluna 1 da
Grid principal. Esta nossa segunda Grid terá o nome de dgvDetalhes e conterá
os detalhes do produto selecionado na ListBox. Para a grid de detalhes
configuramos duas colunas, sendo a segunda coluna duas vezes o tamanho da
primeira e sete linhas de tamanhos iguais, conforme pode ser verificado nas
linhas de 24 a 36. Depois de termos configurado a grid de detalhes, nas linhas
de 37 a 49 incluímos os rótulos de cada informação que será apresentada, ou
seja, cada coluna da tabela Produtos de nosso banco de dados.

Por fim incluímos 6 Textboxes para as informações de ID, Nome, Fornecedor,


Grupo, Preço e Estoque, sendo cada um em sua linha específica e vinculado
ao seu campo na tabela Produtos através do Binding. Incluímos também um
CheckBox para a informação de Produto Descontinuado, correspondente ao
campo ProdDescontinuado da tabela Produtos. Para os campos TextBox
incluídos adicionamos a propriedade IsReadyOnly como true para que os
mesmos sejam somente leitura, porém também adicionamos a propriedade
Mode do Binding a todas às informações com a opção OneWay, o que
significa que os dados somente são atualizados a partir do objeto fonte. Com
isso nosso modelo de dados que está ligado com nossa tabela do banco de
dados. Na informação Descontinuado adicionamos a propriedade IsEnabled
como false, para não permitir edição do CheckBox.

É interessante ressaltar a versatilidade do Data Binding, que converte


automaticamente a informação para ser apresentada em um CheckBox
conforme podemos verificar na informação de Produto Descontinuado, pois a
propriedade IsChecked é um booleano.

O resultado pode ser verificado na Figura 10.


Figura 10. Design do formulário

Agora apenas temos que vincular os dados em nosso formulário, para isto
utilizaremos a propriedade DataContext conforme foi apresentada
anteriormente. No código fonte de nosso formulário, após chamar o método
InitializeComponent, temos que criar uma instância do nosso modelo de dados
configurado pelo Entity Framework. Para isto vamos criar uma variável do
tipo VentoNorteEntities chamada entidades. Após termos criado nossa
instância de entidades, podemos vincular na propriedade DataContext de
nossa ListBox o nosso modelo, conforme Listagem 15.

Listagem 15. Vinculando o modelo de dados

01 public MainWindow()
02 {
03 InitializeComponent();
04 VentoNorteEntities entidades = new VentoNorteEntities();
05 lstProdutos.DataContext = entidades;
06 }

Com esta alteração já temos vinculado nosso modelo na ListBox, porém ainda
precisamos apresentar os detalhes do Produto que será selecionado na mesma.
Para isto temos que implementar o evento SelectionChanged da ListBox.
Na Listagem 14 o evento já estava implementado na linha 12 então basta
criarmos o código do mesmo conforme Listagem 16.

Listagem 16. Evento SelectionChanged da ListBox


01 private void lstProdutos_SelectionChanged(object sender,
SelectionChangedEventArgs e)
02 {
03 if (e.AddedItems.Count > 0)
04 {
05 Produtos p = e.AddedItems[0] as Produtos;
06 dgvDetalhes.DataContext = p;
07 }
08 }

Na Listagem 16 estamos verificando se há item selecionado na ListBox (linha


3) e caso sim, estamos alimentando este item em uma variável do tipo
Produtos e ligando a mesma na propriedade DataContext de nossa Grid de
detalhes. Com isso os dados do produto serão apresentados nos TextBox
definidos conforme os campos do banco de dados.

Ao final podemos executar nosso projeto que teremos listados todos os


produtos da base de dados VentoNorte. Ao selecionarmos um produto na
listagem seus detalhes serão apresentados nos campos conforme seus dados
cadastrados na base (Figura 11).

Figura 11. Projeto executando

Conclusão
Podemos verificar que o Data Binding está muito evoluído em WPF,
auxiliando o desenvolvedor a escrever códigos mais limpos e fornecendo
funcionalidade de produtividade em uma aplicação.
Links

Tutorial Data Binding – WPF


http://www.wpftutorial.net/DataBindingOverview.html

por Fabio Rosa


Guru .net e tecnologias MS

Crie uma aplicação compl


eta passo a passo com C
#, Visual Studio e
ASP.NET
Este artigo finaliza o mini-curso de criação
de uma loja virtual com C#, VS e ASP.NET,
mostrando como requisitar dados adicionais
do usuário para envio do pedido, usando o
recurso de Profiles.
De que se trata o artigo

Este artigo finaliza o mini-curso de criação de uma loja virtual com C#, VS e
ASP.NET, mostrando como requisitar dados adicionais do usuário para envio
do pedido, usando o recurso de Profiles. Mostra também como enviar as
informações do carrinho para o banco de dados, bem como enviar um email
de confirmação.

Em que situação o tema é útil

Profiles são úteis quando necessitamos armazenar no servidor opções


personalizadas para cada usuário, informações estas que podem ser
recuperadas toda vez que o usuário retorna ao site.

Criando uma aplicação completa passo a passo com C#, Visual Studio e
ASP.NET

No primeiro artigo deste mini-curso criamos o banco de dados no SQL Server


usado ao longo desta série. Na segunda parte iniciamos a criação do Web Site,
aproveitando para falar dos fundamentos do ASP.NET e Visual Studio,
sempre comparando-os com a VCL e RAD Studio, com o intuito de facilitar o
aprendizado. Vimos a estrutura básica de um Web Site e iniciamos a
construção do layout padrão do site de E-Commerce (chamado “Computer
Store”), bem como o sistema de navegação. Na parte 3 vimos como construir
a página principal do site, exibindo a lista de produtos, mostrando como fazer
a conexão com o banco de dados. Na parte 4 vimos dois importantes passos
do site, tarefas comuns realizadas em qualquer tipo de aplicação Web que
trabalhe com banco de dados, como criar pesquisas com parâmetros e trocar
dados entre formulários Web. Na parte 5, vimos como adicionar uma das
principais funcionalidades do site, a possibilidade do usuário adicionar
produtos a um carrinho de compras. Na parte 6 vimos um recurso muito
interessante e que possui um excelente suporte pronto e nativo do ASP.NET:
segurança com os controles de Login. Nesta 7ª e última parte do mini-curso, a
aplicação ASP.NET será finalizada com a construção da página de Checkout
(fechamento da compra).

Nesta última etapa, o usuário poderá informar seus dados adicionais para o
envio da compra, para isso será usado o recurso de Profiles e um recurso
interessante do CreateUserWizard, que é a possibilidade de incluir novos
“steps” ao assistente. Os dados que até agora estão na sessão do usuário, em
memória, serão finalmente persistidos no banco de dados criado na primeira
parte desta série. O processo é simples, varrer o DataSet em memória e gerar
comandos SQL de inserção. Será usado ADO.NET diretamente no form, mas
considere o uso de classes separadas para criar acesso a dados em uma
situação real, ou mesmo o uso de um framework de persistência. O ADO.NET
já foi amplamente abordado em etapas anteriores, de forma que não será
discutido aqui. O exemplo emprega classes já discutidas, como
SqlConnection, SqlCommand, DataSet e DataRow. Observações serão feitas
quando pertinente, sempre comparando com o Delphi Win32 tradicional e
VCL, objetivo principal desta série.

Nota: Como já comentado em partes anteriores, existem excelentes framew


orks de persistência e mapeamento objeto / relacional para .NET, como o NH
ibernate e ADO.NET Entity Framework. Como o objetivo deste mini-curso é ju
stamente reaproveitar conhecimentos do Delphi Win32 para o desenvolvime
nto Web, serão utilizados recursos que mais se assemelham ao DBExpress e F
irebird.

Profiles
Uma das técnicas mais interessantes que este exemplo usa é o recurso de
Profiles. O ASP.NET possui inúmeros recursos para manter o estado em
aplicações Web, como o simples uso de Cookies, passando por variáveis de
Sessão, Cache, ViewState e mais. Imagine a seguinte situação: o usuário entra
no seu site e customiza algumas partes da página, define algumas preferências
de navegação, usabilidade etc. Quando ele retornar ao seu site, não importa
quanto tempo isso leve, devemos ter uma forma de “lembrar” essas
preferências definidas pelo usuário. Antigamente (ASP.NET 1.x), era preciso
criar uma tabela no banco de dados com campos que definiam o perfil
(profile) do usuário. Após a sua visita, era preciso gravar suas preferências no
banco e o ID em um cookie local no browser. Quando ele retornava,
informações eram recuperadas a partir do cookie.

Um grande recurso introduzido lá no ASP.NET 2.0 foi o suporte a Profiles.


Este recurso faz basicamente o que foi exposto no parágrafo anterior, porém,
reduzindo drasticamente o trabalho necessário para realizar esta tarefa.

Com o ASP.NET 4.0, pode-se utilizar o recurso de Profiles em aplicações


Web no Visual Studio 2010. Basta adicionar os campos desejados no
Web.Config, como:

<add name="VARIAVEL"/>

O VS faz um parse no XML, verifica o que foi colocado na sessão Profile


(campos) e cria automaticamente uma classe “wrapper” que é injetada na
página através da propriedade Profile. Esta é uma classe fortemente tipada. No
exemplo dado, é possível fazer o seguinte:

Profile.VARIAVEL = TextBox1.Text;
Isso difere de Sessions, onde não há tipo específico, sempre temos um Object
e não há verificação em tempo de compilação:

Session[“VARIAVEL”] = TextBox1.Text;

No momento que o site é acessado pela primeira vez, o ASP.NET aciona o


recurso de Profiles. Ele cria “on-the-fly” um banco de dados prontinho com
uma estrutura previamente definida para guardar os dados do profile, chamado
ASPNETDB, o mesmo usado para guardar dados de login de usuários, visto
no artigo anterior. De praxe, o ASP.NET já grava um cookie no browser para
mapear o usuário para o seu respectivo profile no servidor quando ele entrar
novamente.

Algumas considerações sobre o recurso:

• Por padrão o recurso usa um banco pré-definido no SQL Server chamado


ASPNETDB, mas pode-se criar a estrutura em um banco SQL Server
existente;

• Com um pouco mais de trabalho é possível usar outros bancos de dados;

• É possível gravar vários tipos de informações no banco que não só strings,


mas coleções completas (por exemplo, um carrinho de compras do usuário)
bem como tipos definidos pelo próprio desenvolvedor.

Solicitando informações adicionais


do usuário
Mas como usar Profiles na prática no exemplo? No site de e-commerce o
usuário precisa informar seus dados para o envio do pedido. Normalmente o
usuário tem um endereço padrão cadastrado no site, mas tem a opção de trocá-
lo ao finalizar a compra. Por exemplo, ele pode comprar um produto para
presente que deve ser entregue em outro endereço. Por esse motivo, na tela de
Checkout que será mostrada adiante, é preciso exibir os dados de postagem
atualmente cadastrados.

Como visto na parte anterior do artigo, os dados de login do usuário ficam


gravados nas “tabelas de sistema” do ASP.NET. É o banco ASPNETDB, que
tem uma estrutura pré-definida e juntamente com os controles de login e
providers já faz todo o gerenciamento de contas. No exemplo do artigo, como
fazer para adicionar mais informações a esse cadastro do usuário, como os
dados postais de entrega (endereço, cidade, CEP)? Apesar de possível, o
trabalho de modificar diretamente a estrutura da tabela criada no ASPNETDB
não é recomendado. Talvez criar uma tabela auxiliar que contenha um join
para a tabela de usuário, ligada pelo UserID.

Sem dúvida aqui está um belo exemplo para o uso de Profiles. É justamente
isso que o exemplo faz, utiliza o recurso para armazenar os dados adicionais
do usuário, além dos dados padrão já requeridos pelo sistema de membership
do ASP.NET. Nada melhor do que solicitar essas informações durante o
próprio processo de cadastro, na tela NewUser.aspx, no controle
CreateUserWizard, que agora contém alguns TextBoxs adicionais (Figura 1).

Nota do DevMan

O controle CreateUserWizard descende de Wizard que foi incluído no ASP.N


ET 2.0 / Visual Studio 2005, que permite criar um mecanismo “passo a passo”
para preenchimento de informações. Inclusive na Web pode ser usado para si
mular um PageControl. É possível adicionar mais “steps” ao controle e dentro
de cada aba adicionar mais controles.

Figura 1. CreateUserWizard com “step” adicional

Para salvar essas informações no Profile do usuário, basta manipular o evento


ContinueButtonClick do CreateUserWizard, como o código da Listagem
1. Simplesmente é atribuída a cada propriedade do Profile o texto digitado em
cada TextBox. Não é necessário inserir qualquer código para acesso a banco
de dados, o ASP.NET faz tudo. Estes dados são salvos no próprio banco
ASPNETDB.

Listagem 1. Dados adicionais colocados no CreateUserWizard são salvos no


Profile
protected void CreateUserWizard1_ContinueButtonClick(
object sender, EventArgs e)
{
Profile.FullName = tbFullName.Text;
Profile.Address = tbAddress.Text;
Profile.City = tbCity.Text;
Profile.Country = tbCountry.Text;
Profile.ZIPCode = tbZIPCode.Text;
Profile.EMAIL = CreateUserWizard1.Email;
}

No Web.Config os campos utilizados no Profile devem ser informados, para


que o ASP.NET possa gerar os dados corretamente no ASPNETDB.
A Listagem 2 exibe as chaves incluídas no arquivo de configuração do Web
Site. Não é necessário informar o tipo de dado, pois se ele for string, o
ASP.NET é esperto o suficiente para saber que a maioria dos dados utilizados
são deste tipo.

Listagem 2. Profile no Web.Config

<profile>
<properties>
<add name="FullName"/>
<add name="Address"/>
<add name="City"/>
<add name="Country"/>
<add name="ZIPCode"/>
<add name="EMAIL"/>
</properties>
</profile>

Página de Checkout
A Figura 2 mostra a página de Checkout do sistema de E-Commerce. É nessa
página que o usuário irá confirmar os dados de envio, bem como confirmar o
método de pagamento. O exemplo simplesmente simula um pagamento como
cartão de crédito, solicitando os dados básicos, já que a implementação
completa de um processo de pagamento on-line está fora do escopo deste
artigo. Os Labels vistos na tela simplesmente são alimentados com os dados
de endereço do usuário, através do Profile. Isso é feito no Page_Load quando
a página é carregada, como mostra a Listagem 3.
Figura 2. Design da página Checkout.aspx

Listagem 3. Dados do Profile com informações postais são repassados aos


Labels no carregamento da página (Page_Load)

protected void Page_Load(object sender, EventArgs e)


{
if (!IsPostBack)
{
lbFullname.Text = Profile.FullName;
lbAddress.Text = Profile.Address;
lbCity.Text = Profile.City;
lbCountry.Text = Profile.Country;
lbZIPCode.Text = Profile.ZIPCode;
// preenche o combo com 12 meses do ano
for (int i = 0; i < 12; i++)
ddMonth.Items.Add(Convert.ToString(i.ToString()));
}
}
Nota do DevMan
Muitos desenvolvedores Delphi têm o costume de utilizar o Page_Load como
se fosse o OnShow de um TForm, sendo essa uma das principais fontes para b
ugs em sistemas Web. É importante levar em consideração que o Page_Load é
executado a cada vez que há uma carga completa da página, no caso do ASP.
NET tradicional (sem AJAX). Isso ocorre toda vez que um usuário clica em u
m botão, em uma célula de um GridView que contenha botões, LinkButtons o
u em controles que estejam com o AutoPostBack ativado. Dessa forma, para si
mular realmente um OnShow, garantindo que o código será executado apenas
uma vez, quando a página é carregada, é preciso verificar o valor da proprieda
de IsPostBack. Ele será false no primeiro carregamento.

A Listagem 4 mostra o código do botão Continue. Nele existe a chamada para


dois métodos importantes, o SendToDataBase e o SendEmail, apresentados
adiante. A seguir, o usuário é redirecionado para a página de finalização que
simplesmente exibe uma mensagem de confirmação. Neste ponto, os dados da
compra são persistidos da memória para o banco de dados e um email de
confirmação com os dados da compra é enviado ao usuário. Observe o uso de
Type Inference usando a palavra-reservada var.

Listagem 4. Finalizando a compra: gravação dos dados no banco e envio do


email de confirmação

protected void ImageButton1_Click(object sender,


ImageClickEventArgs e)
{
var OrderId = SendToDatabase();
SendEmail(OrderId);
Response.Redirect("~/Checkout/finish.aspx");
}
Nota do DevMan

Type Inference

NoDelphiWin32 é preciso sempre declarar o tipo de uma variável. Quando for


um objeto, deve ser instanciado comCreatechamando o construtor da classe. O
código a seguirdeclara um TClientDataSet e a seguir o instancia. Mas veja be
m, por que é preciso declarar a classe como sendoTClientDataSet e depois no
momento da criação atribuir um objeto do mesmo tipoà variável?

var
Cds: TClientDataSet;
begin
Cds := TClientDataSet.Create(nil);
Isso tem uma explicação. Em alguns casos, uma variável não é declarada do m
esmo tipo que vai ser instanciada, mas sim de um tipo ancestral. Assim, é poss
ível aplicar técnicas de orientação a objeto como polimorfismo e abstração, al
ém de programação para interfaces. É por esse motivo, por exemplo, que oQui
ck Report aponta para umTDataSete até hoje pode suportar inúmerosenginesd
e acesso a dados, inclusive os que venham a ser criados.

O código a seguir declara uma variável do tipoTDataSet, classe base para muit
as outras classes de acesso a dados naVCL. Porém, na implementação essa var
iávelpode receber tanto umTQueryquanto um TClientDataSet, pois ambos des
cendem deTDataSet. Quando o método Post do DataSet é chamado, o compila
dor vai analisar a assinatura do método na classe declarada (TDataSet), e vai d
etectar que ele évirtual. Com isso, o verdadeiroPostque será chamado não é o
da classeTDataSet, mas deTClientDataSet, que sobrescreve o Postcomoverrid
e, configurando uma chamadapolimórfica:

var Ds: TDataSet;


begin
if [condicao] then
Ds := TQuery.Create(nil)
else
Ds := TClientDataSet.Create(nil);
Ds.Post();

E noC#?Bem, é possível fazer tudo isso sem problemas noC#, usando objetos
daFCLao invés daVCL, claro. Porém, aqui existe uma novidade. Se não formo
s usarpolimorfismo, ou seja, o tipo que vamos instanciar é o mesmo que vai se
r declarado, pode-seomitiro tipo:

// Declarando o tipo

DataSet Ds1 = new DataSet();


// Type Inference, sem declarar o tipo
var Ds2 = new DataSet();
// Outros exemplos de Type Inference
var i = 32;
var s = "Guinther";

No primeiro código, um trecho normal. O objeto é declarado como DataSet e i


nstanciado a partir do construtor da classe(a palavra-chave para instanciar obje
tos éNEW, e nãoCreate). No segundo código o tipo foi omitido, ou seja, foi de
clarado sem tipo. O compilador doC#, a partir do valor que for jogado dentro
da variávelDs2, determina o tipo do objeto. Na sequência, outros exemplos de
como usar o recurso. Isso é chamado deType Inference(não sãoVariantsnão, s
ão variáveis fortementetipadas).
Persistindo os dados de sessão no
banco de dados
A Listagem 5 detalha o método SendToDatabase da página de Checkout. O
código basicamente usa ADO.NET para criar uma conexão com o banco de
dados, para então inserir as informações do pedido, que até agora estão em
sessão (memória). A ConnectionString é lida a partir do Web.Config, isso é
feito através do ConfigurationManager (ou WebConfigurationManager). Um
SqlCommand excuta um comando no servidor para inserir as informações do
pedido. Uma Stored Procedure é usada (Listagem 6).

O for each percorre o DataSet, que nada mais é que o carrinho de compras em
memória e para cada item encontrado executa um insert no banco. A Stored
Procedure retorna o ID do pedido, que é usado para ser incluído como valor
do campo da chave estrangeira na tabela de detalhes do pedido, fazendo assim
o relacionamento correto entre tabelas master e detail.

Listagem 5. Envio dos dados ao BD a partir das informações em memória

private int SendToDatabase()


{
Object OrderId;
var con = new SqlConnection(

WebConfigurationManager.ConnectionStrings["LOJAConnectionString"].Conn
ectionString);
var cmd = new SqlCommand("InsertOrder", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@DATE", DateTime.Now);
cmd.Parameters.AddWithValue("@CUSTOMER",
User.Identity.Name);
cmd.Parameters.Add("@RETURN_VALUE", SqlDbType.Int);
cmd.Parameters["@RETURN_VALUE"].Direction =
ParameterDirection.ReturnValue;
con.Open();
try
{
cmd.ExecuteNonQuery();
OrderId = cmd.Parameters["@RETURN_VALUE"].Value;
var ds = Session["ShoppingCart"] as DataSet;
foreach (DataRow row in ds.Tables[0].Rows)
{
var SQL = System.String.Format(
"insert into OrderDetails (OrderId,ProductId) values
({0},{1});", OrderId, row["ProductId"]);
var cmd2 = new SqlCommand(SQL, con);
cmd2.ExecuteNonQuery();
}
}
finally
{
con.Close();
}
return Convert.ToInt32(OrderId);
}

Listagem 6. Stored Procedure para inserir pedidos no banco

create procedure InsertOrder


@date datetime,
@customer varchar(50)
as
begin
insert into Orders (date,customer)
values (@date,@customer);
return @@IDENTITY;
end
Nota do DevMan

O SQL Server permite que o desenvolvedor obtenha o ID gerado pelo banco d


e dados para uma tabela que tenha um campo Identity (autoincremento), atrav
és da variável de contexto @@IDENTITY. É semelhante a um recurso utiliza
do no Firebird para descobrir o valor gerado por uma Sequence / Generator. P
ara obter esse valor no código, basta recuperar o valor de @RETURN_VALU
E, obtido como parâmetro de saída (Output) de um SqlCommand.

Enviando um email de confirmação


A Listagem 7 mostra o código que envia o email ao usuário. O procedimento
é semelhante ao mostrado no SendToDataBase, pois é preciso varrer o
carrinho para verificar quais itens foram comprados. No entanto, ao invés dos
dados serem enviados ao banco, agora o sistema monta um e-mail que utiliza
configurações pré-definidas de um servidor SMTP para o envio. Note que o
email do usuário é obtido a partir do seu Profile. O StringBuilder é usado para
montar o corpo do email.

Nota do DevMan
Um StringBuilder do .NET Framework é semelhante a um TStringList da VC
L. É usado para concatenar strings. No .NET, quando strings são concatenadas
com o operador “+”, a plataforma simplesmente descarta a string original e cri
a outra em memória, ao contrário do Delphi Win32, onde uma string cresce di
namicamente. Isso causa sérios problemas de performance, e na Web cada mil
issegundo perdido pode se tornar uma grande dor de cabeça em um Web Site
com centenas ou milhares de conexões simultâneas. O StringBuilder resolve o
problema e é tão simples de usar quanto o TStringList a VCL, senão análogo.

Listagem 7. Enviando ao usuário um email de confirmação da compra

private void SendEmail(int OrderId)


{
var msg = new MailMessage();
msg.From = "[email protected]";
msg.To = Profile.EMAIL;
msg.Subject = "Your order";
var sb = new System.Text.StringBuilder();
sb.AppendLine("Order Number: " + OrderId.ToString());
sb.AppendLine("");
var ds = Session["ShoppingCart"] as DataSet;
foreach (DataRow row in ds.Tables[0].Rows)
{
sb.AppendLine("Product: " +
row["ProductName"].ToString());
sb.AppendLine("Price: " + row["Price"].ToString());
sb.AppendLine("");
}
sb.AppendLine("Total: " +
ds.Tables[0].Rows[0]["Total"].ToString());
msg.Body = sb.ToString();
msg.BodyFormat = MailFormat.Text;
var UserName = "coloque aqui o email do usuário SMTP – ex.:
[email protected]";
var Password = "coloque aqui a senha do usuário SMTP";
var MailServer = "coloque aqui o endereço smtp do servidor –
ex.: smtp.empresa.com";

msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpaut
henticate", 1);

msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/senduse
rname", UserName);
msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpas
sword", Password);

msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusi
ng", 2);

msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpser
ver", MailServer);

msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpcon
nectiontimeout", 10);

msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpser
verport", 587);

msg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpuse
ssl", false);
SmtpMail.Send(msg);
}

Teste final
O teste final no exemplo comprova a funcionalidade dos códigos expostos.
A Figura 3 mostra alguns produtos adicionados ao carrinho. Ao fazer o
Checkout, a Figura 4 solicita a confirmação dos dados de envio e o método e
pagamento. Finalizando a compra, o usuário recebe um email, como mostra
a Figura 5.

Figura 3. Itens da compra (carrinho) ficam em memória, no DataSet


Figura 4. Confirmação dos dados para envio e pagamento

Figura 5. Usuário recebe e-mail com confirmação da compra e descrição dos


itens

Conclusão
Ao longo desta série muitos recursos do Visual Studio, C# e ASP.NET foram
explorados, sempre confrontando com as metodologias tradicionais do Delphi
Win32. Não tenho dúvida que o leitor constatou que desenvolver para Web,
com ASP.NET e C#, é tão simples quanto desenvolver aplicações Desktop,
podendo ainda aproveitar muitos conhecimentos já adquiridos. Desejo aos
novos desenvolvedores Web sucesso em seus novos projetos com C# e
ASP.NET.

Links

Visual Studio
www.microsoft.com/visualstudio

Blogs do autor
http://twitter.com/guintherpauli
http://gpauli.com

por Guinther Pauli


Guru .net e tecnologias MS

Avançando com WCF


Este artigo continua falando sobre o
desenvolvimento de aplicações WCF,
iniciado na edição anterior, que são a
plataforma para distribuição de software
como serviços criada pela Microsoft como
um aperfeiçoamento aos Web Services.
De que se trata o artigo

Este artigo continua falando sobre o desenvolvimento de aplicações WCF,


iniciadoar na edição anterior, que são a plataforma para distribuição de
software como serviços criada pela Microsoft como um aperfeiçoamento aos
Web Services. No texto será dada continuação ao desenvolvimento deste tipo
de aplicação e será dado foco às tarefas de publicação usando o IIS e também
a utilização de arquivos de configuração para ajustar tanto o serviço como a
aplicação cliente.

Em que situação o tema é útil

Os conceitos apresentados procuram ajudar o desenvolvedor a criar, publicar e


configurar aplicações que usam o WCF.

Avançando com WCF

Software como provedor de serviços é uma tendência de mercado. Basta


seguir alguns blogs sobre software corporativo e constatar isto. O WCF
permite muitos desdobramentos e grande flexibilidade para criar este tipo de
software. Um aspecto delicado é a publicação destes para serem consumidos
por outros usuários e seus sistemas. A utilização do IIS neste caso não é muito
intuitiva como nos Web Services. A configuração também é um aspecto que
merece atenção e que pode representar alguma complicação. Nada que uma
boa introdução aos recursos do Framework .Net não resolva.

A grande sacada dos Web Services e do WCF foi possibilitar distribuir o


processamento entre computadores separados fisicamente de uma maneira
relativamente simples. Qualquer programador que tenha estudado sistemas
distribuídos precisou aprender a criar sockets e entender o funcionamento das
camadas de rede. Isso sinceramente não é nada fácil, uma vez que muitos
problemas precisam ser resolvidos.

A estrutura fornecida pelo WCF, assim como todas do Framework .Net, busca
providenciar todos os recursos para o desenvolvedor focar ao máximo na
funcionalidade que quer criar e não se preocupar (tanto) com os problemas
citados anteriormente.

Boa parte destes recursos está concentrada na forma como altera o


comportamento do serviço através das configurações. É possível fazer toda a
configuração dos endpoints e do host dentro do código escrito em C#, mas é
melhor que isto seja feito através de arquivos de configuração, como nos
outros tipos de aplicação do Framework .Net. Estes arquivos já são
conhecidos para quem desenvolve projetos Web e Windows e sua estrutura
não difere muito nos WCF.

A configuração da aplicação cliente que é a que irá acessar o serviço, também


pode ser feita com o uso dos arquivos. Desta forma este tipo de aplicação
pode fazer alterações como mudança do endereço do serviço e alguns detalhes
do seu acesso sem precisar sofrer nenhuma modificação no seu código.

Também é oferecido para o desenvolvedor uma forma facilitada para hospedar


os serviços dentro da infraestrutura oferecida pelo IIS (Internet Information
Service) que é o gerenciador padrão dos sistemas Windows para hospedagem
de páginas e aplicativos Web.

A hospedagem do WCF no IIS não é tão intuitiva, mas com um pouco de


esforço os resultados são satisfatórios. Sempre que se escreve sobre o
Framework .Net existe uma tendência de superestimar suas vantagens. Em um
primeiro momento, a tendência é achar que tudo deve ser muito simples e
rápido, e depois que se conhece um pouco mais da sua arquitetura, tudo acaba
ficando assim mesmo, mas primeiro é importante se aprofundar em alguns
aspectos.

A arquitetura do WCF
Desde a versão 2.0 do Framework .Net, a base para desenvolvimento de
serviços continua a mesma, ou seja, as classes principais são desta versão.

As novidades como WCF, WPF (Windows Presentation Foundation, uma


nova plataforma para o desenvolvimento de aplicações desktop), LINQ
(Language Integrated Query, uma linguagem de consultas integrada com as
linguagens do Framework como VB e C#), são acréscimos feitos a partir das
novas versões. O WCF, por exemplo, está embutido na versão 3.0. A Figura
1 dá uma ideia desta arquitetura.
Figura 1. WCF e o Framework

Isto significa que para ativar estes tipos de aplicação, se deve instalar a versão
correta do Framework. Um detalhe importante é que as versões Windows 7
para o desktop e Windows 2008 para o servidor já estão com as versões
necessárias instaladas. Outro ponto a considerar é que ao instalar a versão 3.5
a 2.0 já é instalada por padrão.

É sempre bom lembrar que as pastas do Framework .Net estão tipicamente em


c:\windows\Microsoft.Net. A Figura 2 demonstra uma estrutura destas no
Windows 7.

Figura 2. Pastas do Framework

Observe que as versões 1.0, 1.1 e 2.0 também são instaladas para manter
compatibilidade. Sabendo desta arquitetura, ao fazer a hospedagem do WCF
no IIS, a configuração da aplicação ficará um pouco mais fácil de entender
principalmente quando se estiver configurando o pool de aplicações que é
como o IIS faz o gerenciamento destas. Em alguns casos, como o WCF, é
indicado usar o Classic App que usa a versão 2.0 como base.

Nota: é bom verificar a versão do Windows que está instalada. Algumas versõ
es mais básicas, apesar de terem as versões do Framework, podem não ter alg
umas ferramentas como o IIS instaladas por padrão.

Usando o IIS para hospedar o


serviço
O IIS está presente em quase todas as versões do Windows, mesmo as
Desktop. Atualmente na versão 7 que vem por padrão no Server 2008 e no
Windows 7 (a partir da Professional), é a maneira mais indicada para hospedar
serviços WCF.

O seu acesso pode ser feito de diversas maneiras sendo as mais simples
através das ferramentas administrativas, digitando “IIS” no menu iniciar
(Figura 3) ou através da opção “Executar” do menu iniciar do Windows
digitando “inetmgr”.
Figura 3. Acessando o IIS

Se o mesmo não estiver instalado, é fácil fazer isto através da opção Adicionar
Programas do painel de controle do Windows. Nesta tela, deve se abrir a
ferramenta para habilitar ou desabilitar recursos do Windows (Figura 4).

Figura 4. Instalando o IIS

Estes passos foram elaborados a partir do Windows 7, mas devem funcionar


com a versão do servidor também. Lembre-se de que será necessário ter
permissões do usuário Administrador. Se estiver configurando o IIS, após
instalar, não é necessário reiniciar o computador, apenas alguns passos
adicionais precisam ser dados. Entre estes deve se instalar o ASP.NET no IIS.
Isto é feito no prompt de comandos (aberto como administrador) na pasta
c:\windows\microsoft.net\Framework\v2.0.50727 com o comando:

> aspnet_regiis –i

Após isto, outro passo também deve ser feito ainda no prompt, porém agora
na pasta da versão 3,0 c:\Windows\Microsoft.NET\Framework\v3.0\Windows
Communication Foundation executando o comando:

> ServiceModelReg.exe –i

Normalmente isto é necessário em máquinas desktop principalmente onde se


fez uma instalação manual do Framework .Net ou do Visual Studio.
Novamente não é necessário reiniciar o Windows, apenas o IIS que pode ser
feito no próprio prompt de comandos na pasta c:\windows\system32 através
do comando:

> iisrest –restart

Ou na própria interface do IIS.

Nota: estes passos se aplicam em versões de 32 bits do Windows e algumas p


astas estão localizadas em lugares diferentes nas versões de 64 bits. É bom obs
ervar este detalhe se for fazer configurações do IIS e do Windows.

Como preparar o WCF para o IIS


O IIS precisa ser preparado para hospedar o WCF. Existem muitos exemplos
de como criar uma aplicação console para disponibilizar o serviço WCF,
inclusive foi tema do artigo anterior. Entretanto, a melhor opção é o IIS, por
vários motivos, entre eles a sua capacidade de gerenciamento dos processos e
controle de falhas.

Quando se desenvolve um serviço WCF para ser hospedado no IIS duas


modificações importantes precisam ser feitas. Uma é criar um arquivo de
configurações, como será colocado adiante, e outra é acrescentar um arquivo
com a extensão .svc no projeto.

O arquivo .svc pode ser acrescentado no projeto facilmente e consiste


basicamente de um documento XML onde se indica o nome do serviço e o
namespace e a classe que está sendo exposta. Este conteúdo será muito
parecido com o dos arquivos .asmx usados nos Web Services:

<%@ ServiceHost Service="InvestServiceDemo.InvestService" %>

Através deste código, é possível acessar o WCF passando o nome do serviço a


ser acessado. O IIS se encarrega de resolver como será feito o acesso na DLL
do WCF que é publicada. Aliás, é importante observar como será feita a
publicação do WCF no IIS. Deve-se copiar para a pasta a ser configurada no
IIS os seguintes conteúdos:

 Pasta bin, contendo as dll´s do serviço e acessórias, que forem


necessárias. Na pasta bin, somente estes arquivos são copiados;
 Arquivos “.svc”;
 Arquivos de configuração, que devem ser renomeados para web.config.
Ao criar uma aplicação do tipo WCF Library o arquivo .svc não é
acrescentado por padrão e nem o arquivo de configurações. No exemplo
prático será demonstrado como adicionar estes no seu projeto.

Outra questão interessante é que também é possível usar a extensão .asmx em


vez do .svc, mas, se for fazer isto, será necessário indicar isso nas
configurações. Uma boa ideia é manter .svc até para poder diferenciar as
aplicações Web Services de WCF.

O arquivo de configurações do WCF


No projeto, ao se acrescentar o arquivo de configurações, usualmente ele
ficará com o nome de app.config, mas se ao criar o projeto optou-se por criar
uma WCF Class Library (veja mais adiante quando uma aplicação de exemplo
é demonstrada), o Visual Studio se encarrega de criar a estrutura básica para
este arquivo.

Este arquivo, como outros de outros projetos do Framework, usa documentos


XML e sua hierarquia para armazenar as configurações. Seus principais
elementos podem ser observados na Listagem 1 que demonstra apenas os nós
principais, sem os seus elementos internos.

Listagem 1. Nós principais do arquivo de configurações

<?xml version="1.0"?>
<configuration>
<system.web>
<appSettings>
<system.serviceModel>
<services>
<behaviors>
</system.serviceModel>
<startup>
</configuration>

Todos os elementos estão dentro de <configuration> que é o principal. Os


principais elementos que estão nesta listagem são:

 system.web: armazena o comportamento da aplicação ao ser acessada


remotamente. É aqui onde se configura, por exemplo, se informações
de depuração são enviadas com os dados;
 appSettings: é a seção para armazenamento de dados referentes ao
comportamento da aplicação;
 system.serviceModel: responsável por armazenar a configuração de
um ou vários serviços que estão disponibilizados. Nesta seção são
configurados os serviços na tag <services> que é desdobrada em vários
atributos e outros nós filhos e na tag <behaviors> são configurados
itens como operações HTTP suportadas, entre as mais típicas;
 startup: configura opções que indicam qual a versão do Framework
que estão suportadas.

Uma das mais propagadas vantagens de se usar um arquivo de configurações é


que este é facilmente editável. Esta justificativa leva em consideração
principalmente cenários onde o servidor tipicamente possui apenas
ferramentas necessárias para o seu gerenciamento e, dificilmente, incluirá uma
cópia do Visual Studio entre estas.

Além disto, não é muito comum que se crie um arquivo de configurações


partindo do zero já no servidor. O cenário mais comum é que sua
configuração inicial seja feita no ambiente de desenvolvimento sendo que no
servidor, somente pequenos detalhes como endereço IP e outros dados
referentes a rede sejam alterados.

Considerando a complexidade da estrutura do arquivo de configurações,


existem algumas formas de contornar a árdua tarefa de ter de decorar um
schema XML. A seguir serão dadas duas formas de se configurar estes
arquivos usando ferramentas visuais.

Ferramentas para auxiliar as


configurações
O IIS permite que se editem alguns dados das configurações da aplicação
WCF. Inicialmente, podem-se configurar todos os itens da seção
<appSettings> através do ícone Application Settings que abre uma lista com
configurações que estão disponíveis para alteração e podem ser editadas
facilmente com um duplo clique, conforme é demonstrado na Figura 5.
Figura 5. Usando o editor de configurações do IIS

Este recurso já resolve o problema para editar a seção appSettings, mas ainda
não é satisfatório para editar configurações do serviço. Lembrando que o
arquivo de configurações usa um documento XML que precisa obedecer um
schema, ou as configurações não serão validadas e o serviço poderá ficar
inoperante.

Em alguns casos é muito complexo editar manualmente o arquivo


principalmente quando se precisa fazer ajustes finos e garantir a integridade
do mesmo. Para este fim é preciso usar outra ferramenta que é o Microsoft
Service Configuration (Figura 6).
Figura 6. Ferramenta para configuração do serviço

A interface desta ferramenta permite editar cada aspecto do arquivo de


configuração usando conceitos comuns das interfaces dos programas do
Windows.

Diferente do arquivo XML, seu uso, apesar de na UI haver poucos elementos,


é bem intuitivo principalmente no caso de gerenciadores de sistemas e mesmo
desenvolvedores.

A linha de comando deste utilitário é:

> SvcConfigEditor.exe

O diretório da aplicação é C:\Program Files\Microsoft


SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools. Verifique a instalação do
Windows, normalmente é instalada apenas com o Visual Studio. Também
pode ser executada pelo menu Iniciar.

A aplicação cliente
Ao fazer a publicação do serviço usando o IIS, uma das vantagens é que este
fará o gerenciamento total da aplicação que poderá ser acessada tanto pelos
protocolos HTTP e TCP (sendo que se este último for usado, o IIS deverá ser
preparado para isto).

Também, não haverá mudanças para que um aplicativo consuma os serviços.


A referência para o serviço pode ser feita em tempo de projeto adicionando
um Service Reference na aplicação. Este serviço pode estar na mesma
máquina de desenvolvimento ou em outro servidor.

Note na Figura 7 a referência para o serviço é feita de uma forma bem


transparente, se informa o endereço do servidor e do serviço.

Figura 7. Exemplo de referência a serviço em aplicação cliente

A diferença principal ao usar o IIS ocorre no fato de que se deve informar


também o arquivo .svc que foi configurado no WCF, ou o serviço não será
corretamente acessado.
Um serviço de exemplo
A principal motivação de se desenvolver serviços distribuídos é disponibilizar
dados e processamento para máquinas separadas fisicamente. Os Web
Services providenciaram um crescimento muito grande na adoção destes
serviços e a sua evolução natural é o uso dos WCF.

Como eu espero ter demonstrado, o WCF também é versátil para ser usado
com o IIS que é o cenário típico para este tipo de aplicação, embora, possua
mais detalhes. Para que estes detalhes possam ser explorados pelo leitor,
resolvi criar um pequeno serviço e demonstrar quase que passo a passo a
criação deste tipo de aplicação.

O projeto tem como objetivo, retornar quantos meses será necessário fazer
depósitos em uma conta de investimento fictícia, a uma taxa de juros mensal
pré-determinada, para que se tenha um valor montante especificado. O usuário
precisará informar o valor das parcelas mensais, o valor final desejado e a data
do início do investimento. O serviço retorna um objeto contendo:

 O valor do investimento final;


 Os dados informados pelo usuário;
 O número de parcelas necessárias (meses);
 O número de anos estimado (que é obtido pela divisão do total de
meses por doze);
 O valor final do investimento;
 A data final.

O projeto consiste de duas partes. Um primeiro projeto é do tipo WCF Service


Library, que é nada mais, do que uma DLL contendo serviços
disponibilizados usando o WCF. A segunda parte é uma aplicação console
criada apenas para demonstrar como consumir o WCF hospedado no IIS. Os
próximos tópicos do artigo demonstram como este serviço foi criado.

Para desenvolver eu usei os seguintes elementos, entre sistema operacional,


ferramentas de desenvolvimento:

 Windows 7 Ultimate 32 Bits;


 IIS versão 7.5;
 Visual Studio 2010;

Criando o serviço
O projeto WCF foi criado a partir do template WCF Service Library do Visual
Studio. A Figura 8 demonstra a caixa de diálogo do Visual Studio que
permite ajustar detalhes como o nome do projeto, a linguagem a ser usada (no
caso do exemplo, o C#) e também a versão do Framework.

Figura 8. Criando o projeto

É possível usar criar uma aplicação do zero, usando um projeto do tipo Class
Library e acrescentando referências a System.ServiceModel que é a principal
biblioteca do WCF. Só que isto costuma exigir mais esforço na hora de ajustar
o funcionamento do projeto causando atrasos. Optei usar o template do Visual
Studio e acho que é a melhor opção para a maior parte dos casos.

Com o projeto carregado no Visual Studio, o primeiro passo é criar a interface


tanto para o DataContract como para o ServiceContract.

Relembrando, o primeiro controla os tipos de dados que serão expostos pelo


serviço e o segundo, qual o serviço que é representado por uma interface no
C# e os métodos disponibilizados. Para adicionar uma interface deste tipo no
projeto, basta usar o menu de contexto. A Figura 9 demonstra isto.
Figura 9. Adicionando interface

Ao escolher a opção do menu, uma janela se abre para que seja escolhido o
tipo do item que será acrescentado. O correto é usar a opção Interface que é a
maneira usada para definir o ServiceContract. Os detalhes da janela para a
criação da interface no projeto podem ser conferidos na Figura 10.

Figura 10. Incluindo uma interface no projeto

Ao fazer isto no tipo de projeto selecionado as referências para as bibliotecas


necessárias já são automaticamente importadas. No projeto, para simplificar o
trabalho, coloquei no mesmo arquivo o ServiceContract, representado pela
interface e também o DataContract. Observe na Listagem 2 a implementação
da interface.

Listagem 2. A interface para o ServiceContract

1 using System;
2 using System.Configuration;
3 using System.Runtime.Serialization;
4 using System.ServiceModel;
5
6 namespace InvestServiceDemo
7 {
8 [ServiceContract]
9 interface IInvestService
10 {
11 [OperationContract]
12 invest Target(double target, double monthlyQuota, DateTime
startDate);
13 }
14

No início da listagem são colocadas as referências para bibliotecas que são


necessárias na interface. Além da tradicional System, duas referências
precisam ser adicionadas. A referência para System.Configuration é
necessária quando se deseja usar classes que fazem leitura de dados
armazenados em arquivos de configuração do projeto. A classe responsável
por efetuar o cálculo irá ler a taxa a partir das configurações. Mais adiante,
quando a classe for explicada, mais detalhes serão dados, por hora, é
importante perceber que, sempre que for necessário acessar dados do arquivo
de configurações, deve se referenciar esta biblioteca.

Ainda com referência às configurações, será necessário adicionar uma


referência para System.Configuration no projeto. Para fazer isto os passos que
devem ser dados são simples, primeiro, deve se clicar com o botão direito do
mouse sobre o projeto e escolher a opção Add reference conforme é
demonstrado na Figura 11.
Figura 11. Adicionando uma referência ao projeto

Este passo é importante porque não é feita esta referência automaticamente no


projeto, como ocorre para as demais. Fazendo isto, será possível usar as
classes em System.Configuration. Retornando à listagem, outra biblioteca
importante que deve ser importada é System.Runtime.Serialization que é a
responsável por permitir a definição dos atributos [DataContract] que serão
usados na classe que irá expor os dados. A última biblioteca adicionada é
System.ServiceModel que permite definir o ServiceContract.

Em seguida, a linha 6 contém a definição do namespace. Este será usado no


arquivo .svc e então deve ser bem definido de forma que seja fácil fazer sua
referência no arquivo de configurações.

Logo em seguida está a definição do ServiceContract. Este é definido logo


acima da declaração da Interface (linha 8). Aqui cabem duas observações.
Primeiramente, a partir do Visual Studio 2010, não é obrigatória a colocação
dos atributos para ServiceContract e nem DataContract, porém, é boa prática
usá-los principalmente para que isto fique claro para o programador.

Em segundo lugar, no exemplo foi usado o prefixo “I” para o nome de uma
interface. É uma convenção e pode ser feito de forma diferente. Mais uma vez,
é boa prática também seguir este padrão, já que boa parte dos programadores
faz assim e mesmo os códigos de exemplo da Microsoft seguem esta prática.

O método que faz o retorno da operação é declarado na linha 12 e recebe os


parâmetros usados na operação. A ideia básica é fazer com que este método
retorne uma instância do tipo Invest, definido no DataContract. Esta classe
está definida na Listagem 3.

Listagem 3. O DataContract

15 [DataContract]
16 public class invest
17 {
18 [DataMember]
19 public double Target { get; set; }
20 [DataMember]
21 public double MonthlyQuota { get; set; }
22 [DataMember]
23 public DateTime StartDate { get; set; }
24 [DataMember]
25 public DateTime EndDate { get; set; }
26 [DataMember]
27 public int TotalMonths { get; set; }
28 [DataMember]
29 public double Final { get; set; }
30
31 public invest Estimate(double target, double monthlyQuota,
DateTime startDate)
32 {
33 Target = target;
34 MonthlyQuota = monthlyQuota;
35 StartDate = startDate;
36 TotalMonths = 0;
37 Final = 0;
38 double tax =
double.Parse(ConfigurationManager.AppSettings["tax"].ToString());
39
40 while (Final < Target)
41 {
42 Final = (Final + MonthlyQuota) * (100 + tax) / 100;
43 TotalMonths++;
44 }
45
46 EndDate = StartDate.AddMonths(TotalMonths);
47 return this;
48 }
49 }

A classe Invest expõe as seguintes propriedades através dos atributos


[DataMember]:

 Target – é a quantia final que deve ser atingida;


 MonthlyQuota – representa o valor mensal que será investido;
 StarDate – data inicial do investimento;
 EndDate – data final, que será calculada pela classe;
 TotalMonths – número total de meses que serão necessários para se
atingir o investimento;
 Final – o valor final atingido. Como o cálculo será feito dentro de um
loop, pode ser que o valor final ultrapasse o valor alvo a ser atingido.

Estas propriedades são usadas no método Estimate que está descrito a partir da
Linha 31. As propriedades precisam obrigatoriamente ter o get; set; informado
ou o serviço não funciona corretamente.

O método recebe os argumentos necessários para fazer o cálculo. Da linha 33


até a linha 37 as propriedades da classe têm os seus valores iniciais
configurados.

Para fazer o cálculo a classe vai obter a taxa a ser usada lendo este dado do
arquivo de configuração (linha 38). Esta sintaxe básica considera que a chave
de configuração está corretamente configurada no arquivo. Portanto, em um
serviço do mundo real é conveniente certificar-se de que um valor é retornado
ou uma exception será gerada e nada será retornado.

O cálculo é feito dentro de um loop while (linha 40). Note que os meses
(TotalMonths) vão sendo incrementados a cada cálculo feito. Por fim, é obtida
a data final para o investimento adicionando meses para a data inicial (linha
46). E o método retorna a instância atual da classe.

Nota do DevMan

Existem muitas maneiras de implementar o algoritmo que calcula o investime


nto. É possível ainda, com a linguagem C# fazer isto de maneira bem mais dir
eta, entretanto, gosto de fazer o código da maneira mais longa para que seja fá
cil sua compreensão. Lembrando que há pouca diferença para o compilador co
mo o cálculo é feito, se há ganho em desempenho, é mínimo, por outro lado, p
ara outros que forem ler o código, a diferença pode ser a compreensão correta
do que está escrito. Considere isto quando for fazer o seu código.
Implementando a classe do serviço
A classe exposta pelo DataContract faz todo o serviço, então resta pouco para
a classe do serviço. Esta deve implementar a interface e fazer a chamada para
o método Estimate da classe Invest. No projeto eu adicionei uma classe
usando novamente o menu de contexto da janela Solution Explorer. A classe
pode ser configurada na Listagem 4.

Listagem 4. A classe implementada para o serviço

1 using System;
2
3 namespace InvestServiceDemo
4 {
5 public class InvestService : IInvestService
6 {
7
8 public invest Target(double target, double monthlyQuota,
DateTime startDate)
9 {
10 return new invest().Estimate(target, monthlyQuota,
startDate);
11 }
12 }
13 }
14

O ponto mais importante da implementação da classe é fazer derivar da


interface IInvestService. Isto foi feito na linha 5. O método está definido a
partir da linha 8 e segue a assinatura que foi definida na interface.

Nesta implementação estou usando uma prática que é bem comum, em classes
que retornam poucos dados e tem poucas operações: usar o seu construtor para
fazer uma chamada ao método Estimate. A lógica disso já foi passada em
outros artigos, mas, relembrando, o construtor retorna uma instância da classe,
logo faz sentido fazer uma chamada de um método deste.

Como não será necessário usar a instância criada da classe, basta usar este tipo
de codificação para resolver o problema todo com apenas uma linha.

O arquivo SVC
O arquivo que publica o serviço deve ser adicionado ao projeto como um
novo item e com o nome InvestService.svc. O seu conteúdo deve ser a linha:

<%@ ServiceHost Service="InvestServiceDemo.InvestService" %>

Através da tag ServiceHost é definido o acesso ao serviço, que é configurado


no atributo Service. Observe atentamente que se trata do namespace mais o
nome da classe que implementa o serviço que foi especificado anteriormente.
Se houver falha neste ponto, não será possível acessar o WCF.

Diferentemente dos arquivos ASMX, não é necessário especificar o arquivo


.cs responsável pelo código. Se tiver dúvidas sobre como adicionar um
arquivo do tipo .svc no projeto, basta fazer da mesma forma que adiciona
qualquer item, ou seja, através do menu de contexto.

A diferença está apenas que se deve escolher um arquivo do tipo texto e


alterar a sua extensão para .svc. Tire as dúvidas, se necessário, na Figura 12.

Figura 12. Definindo o arquivo SVC

Configurando
O ponto fundamental do WCF é o arquivo de configurações. Em tempo de
projeto este arquivo é nomeado como “app.config” e pode ser encontrado na
janela Solution Explorer conforme demonstrado na Figura 13.
Figura 13. Arquivo de configurações

Este arquivo é um documento do tipo XML e segue um schema próprio.


Entretanto, ao se criar o projeto WCF usando o template correto, o mesmo
vem pré-definido com os principais elementos. No exemplo, foi necessário
editar o arquivo deixando com o conteúdo da Listagem 5.

Listagem 5. Configurações do serviço

1 <?xml version="1.0"?>
2 <configuration>
3 <system.web>
4 <compilation debug="true"/>
5 </system.web>
6 <appSettings>
7 <add key="tax" value="0.5" />
8 </appSettings>
9 <system.serviceModel>
10 <services>
11 <service name="InvestServiceDemo.InvestService"
behaviorConfiguration="InvestServiceDemo.ServBehavior">
12 <host>
13 <!--<baseAddresses>
14 <add
baseAddress="http://localhost:8732/invest/WCFDemo2/"/>
15 </baseAddresses>-->
16 </host>
17 <endpoint address="" binding="wsHttpBinding"
contract="InvestServiceDemo.IInvestService">
18 <identity>
19 <dns value="localhost"/>
20 </identity>
21 </endpoint>
22 <endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
23 </service>
24 </services>
25 <behaviors>
26 <serviceBehaviors>
27 <behavior name="InvestServiceDemo.ServBehavior">
28 <serviceMetadata httpGetEnabled="True"/>
29 <serviceDebug
includeExceptionDetailInFaults="False"/>
30 </behavior>
31 </serviceBehaviors>
32 </behaviors>
33 </system.serviceModel>
34 <startup>
35 <supportedRuntime version="v4.0"
sku=".NETFramework,Version=v4.0"/>
36 </startup>
37 </configuration>
38

Esta versão do arquivo, apesar de um pouco longa está bem resumida, se for
levar em consideração todas as possibilidades da sua estrutura.

Anteriormente foram explicadas quais as principais seções, então, vamos


aprofundar em algumas delas, principalmente aquelas que se referem às
configurações do serviço propriamente dito.

A seção representada pela tag <system.web> tem neste projeto a função de


especificar se o serviço está em versão debug, ou seja, se ao compilar o
serviço, informações de depuração devem ser incluídas. Isto deve ser
removido nos serviços que são publicados em servidores de produção.

Na seção seguinte está configurada a taxa para o cálculo através da chave


“tax”. É importante lembrar que, como se trata de um documento XML, o
mesmo é case sensitive e, caso isto não seja respeitado, a chave não poderá ser
recuperada corretamente.

A seção system.serviceModel (linha 9 em diante) é a mais importante pois


aninha todas as configurações do serviço. É possível configurar mais de um
serviço no arquivo de configuração, logo a tag Services, mantém estes
armazenados e configurados na tag service da linha 11.

Neste ponto o atributo name configura o namespace e a classe responsável por


executar a operação no assembly que é gerado após a compilação. Já o
atributo BehaviorConfiguration referencia uma chave de configuração que é
armazenada neste arquivo na tag behaviors e é responsável pelo nome e pelo
comportamento do WCF.

Na seção host pode-se configurar um endereço tcp ou HTTP para que o


serviço seja acessado. Neste caso, deixei comentado porque o endereço será
dado pelo IIS quando o mesmo for publicado.

A tag endpoint configura aspectos do serviço e de como este pode ser


localizado. No exemplo deixei em branco o atributo address já que,
novamente, é o IIS que fará a definição deste. Neste arquivo está definida em
dois pontos. Na sua primeira ocorrência, na linha 17, configura o serviço
propriamente dito, na segunda, na linha 22, especifica configurações para o
acesso e a geração do documento WSDL.

O atributo binding (ainda na linha 17) refere-se ao protocolo que será usado
para acessar e descobrir o serviço. No caso, wsHttpBinding indica um
tratamento mais aprofundado usando o protocolo HTTP e que deve ser usado
sempre quando se trabalha com o IIS.

Outra possibilidade que pode ser usada é basicHttBinding, mas é mais


limitada para ser usada com o IIS. Existem vários protocolos suportados, é
interessante procurar a documentação referente para usar o que seja mais
adequado ao ambiente em que o serviço irá rodar. É importante lembrar que
mesmo usando o IIS é possível usar também o protocolo tcp, mas,
configurações devem ser feitas.

O atributo contract expõe o namespace e o ServiceContract – definido na


interface no código – para que o serviço seja executado. É importante ressaltar
que se deve colocar corretamente o namespace e a interface corretamente
nomeados neste ponto. Aqui pode fazer diferença em se usar ou não o prefixo
“I” para nomear interfaces, uma vez que tanto a classe como a interface
devem ser referenciadas nas configurações.

A tag identity especifica dados do servidor. Estes podem ser omitidos e no


exemplo que foi desenvolvido, foi usado o nome localhost mesmo, já que não
será acessado por aplicações externas.

Finalizando a tag <service> encontramos mais uma ocorrência da tag


<endpoint> na linha 22. Aqui é responsável por definir a geração do
documento WSDL que contém os padrões para a geração da classe proxy.
Lembrando que, quando um Web Service ou WCF for consumido por
aplicações escritas no Framework .Net e usando o Visual Studio, ao fazer a
referência ao serviço, através do documento WSDL é que a classe proxy é
gerada. Mais sobre classe proxy e documento WSDL mais à frente quando
estiver tratando da aplicação cliente.

A seção behaviors configura entre outros aspectos, se é possível visualizar os


dados básicos do WCF usando um browser, por exemplo. Este
comportamento é útil principalmente porque permite que se tenha acesso ao
documento WSDL. O principal atributo responsável por este comportamento
está definido na tag serviceMetadata (linha 28) através do atributo
httpGetEnabled.

Lembre-se também de que o atributo name informado aqui na linha 27 deve


corresponder ao mesmo que está informado no atributo
behaviorConfiguration, na linha 11.

As configurações deste arquivo estão muito restritas ao exemplo que foi dado.
Não estão sendo considerados aspectos como disponibilização de outros
protocolos como net.tcp. Nem foi feito um ajuste fino no endereçamento do
servidor. Existem vários ajustes que podem ser feitos.

Uma boa dica, que foi dada anteriormente ao tratar do arquivo de


configuração, que existe, nas máquinas onde o Visual Studio é instalado, um
aplicativo chamado Service Configuration Editor. Com certeza, editar o
arquivo .config na mão é bem difícil e deve ser evitado sempre que possível.

Publicando o serviço no IIS


Para que o projeto seja publicado no IIS alguns passos iniciais devem ser
tomados:

1. Verificar sua instalação no sistema e se já possui suporte a ASP.NET e


WCF. Isto foi demonstrado anteriormente ao tratar do IIS;
2. Gerar a DLL do projeto WCF;
3. Configurar o arquivo .config conforme a necessidades;
4. Gerar o arquivo .scv;
5. Criar a pasta correspondente a aplicação dentro da estrutura do servidor
e copiar para lá a pasta bin contendo a DLL do serviço e os arquivos
.svc e .config, este devendo ser renomeado para web.config.

A estrutura de pastas do servidor, se for seguida uma instalação típica irá ficar
da forma como é apresentada na Figura 14.
Figura 14. Pasta do serviço com os arquivos

Com o conteúdo copiado para as pastas e o IIS aberto é hora de criar a


aplicação. O IIS permite criar pastas virtuais e aplicações, sendo que o mais
indicado no caso do WCF é a segunda opção.

Normalmente isto é feito clicando com o botão direito sobre o ícone do site
padrão (Default Web Site) e escolhendo a opção Add Application. Esta irá
abrir uma janela onde devem ser fornecidos os dados do Alias da aplicação,
que é o endpoint do WCF. Outro campo que deve ser preenchido é a
localização da pasta dentro do servidor (no campo Physical Path).

Outro detalhe muito importante é configurar o Application Pool padrão que


será usado. Isto é feito ainda na janela Add Application acessando o botão
Select, ao lado do campo Application Pool. Os detalhes desta operação podem
ser conferidos na Figura 15.
Figura 15. Passos para incluir a aplicação

Este processo, se finalizado corretamente fará com que o WCF apareça na


pasta do site padrão e esteja imediatamente disponível para acesso pelo
browser (Figura 16).

Um teste padrão é abrir o navegador e digitar o endereço desejado para que a


página do serviço seja exibida. No caso do exemplo, o endereço que deve ser
digitado é:

http://localhost/investDemo/service.svc
Figura 16. O serviço publicado

E é este também o endereço que deve ser passado para a aplicação cliente
quando for fazer referência ao serviço e se criar a classe proxy.

Consumindo o serviço
Normalmente, se o serviço está acessível pelo browser é um forte indicador de
que tudo está funcionando bem. Entretanto, diferentemente dos Web Services,
não é possível testar o seu funcionamento através do browser.

A melhor alternativa então é criar um projeto do tipo Console para testar seu
funcionamento e foi isto que foi feito.

O projeto foi criado no Visual Studio em uma solution separada do WCF. O


caminho é o padrão para criação de novos projetos: File > New > Project. Os
detalhes usados para definir o projeto podem ser conferidos na Figura 17.

Figura 17. Detalhes da criação do projeto console

Não há restrições quanto ao tipo de aplicação que pode consumir serviços


WCF no Framework .Net. Console, Windows Forms, ASP, MVC e Class
Library, entre outras. A escolha pelo Console recaiu aqui apenas para focar
nas tarefas relacionadas com o WCF e não em ficar configurando controles
visuais na tela.
O principal aspecto das aplicações que consomem serviços WCF é a
necessidade de se acrescentar uma referência a este. Como o Visual Studio
oferece assistentes para a maior parte das tarefas, não é diferente com o WCF.
Para iniciar as tarefas para referenciar um serviço basta usar o menu de
contexto da janela Solution Explorer (que normalmente é acessado ao se usar
o botão direito do mouse) e escolher a opção Add Service Reference (Figura
18).

Figura 18. Inserindo referência ao serviço - acessando pelo menu

A janela Add Service Reference é aberta e é preciso passar o endereço do


serviço como foi demonstrado anteriormente. Usando o assistente o primeiro
passo é digitar nesta janela o endereço no campo Address e clicar no botão Go
para que seja iniciada a descoberta do mesmo (Figura 19).
Figura 19. Informando o endereço

Também é conveniente que nesta etapa já seja definido um namespace que


será usado para a criação da classe proxy ao término da importação da
referência. Se o serviço for descoberto com sucesso, a janela irá apresentar os
serviços que podem ser acessados conforme a Figura 20 demonstra. O passo
seguinte é selecionar o serviço correspondente ao que foi definido na interface
Operation Contract. No exemplo, este é representado por IInvestService.
Figura 20. Visualizando detalhes do serviço

Relembrando este processo, quando um endereço de um serviço válido é


digitado e localizado, o Visual Studio trata de ler o documento WSDL e criar
a classe proxy.

WSDL é a sigla para Web Services Description Language e corresponde ao


documento que descreve as operações de um Web Service ou WCF. Este
documento permite que o Visual Studio crie a classe que será usada pela
aplicação cliente para acessar o serviço remoto como se este estivesse sendo
executado localmente. Esta classe não deve ser editada, como já foi assunto de
artigo anterior e, caso ocorra alguma modificação no serviço, como novas
operações acrescentadas, deve ser atualizada.

Após a importação da referência esta deve aparecer dentro da pasta Service


References na janela Solution Explorer como a Figura 21 demonstra.
Figura 21. Classe proxy e arquivo de configurações

Configurando o acesso
Ao fazer a referência, um arquivo de configurações chamado app.config é
gerado e populado dentro da solução já contendo todos os elementos
essenciais para que a aplicação possa se comunicar corretamente com o
serviço. O conteúdo completo deste pode ser conferida na Listagem 6.

Listagem 6. O arquivo de configurações

1 <?xml version="1.0" encoding="utf-8" ?>


2 <configuration>
3 <system.serviceModel>
4 <bindings>
5 <wsHttpBinding>
6 <binding name="WSHttpBinding_IInvestService"
closeTimeout="00:01:00"
7 openTimeout="00:01:00" receiveTimeout="00:10:00"
sendTimeout="00:01:00"
8 bypassProxyOnLocal="false" transactionFlow="false"
hostNameComparisonMode="StrongWildcard"
9 maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" messageEncoding="Text"
10 textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
11 <readerQuotas maxDepth="32"
maxStringContentLength="8192" maxArrayLength="16384"
12 maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
13 <reliableSession ordered="true"
inactivityTimeout="00:10:00"
14 enabled="false" />
15 <security mode="Message">
16 <transport clientCredentialType="Windows"
proxyCredentialType="None"
17 realm="" />
18 <message clientCredentialType="Windows"
negotiateServiceCredential="true"
19 algorithmSuite="Default" />
20 </security>
21 </binding>
22 </wsHttpBinding>
23 </bindings>
24 <client>
25 <endpoint address="http://vladimir-
note/investDemo/service.svc"
26 binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IInvestService"
27 contract="investService.IInvestService"
name="WSHttpBinding_IInvestService">
28 <identity>
29 <dns value="localhost" />
30 </identity>
31 </endpoint>
32 </client>
33 </system.serviceModel>
34 </configuration>

Novamente, trata-se de um arquivo complexo de ser editado manualmente,


principalmente porque seu conteúdo é gerado por ferramentas automatizadas.

Entretanto, dificilmente este deverá ser editado manualmente, provavelmente,


você vai precisar, em um ambiente de produção, alterar as configurações da
tag <client> a partir da linha 24.

Esta define o endereço do serviço no atributo address da tag endpoint (linha


25), se você observar, é o mesmo endereço usado para fazer referência ao
serviço.
O atributo binding corresponde à configuração usada para o protocolo http
que é a mesma que está no arquivo de configuração do WCF.

Também está presente um atributo para configuração local do binding


representado por bindingConfiguration. Este refere-se a uma chave definida
na linha 6 do arquivo de configuração.

O atributo contract se refere ao OperationContract que foi especificado no


WCF e no arquivo .svc e por este motivo, se percebe a importância da correta
elaboração deste ponto ao se escrever a interface.

A tag binding cuida da maneira como é feita a conexão. Estou omitindo aqui
maiores explicações sobre a mesma pois, normalmente, esta configuração é
feita automaticamente ao se fazer a referência ao serviço e não ser necessário
executar ajustes. Se estiver procurando maiores dados, é importante ler a
documentação da própria Microsoft sobre estas configurações que é extensa.

Novamente é bom lembrar que estas configurações, assim como as do WCF,


podem ser mais facilmente editadas através do aplicativo Service
Configuration Editor.

Consumindo o serviço
Ao fazer a referência para o WCF é gerada a classe proxy cujo principal
objetivo é permitir ao programador trabalhar com objetos remotos como se
estivessem localizados na máquina de trabalho.

O código da Listagem 7 demonstra como foi desenvolvido o código da


aplicação para invocar e consumir o serviço.

Listagem 7. Código da aplicação client

1 using System;
2 using System.Text;
3
4 namespace WCFConsoleDemo
5 {
6 class Program
7 {
8 static void Main(string[] args)
9 {
10 double target = 100000D;
11 double mQuota = 200D;
12 var initialDate = DateTime.Today;
13 var item = new
investService.InvestServiceClient().Target(target, mQuota,
initialDate);
14 var sb = new StringBuilder();
15 sb.AppendFormat("{0, -20}{1, 20:c}\n", "Target",
item.Target);
16 sb.AppendFormat("{0, -20}{1, 20:c}\n", "Monthly Quota",
item.MonthlyQuota);
17 sb.AppendFormat("{0, -20}{1, 20:dd/MM/yyyy}\n", "Start
Date", item.StartDate);
18 sb.AppendFormat("{0, -20}{1, 20:dd/MM/yyyy}\n", "End
Date", item.EndDate);
19 sb.AppendFormat("{0, -20}{1, 20}\n", "Total Months",
item.TotalMonths);
20 sb.AppendFormat("{0, -20}{1, 20}\n", "Years",
item.TotalMonths / 12);
21 sb.AppendFormat("{0, -20}{1, 20:c}\n", "Final",
item.Final);
22 Console.WriteLine(sb.ToString());
23 }
24 }
25 }
26

Diferentemente do WCF, o aplicativo cliente, uma vez configurado, não


precisa de muita coisa para consumir. O programa contém o código básico
para qualquer aplicação console.

Das linhas 10 à 12 são declaradas e inicializadas as variáveis com os valores


para serem enviados para o serviço. Na linha 13 ocorre a chamada para o
serviço da mesma forma direta que demonstrei anteriormente. Observe que é
possível usar a palavra-chave var do C# porque há um retorno de uma
instância do objeto Invest que é devolvido pelo WCF.

Para produzir uma saída minimamente formatada eu optei por usar a classe
StringBuilder que inclusive deve ser usada para evitar concatenação de
strings. Na linha 14 é criada a instância desta.

Das linhas 15 à 22 é enviado o conteúdo a ser formatado. O método


AppendFormat funciona seguindo o princípio de outro método muito
conhecido, o String.Format(). A expressão que está usada segue um padrão
muito fácil de entender:

{<índice>, [<quantidade de espaços>]:[<expressão de formatação>]}


Todas as expressões devem vir encerradas entre chaves, assim é possível ter
várias em uma mesma string. O primeiro argumento é obrigatório e é um
número inteiro que representa o índice com base zero do objeto a ser
formatado.

Se for passado o segundo argumento – a quantidade de espaços – que é


opcional, deve-se usar a vírgula. Este número tem dois comportamentos
distintos. Se for usado um número maior do que zero, o texto fica alinhado à
direita, senão o alinhamento é feito à esquerda. No caso do exemplo, o
primeiro elemento, que é uma string, ficou alinhado à esquerda e o segundo à
direita. Por fim, o terceiro argumento, que também é opcional, é uma
expressão de formatação que é muito comum com o String.Format.

Ao executar o programa, deve ser exibida uma tela parecida com a da Figura
22.

Figura 22. O projeto sendo executado

Conclusão
Web Services já eram robustos para desenvolvimento de serviços distribuídos.
Os WCF acrescentaram mais recursos, embora com um pouco mais de
complexidade. Sob o ponto de vista das boas práticas, obriga o desenvolvedor
a pensar melhor no seu código e estruturá-lo de forma mais organizada, já que
deve explicitamente estabelecer o contrato para os serviços e para os dados
que serão expostos.

A configuração está longe de ser uma das tarefas mais simples e requer muita
atenção, o aspecto negativo é que é muito fácil bagunçar tudo e deixar o
serviço inoperante. O aspecto positivo das configurações é que se pode usá-las
para refinar o comportamento do aplicativo e, dependendo da forma que se
escreve o código, pode-se fazer customizações apenas usando os arquivos de
configuração.
O artigo procurou dar uma visão em mais alguns detalhes. Existe um aspecto
do WCF que é muito interessante que é a possibilidade de realizar call-backs
com a aplicação cliente, ou seja, o aplicativo cliente interage com o WCF e
este pode, de formas bem distintas, interagir com a aplicação cliente. Espero
poder tratar deste assunto em um artigo em breve.

Links

Blog com vários artigos sobre wcf


http://blogs.msdn.com/b/rafaelgodinho/archive/tags/wcf/

Callback
http://blogs.msdn.com/b/rafaelgodinho/archive/2010/12/23/callback-com-wcf.
aspx

Problemas ao hospedar arquivos .svc no IIS


http://blogs.msdn.com/b/rafaelgodinho/archive/2010/03/11/problemas-ao-hos
pedar-arquivos-svc-no-iis.aspx

How to: Host a WCF Service in IIS


http://msdn.microsoft.com/en-us/library/ms733766.aspx

WCF - Hosting
http://www.israelaece.com/post/WCF-Hosting.aspx

Configuring WCF and IIS 7 With HTTP Bindings and Multiple Host Hea
ders
http://keithelder.net/2008/04/28/configuring-wcf-and-iis-7-with-http-bindings-
and-multiple/

How To: Hosting a WCF Service in IIS


http://blogs.msdn.com/b/trobbins/archive/2006/11/27/how-to-hosting-a-wcf-se
rvice-in-iis.aspx
http://blah.winsmarts.com/2008-4-Host_a_WCF_Service_in_IIS_7_-and-amp;
_Windows_2008_-_The_right_way.aspx

Running a WCF Service on IIS 7


http://weblogs.asp.net/dwahlin/archive/2009/07/21/running-a-wcf-service-on-i
is-7.aspx

WCF Client Configuration


http://msdn.microsoft.com/en-us/library/ms731745.aspx

Getting Away with Client Config in WCF


http://www.codeproject.com/KB/webservices/WCFService_config_problem.a
spx
WCF Essentials—Programmatic Client Configuration
http://en.csharp-online.net/WCF_Essentials%E2%80%94Programmatic_Clien
t_Configuration

Hospedando um serviço WCF no IIS


http://blogs.msdn.com/b/rafaelgodinho/archive/2009/04/02/hospedando-um-se
rvi-o-wcf-no-iis.aspx

Deploying WCF Tutorial App on IIS7: "The type could not be found"
http://stackoverflow.com/questions/2739465/deploying-wcf-tutorial-app-on-ii
s7-the-type-could-not-be-found

WCF: The type provided as the Service attribute could not be found
http://thejoyofcode.com/WCF_The_type_provided_as_the_Service_attribute_
could_not_be_found.aspx

Thread: Handling WCF in IIS7


http://forums.iis.net/t/1149591.aspx

WCF Hosting – Issues with VS2010 and Fresh IIS 6


http://basharatspace.blogspot.com/2010/12/wcf-hosting-issues-with-vs2010-a
nd.html

Blogs
http://vladimirrech.blogspot.com.br
http://twitter.com/vladimirrech

por Vladimir Rech


Guru .net e tecnologias MS

Você também pode gostar