Olá filhotes! Hoje só para variar irei mostrar uma nova função do Visual Studio 2010, o Web.Config Transformation. Agora com o Visual Studio 2010 nós podemos ter vários web.configs diferentes para cada publicação. Como assim? Bom… quando você esta no ambiente de desenvolvimento o seu banco é diferente do banco de produção, então quando você publicava o seu projeto você era obrigado á alterar o web.config, não só a string de conexão, mas qualquer outra configuração de segurança, etc… Agora nós podemos “ter” um Web.Config para cada ambiente. Vamos lá:
Já repararam que agora o Web.Config tem a opção de ser expandido (Se estiver usando VB você vai precisar habilitar a opção de “Ver todos os arquivos”).

image
Por padrão nós temos o Web.Debug e o Web.Release, são os nossos arquivos de transformação. Um arquivo de transformação serve para informar quais atributos iremos alterar/adicionar/remover no nosso Web.Config original, então na verdade nós só temos um Web.Config que é transformado automaticamente para cada ambiente. Mas os arquivos de transformação devem ser arquivos XML válidos! Dentro dos arquivos por padrão há comentários com exemplos de como substituir os nós do Web.Config original, e também terá essa tag:

<?xml version="1.0"> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> </configuration>


Mas o que é isso? Bom, para fazer as transformações no nosso Web.Config nós precisamos usar os atributos do namespace XML-Document-Transform, então todos os arquivos de transformação devem ter esse namespace registrado. O namespace XML-Document-Transform é composto por dois atributos: Locator e Transform. O Locator é usado para localizar o elemento que você vai modificar e o Transform determina a ação que acontecerá ao elemento ( Excluir, Alterar, Adicionar ). Deixe eu exemplificar isso, vamos dizer que eu tenho essa connection string no meu Web.Config:

<add name="MyDB"
         connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyDB;Integrated Security=True"
         providerName="System.Data.SqlClient" />


Mas quando formos publicar ele para o cliente iremos usar outra string de conexão, já que acessaremos o banco de produção. Para isso nós iremos precisar adicionar essa nova string de conexão no nosso arquivo de transformação (nesse caso, o web.Release ):

 <add name="MyDB" 
        connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" 
        xdt:Transform="Replace" xdt:Locator="Match(name)"/>

Perceberam que adicionei o Locator e o Transform ? Então, agora vamos ver o porquê dos valores: O Transform Replace significa que iremos substituir todo o nó, e o Locator Match(name) mostra que ele ira procurar pelos nós (Dentro de Configuration / ConnectionStrings / Add) cujo parâmetro (nesse caso o name) possui o mesmo valor. Com essa linha nós substituiremos a string de conexão DbPortal do Web.Config pela do Release.

Existem outros Locators e Transforms, vamos ver o que cada um faz:

Locators

Match([args]) – Como dito antes, procura elemento(s) com o mesmo valor do argumento, sendo que você pode passar mais argumentos separando por virgula.

<add name="MyDB" connectionstring="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" providername="System.Data.SqlClient" xdt:transform="Replace" xdt:locator="Match(name,providerName)"> </add>


Condition([arg])  – A condição será transformada em uma expressão XPath e será associada ao elemento. Acha todos os nós que “batem” com as condições. No nosso exemplo ele substituirá a connection string TempDB que também possui como providerName System.Data.SqlClient

<connectionstrings>     <add name="ReleaseDB" connectionstring="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" providername="System.Data.SqlClient" xdt:transform="Replace" xdt:locator="Condition(@name='TempDB'
     and @providerName='System.Data.SqlClient')">   </add>  </connectionstrings>

O XPath real fica sendo: configuration/connectionStrings[@name=’TempDB’ or @providerName=’System.Data.SqlClient’]

XPath([XPath expression]) – Ao contrario do Condition você tem que passar toda a expressão XPath. No nosso exemplo ele removerá a connection string ReleaseDB e todas com o Provider igual à System.Data.SqlClient

