Introdução
Com o recém-lançado Visual Studio 2010, o C# passou por diversas melhorias. E para quem trabalha com automação do Excel utilizando VSTO (Visual Studio Tools for Office), a situação melhorou muito para o desenvolvedor C#. Até a versão anterior simplesmente não compensava o esforço de se fazer add-ins para Office utilizando C#. Por ser uma linguagem fortemente tipada e com tipagem estática, ao acessar os objetos COM do modelo de objetos do Office, era necessário realizar múltiplos casts para objetos em .NET existentes nos PIAs (Primary Interop Assemblies). Os PIAs, contêm o modelo de objetos de cada aplicação Office (Excel, Word, etc…) representados por “cópias” em .net de objetos COM. Para trabalhar com o modelo de programação do COM o VB.NET sempre foi melhor, permitindo parâmetros opcionais, variants e etc…, coisas até então inexistentes em C#.
O C# 4.0 agora suporta o sistema de tipagem conhecido por “tipagem dinâmica”. A tipagem dinâmica permite que o você chame métodos e propriedades que serão apenas resolvidos em tempo de execução, similar ao que acontece em Javascript. Essa resolução em tempo de execução é mais arriscada, mas, quando você bem o modelo de objetos, permite um código muito limpo, com quase nenhum cast desnecessário.
Na prática, com o C# 4.0, temos o mesmo poder de criar customizações para o Office utilizando a plataforma .NET que o VB.NET já oferecia. Com grande simplicidade, podemos criar aplicações muito legais e mais baratas, afinal, é possível usar todas as vantagens do Excel para manipular meus dados, sem a chatice de criar páginas em Web só para isso…
Nosso Exemplo
Este exemplo tentará ser um pouco mais completo. Vamos utilizar várias tecnologias para conseguir atingir nossos objetivos. Como ferramentas, utilizamos o VS2010 final, o Excel 2010 e o SQL Server 2008. Vamos realizar os seguintes passos:
1) Instalar os bancos de dados de exemplo do SQL Server 2008
2) Utilizar o Entity Framework para mapear os dados para a minha aplicação
3) Criar o serviço WCF que retorna a lista de produtos
4)Realizar testes simples do modelo e serviço
5) Adicionar a referência do serviço WCF ao Excel
6) Trazer os dados para o Excel
7) Trabalhar com os dados utilizando o C# e VSTO
Vamos detalhar cada passo com imagens, resolução de dúvidas mais recorrentes e vamos explicar tudo passo a passo. Vamos pra cima então!
Instalando o AdventureWorks para o SQL Server 2008
Atualmente os bancos de exemplo estão no CodePlex. O link para baixar os bancos de exemplo é: http://msftdbprodsamples.codeplex.com/releases/view/37109. Vale notar que para o exemplo temos instalado o SQL Server 2008 e não o R2, que saiu recentemente. Os bancos de exemplo são criados para cada versão do SQL Server e é importante instalar a versão adequada. Para esse teste, funciona qualquer versão do SQL Server.
Ao instalar, a dica é liberar antes o FILESTREAM para a instância do SQL Server 2008. Se não fizer isso antes, o instalador não coloca todas as versões do AdventureWorks. O instalador é bem inteligente e já faz a instalação de todas as versões do AW. Entre elas, tem uma versão Light, que é a que utilizamos no exemplo deste post.
Criando o modelo de dados com o Entity Framework
O EF nesta versão do .NET está com mais funcionalidades, entre elas, a possibilidade de criar modelo de dados em .NET e depois criar o banco de dados. Mas como já temos o banco de dados pronto, vamos criar um modelo de dados da forma mais simples possível, utilizando as opções padrão.
Antes de começar, criamos um projeto do tipo Class Library contendo uma pasta chamada BusinessEntities. Adicionamos a esta pasta um modelo de dados do EF:

Criamos uma conexão com o banco de dados AdventureWorksLT2008.

Utilizamos estas tabelas do modelo:

O modelo de dados ficou desta maneira:

Até aqui nada demais. Estamos usando o EF para automatizar o acesso a dados, sem grandes mistérios.
Criando o Serviço WCF que retorna a lista de produtos
Para este caso vamos hospedar o serviço no próprio IIS, utilizando as opções padrão do WCF. No caso vamos apenas renomear o serviço e as classes/interfaces para facilitar o uso deste serviço pelos clientes.
Após renomear os serviços, a solução ficou próxima disso:

O nome do serviço é ProductService e o método que traz todos os produtos se chama “GetAllProducts”. Veja o detalhe do código abaixo:

O método retorna uma lista de produtos que é trazida da biblioteca onde está guardado o modelo de dados do EF. Neste caso, abrimos o contexto que contém as entidades, obtemos os dados com o select e com o ForEach das listas genéricas, presente desde o .NET 2.0, utilizamos uma lambda expression que solicita que cada item da lista seja “desatachado” do contexto de dados do EF. Com isso, eu consigo passar a lista de produtos para os clientes remotos. Se eu não fizer o Detach, acontecerão vários erros ao trabalhar com os itens da lista de produtos, como por exemplo, tentativas de se conectar ao store de dados diretamente do cliente.
Vale lembrar que a string de conexão ao model deve ser declarada no arquivo de configuração do serviço. O construtor do AdventureWorkdLT20008Entities, objeto de contexto do EF responsável por controlar as operações com as entidades, sempre olha o arquivo de configuração para realizar a abertura da conexão. A imagem abaixo mostra o web.config com a informação de string de conexão ao modelo de dados do EF.

E finalmente, o serviço funcionando de forma padrão fica assim:

Na prática este é o jeito mais simples possível de se criar um serviço WCF. Não temos muitos segredos até o momento…
Testando o modelo de dados e o serviço WCF
Embora opcional, este passo consideramos muito importante para o desenvolvimento de qualquer coisa, desde um simples exemplo a uma complexa aplicação. Vamos realizar testes unitários muito simples capazes de indicar que o sistema está pronto para ser chamado do Excel. Não será preciso apelar para TDD neste caso pois nossos métodos são extremamente simples de serem testados. E não vamos contar com falhas como eventuais quedas do banco e do serviço, pois afinal, estamos querendo trabalhar mesmo é o com o Excel neste artigo. Vamos usar a estratégia de testes conceituais para este exemplo.
Crie um projeto usando o template de testes do VS2010. Adicione referência ao projeto contendo o DataModel. Adicione também uma referência ao serviço criado no passo anterior. As imagens mostram como referenciar o serviço ao projeto de testes. Basicamente o VS2010 identifica nos projetos da solução onde há um serviço WCF existente e puxa suas informações públicas, mostrando-as para nós.


Na guia “Advanced”, costumamos utilizar o List ao invés do Array para trabalhar com conjuntos de entidades por ser muito mais prático. Mas isso é opcional. Nós renomeamos a referência para ProductServiceReference para ficar mais legível no código final, pois este namespace que guardará o proxy do serviço WCF.
Com isso, vamos para o teste do modelo de dados:

Neste primeiro testes, conseguimos provar que o modelo funciona. E para comprovar, inicialmente coloquei um trace para que o teste escreva na janela de output o código e o nome de cada produto existente no banco. E o teste também contém um asserção para provar que há dados no banco para os testes. O teste executou ok. Fizemos o mesmo para o método que testa se o serviço realmente retorna dados.

Este teste realmente demorou mais para passar. Tínhamos nos esquecido de desatachar os objetos do contexto e por isso os dados nunca vinham. Outro erro que acontecia era o tamanho do conjunto de dados. O arquivo de configuração vem por padrão com um tamanho reduzido de bytes de tamanho da resposta. Tivemos que aumentar o tamanho do pacote no app.config do projeto de testes.
Vale lembrar que é recomendável sempre fechar o proxy do serviço WCF. Com o fechamento, o WCF libera os recursos como threads e alocações de memória que ele prepara para cada conexão ativa no serviço. E quando estamos trabalhando com o conceito de sessões no WCF, o fechamento indica o término de uma sessão. Abaixo mostramos o resultado final da tela de testes que o Visual Studio mostra quando os testes passam:

Como sempre, podemos debugar o teste, e no debug, podemos passar do cliente para o servidor na mesma execução. Com o F10, posso andar em cada método que é executado, e, se o cliente chama o servidor, o debug vai para o servidor e continua a execução, permitindo que tenhamos pleno controle da situação. Colocando o breakpoint tanto no servidor como no cliente, você sempre terá a informação de quem chamou quem e o que aconteceu durante as chamadas.
Criando uma customização de uma planilha do Excel 2010 com o VS2010
É possível customizar tanto documentos como a própria aplicação. Neste exemplo não é necessário criar uma customização do Excel, apenas é preciso adicionar novas funcionalidades a apenas uma planilha. Com isso, vamos optar pelo template de projeto Excel 2010 Workbook:

Ao prosseguir, teremos um projeto e um documento criado. Teremos algumas classes em .NET representando cada planilha do documento:

Como podemos ver, na prática um projeto com VSTO é muito similar a um projeto comum em .NET. Podemos adicionar novos itens, outras classes, referenciar outros projetos e muito mais. Neste exemplo, a referência ao serviço já foi adicionada ao projeto. Também por padrão é adicionado um certificado temporário para que o projeto possa ser aceito pelo Office.
Antes de prosseguir é preciso esclarecer alguns pontos – vamos focar esta seção mais no Excel, mas as perguntas e respostas são válidas para outros programas.
- O que é o VSTO? O VSTO nada mais é do que o conjunto de ferramentas necessário para se trabalhar com o Excel utilizando o .NET. É composto de bibliotecas de classes, ferramentas gráficas e customizações do Excel necessárias para que o Add-in seja reconhecido e corretamente visualizado no Excel. Também é responsável por se comunicar com os objetos COM do modelo do objetos do Excel e realizar adequadamente as ações desejadas. E por fim, o VSTO possui um conjunto interessante de eventos trazidos do Excel para o .NET, de forma que é possível saber no .NET quando por exemplo, alguém altera uma determinada célula da planilha.
- Como eu faço para conhecer o modelo de objetos do Excel? Para trabalhar com a automação é necessário ter noção de como se cria macros no VBA. Uma macro do Excel pode ser transcrita para o C# com certa simplicidade. O modelo de objetos está muito bem documento na ajuda do VBA. Para mostrar a tela do VBA do Excel, use ALT + F11. Finalmente, use o Gravador de Macros do Excel para ir aprendendo os comandos e sintaxe mais comuns do Excel.
- Vejo alguns namespaces que estão me confundindo. Para se trabalhar com o Excel, temos as bibliotecas principais representadas por Microsoft.Office.Interop.Excel e Microsoft.Office.Core. Essas bibliotecas contêm basicamente uma representação em .NET do que o Excel contém. Elas são os famosos PIAs. Se na tela do VBA você achar um objeto denominado Chart, no objeto equivalente em .NET você provavelmente também encontrará o Chart. Vale notar que as traduções em .NET são feitas com interfaces e não classes concretas em .NET. Mas na prática, você conseguirá controlar o objeto da mesma forma, chamando os métodos com os mesmos nomes e parâmetros vistos no VBA. Porém, existe um outro namespace que mora em outra biblioteca do VSTO denominada Microsoft.Office.Tools.Excel. Este último namespace guarda objetos em .NET que representam os principais recursos do Excel em .NET, melhorados de forma a se tornarem particularmente úteis. Eles contém uma representação bacana do Workbook, Worksheet, ListObject, NamedRange e alguns outros elementos. Tais elementos podem ser criados diretamente do .NET usando o designer do Visual Studio, muito similar à criação de um controle utilizando Windows Forms. Com isso, o desenvolvedor tem como referenciar de forma simplificada os objetos importantes de sua planilha.
- Qual o melhor jeito de começar com os testes simples? O ideal é trabalhar com o Globals. Esta classe contém uma referência para todos os objetos do Tools.Excel de forma simples. Para acessar a planilha1, basta pedir Globals.Sheet1 e por aí vai… vamos mostrar na prática como funciona a referência a tais objetos. Brinque com o Range, com o Offset, modifique os conteúdos da célula… Para rodar basta utilizar o F5 comum para fazer os testes. O add-in é carregado e o Visual Studio consegue se atachar ao código .NET que está executando na planilha. Logo, é possível colocar breakpoints no VS2010 e olhar o que está em cada variável. Também é possível utilizar janelas como Immediate Window para realizar testes preliminares sobre a validade de suas expressões. O desenvolvimento para Office exige uma carga adicional de tentativa e erro para realizar uma determinada tarefa. E com o Visual Studio você tem total suporte a isso. Recomendamos que você tenha calma pois muitas vezes poderá acontecer um erro de COM impossível de descobrir pelo fato de não se ter um modelo legal de controle de erros como o .NET. Não se assuste. Vá por partes. Tenha certeza que cada pedaço da expressão funcionou. Lembre-se de não usar índice zero com o Range e laços For. Use e abuse do Immediate Window. Use Listas e Named Ranges – evite lógica com o número/nome da range. Por fim, domine o Excel.
- E o Ribbon? Como trabalhar com ele? O Ribbon, que é o menu inovador lançado no Office 2007, também continua presente no Office 2010. Na verdade, ele foi ligeiramente modificado no Office 2010 – foi criado um “Backstage Ribbon” no 2010, que contém opções que geralmente ficariam no menu Arquivo. Esse backstage ribbon se chama File na versão americana do Office. No .NET, é um controle que pode ser adicionado ao projeto, com um code-behind contendo eventos convenientes. No designer do VS2010 é possível arrastar e soltar itens para o Ribbon e amarrar eventos a cada botão de forma normal, como se fosse em Windows Forms. Para o desenvolvedor, o Ribbon é uma aba que fica no dentro do menu Add-ins do Excel. E para o desenvolvedor, o Ribbon nada mais é que um form cheio de controles comuns. Simples e prático de usar. O Ribbon pode ser criado mesmo em customizações de documentos. Não necessariamente vale só para customização de aplicações.
Antes de prosseguir com a customização, fizemos um teste básico para ver se realmente era possível chamar o WCF de dentro do Excel. Embora isso pareça ser óbvio, não necessariamente tudo acontece conforme o esperado. No evento que é chamado quando o arquivo abre, colocamos o seguinte teste:

Entretanto, ocorreu um erro. Ao dar F5, o Excel tenta abrir:

Mas em seguida surgiu uma mensagem de erro:


Conforme esperado, o conjunto de dados era maior do que o padrão (conforme visto nos testes). Deixamos este erro acontecer para demonstrar que quando o erro acontece você pode parar, debugar e continuar com a execução. Não recomendamos que você mate o processo dando stop na depuração. Sempre continue com F5 e só então termine a execução. As falhas podem acontecer e quando acontecem, o Excel lança o erro neste formato mostrado acima e continua normalmente a rodar, sem cair.
Finalmente acertamos o config da aplicação e testamos novamente com sucesso.

Trazendo dados do WCF para o Excel
Tendo a certeza de que o WCF estava trazendo os dados e que o Excel é capaz de mostrar os dados, vamos para o próximo passo: mostrar os produtos na planilha do Excel.
Para isso, crie uma nova tabela na planilha principal com 2 colunas. Assuma que as colunas terão um header. Como as tabelas devem ter um nome, nós alteramos para tblProdutos:

Esta funcionalidade se chama “Tabela” no Office 2007 em diante. No Office 2003 esta funcionalidade se chama “Lista”. Por isso que no .NET ela também se chama ListObject. Com o uso de tabelas, os dados ficam muito mais organizados do que em planilhas comuns, sendo uma forma muito inteligente de trabalhar com dados no Excel, mesmo quando não estamos fazendo coisas tão avançadas como Macros e customizações com .NET.
O próximo passo é criar o Ribbon, que será mostrado ao usuário final e terá alguns itens para podermos realizar nossos exemplos. Ao escolher a opção Add New Item do projeto Excel, no VS2010 aparecerá vários itens. Vá no subgrupo Office e escolha a opção Ribbon (Visual Designer). É possível criar um Ribbon editando um arquivo XML específico diretamente – modo avançado de se trabalhar com o Ribbon.

O editor visual mostra o Ribbon vazio. Devem ser adicionados os controles ao Ribbon usando o designer visual por ser mais prático.

Com o Ribbon pronto, vamos fazer o código busca a lista no WCF e faz o databind com o ListObject do VSTO/Table do Excel. O código que executa é um evento do click do botão de dentro do Ribbon. Logo, ele não está em nenhuma planilha. Portanto é preciso referenciar os objetos de interesse utilizando a classe Globals. Vejamos como fazer isso:

A classe Globals é gerada automática pelo template do VS2010 e representa como propriedades estáticas os objetos importantes do documento Excel. O Sheet1 é uma representação melhorada da planilha para uso em .NET e não o Sheet do Interop. O tblProdutos é um campo do objeto .NET Sheet1.
O método SetDataBinding permite fazer o databind com qualquer conjunto de dados comum do .NET. No caso, este método possui a capacidade de escolher quais colunas podem ser mostradas ou não. O segundo parâmetro está vazio, mas por exemplo, poderia ser o nome da tabela que esteja dentro do Dataset no caso de múltiplas tabelas.
Com o databinding, eu consigo colocar os dados na lista sem ter que me preocupar com o número de linhas na lista, redimensionamento e sem ter que usar um laço For para processar cada registro. Muitos incômodos a menos. Com isso a lista preenchida fica conforme mostra a figura abaixo. O Ribbon tem mais 2 botões que serão úteis para os testes seguintes em cima da lista preenchida. Note que o Ribbon que montamos ficou dentro da aba Add-Ins. Nesta aba ficam também os outros add-ins de fabricantes diversos.