<connectionstrings> <add xdt:transform="RemoveAll" xdt:locator="configuration/connectionStrings[@name='ReleaseDB' or @providerName='System.Data.SqlClient']"> </add></connectionstrings>

Como visto no ultimo exemplo, há (vários) outros transforms:

Replace – Substitui a primeira ocorrência do(s) nó(s) encontrados completamente, juntamente com seus filhos.

<globalization xdt:transform="Replace" fileencoding="ISO-8859-1" responseencoding="ISO-8859-1" requestencoding="ISO-8859-1" uiculture="en-US" culture="en-US"></globalization>

Remove – Remove a primeira ocorrência do(s) nó(s) encontrados, juntamente com seus filhos.

<globalization xdt:transform="Replace" xdt:locator="Condition(@culture='es-MX')" fileencoding="ISO-8859-1" responseencoding="ISO-8859-1" requestencoding="ISO-8859-1" uiculture="en-US" culture="en-US"></globalization>


RemoveAll – Remove todas as ocorrências do(s) nó(s) encontrados, junto com os filhos.

<globalization xdt:transform="RemoveAll"></globalization>

Insert – Insere o nó como ultimo item da configuração.

<globalization culture="jp-JP" uiCulture="jp-JP" requestEncoding="ISO-8859-1" responseEncoding="ISO-8859-1" fileEncoding="ISO-8859-1"  xdt:Transform="Insert" />


InsertAfter(XPath) – Insere o nó logo após o elemento definido pelo XPath. Ex: Vamos inserir uma chave “EmailCopia” no AppSettings logo após o “EmailUsuario”

 <appSettings>     <add key="EmailCopia" value="homologacao@100loop.com.br" xdt:Transform="InsertAfter(/configuration/appSettings/add[@key='EmailUsuario'])"/>   </appSettings>

InsertBefore(XPath) – Insere o nó antes do nó especificado no XPath.

SetAttributes – Substitui os atributos do nó em vez do nó inteiro. Pode se passar mais de um atributo separando-o por virgula.

 <connectionStrings>     <add name="MyDB"       connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"         providerName="System.Data.SqlClient"       xdt:Transform="SetAttributes(connectionString)" xdt:Locator="Match(name)"/>   </connectionStrings>


RemoveAttributes – Remove um ou mais atributos de um nó.

<compilation xdt:Transform="RemoveAttributes(debug,batch)" />

Pronto. Basta você colocar cada nó que você deseja substituir no arquivo de transformação usando o Transform e Locator e seu Web.Config estará configurado para cada ambiente. Se você quiser também você pode copiar todo o Web.Config para o arquivo de transformação, fazendo a modificação no que você queira, e adicionando o Transform="Replace" no primeiro nó. Com isso você substitui todo o web.config por outro. Nesse caso não é necessário o Locator, já que substituirá todo web.config.

E claro, mas como o Visual Studio sabe em qual ambiente nós queremos publicar? Basta irmos no combo Solution Configurations na toolbar e alterar o tipo de ambiente em que iremos publicar.

image

Há a possibilidade também de criar novas configurações, para isso basta ir em configuration manager, e em Active solution configuration selecionar <New…>.

image

image

E adicione o nome do seu novo ambiente, se quiser pode copiar as configurações de outro ambiente para esse novo. Depois de criar um novo ambiente, basta clicar com o botão direito sobre o Web.Config e escolher Add Config Transforms.

image

Será criado um arquivo de transformação para cada configuração nova.

image

Eu sei que o grande @ivanpaulovich ira falar um pouco sobre esse assunto também na palestra dele no Tech Ed.

Espero que tenham gostado! Ate mais!

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

http://blogs.msdn.com/b/webdevtools/archive/2009/05/04/web-deployment-web-config-transformation.aspx

Introdução ao XPath: http://www.microsoft.com/brasil/msdn/Tecnologias/visualc/XPath.mspx