Trabalhando com os dados obtidos no Excel utilizando C# 4.0
A nossa Ribbon agora deverá ter mais dois botões conforme mostrado na tela acima. No designer ela fica assim:

O botão “Trabalhar com Lista” irá mostrar os 10 primeiros registros da lista. Desta forma poderemos ver algumas novidades que o C# 4.0 tem para nos ajudar nesta tarefa.
Antes de mostrar o método completo temos que comentar sobre os objetos dinâmicos do C#. Veja a imagem abaixo extraída do Intellisense:

Se você observar bem, o objeto correspondente a uma Range específica é do tipo dynamic. Isto é, não precisamos fazer um cast para o objeto exato do Interop para poder trabalhar com o objeto desejado. Note também que em C# antes era obrigatório passar o Type.Missing para os parâmetros opcionais e agora não é mais – ele já vem com o valor pré-fixado para nossa conveniência.
Para ser mais completo na explicação, o Range possui um indexer com o parâmetro coluna e linha opcionais. Isso significa que posso ter vários tipos de seleção de conjunto de células e na prática, vários tipos de retornos do mesmo indexer. Para isso é conveniente a assinatura com parâmetros opcionais e retorno dinâmico, pois mais tarde o desenvolvedor, que já espera qual será o retorno adequado, pode trabalhar com o resultado esperado sem se preocupar em tempo de compilação. Abaixo segue a assinatura do indexer da classe Range do Interop.Excel – o Range normal não foi evoluído no Tools.Excel. Só o NamedRange.

Voltando então ao exemplo, decidimos deixar o método mais prolixo para explicitar o uso do dynamic do C# 4.0:

Neste caso, embora não fosse necessário para este exemplo, fizemos com que a cada iteração do For, o Range equivalente à linha da lista de produtos ficasse guardado numa variável dinâmica. A partir deste momento, tudo o que for feito com a variável x também se torna dinâmico, permitindo que eu chame métodos e realize atribuições sem saber exatamente o que tem em x com a ajuda do Intellisense. Se eu quisesse chamar uma propriedade x.Teste, só iria dar erro em tempo de execução. O compilador, ao lidar com variáveis dinâmicas, não tem como descobrir quais são os métodos e propriedades de x. Mas como conhecemos o modelo de objetos, as variáveis valorColuna1 e valorColuna2 ficarão com os valores adequados. Finalmente, o método Append do StringBuilder saberá qual overload usar para inserir o número ou o nome do produto.
Finalmente, com um último exemplo mais prático, vamos mostrar todos os código de produto recebidos pelo serviço num MessageBox. Com isso vamos mostrar que também é possível iterar com foreach de forma mais prática em alguns casos. Podemos usar dynamic diversas situações como mostra a figura a seguir.

Executando os dois exemplos temos os seguintes resultados:
a) Primeiros 10 itens da lista:

b) Todos os códigos de produto recebidos do serviço:

Com isso conseguimos concluir como mostrar e trabalhar com dados no Excel, concluindo assim o exemplo.
Conclusão
Com esta pequena demonstração conseguimos mostrar como trabalhar com fontes de dados modernas como web services, por exemplo. O uso de VBA, embora seja bastante válido e muito poderoso, não permite que se use arquiteturas mais modernas nem ferramentas de desenvolvimento mais atualizadas para se criar aplicações atuais para a plataforma Microsoft Office.
O uso da plataforma Office está crescendo muito e os desenvolvedores hoje precisam entender que nem todo sistema precisa ser Web! Muitas vezes, uma solução muito mais complicada em Web pode ser facilmente resolvida utilizando o Office com inteligência.
O uso de .NET e Visual Studio 2010 também favorece muito o desenvolvimento de aplicações baseadas em Sharepoint, o que torna o uso do Excel, do Word e do Outlook particularmente importante como plataforma de desenvolvimento de aplicações corporativas. Com vários templates para Sharepoint, é possível criar solução altamente integradas com custos muito menores de desenvolvimento, utilizando ferramentas que os information workers conhecem há mais de 10 anos – a plataforma Microsoft Office.
Sobre Nós
A Accendis é uma consultoria que presta serviços utilizando a plataforma de desenvolvimento Microsoft. Conheça mais sobre o nosso trabalho www.accendis.com.br. Se você precisar de treinamento para você, sua empresa, alocação de profissionais em formato body shop e consultoria para resolver problemas mais complexos, estamos aqui para te ajudar.
Grande Abraço
Equipe Accendis
C# 4.0, dynamic, EF, Excel, interop, Office, VSTO, wcf