<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Sayed Ibrahim Hashimi - MSBuild, Web Deploy (MSDeploy), ASP.NET - Config-Transformation</title>
    <link>http://sedodream.com/</link>
    <description>MSBuild, C#, Visual Studio and more</description>
    <language>en-us</language>
    <copyright>Sayed Ibrahim Hashimi</copyright>
    <lastBuildDate>Sun, 19 Aug 2012 22:18:16 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>sayed.hashimi@gmail.com</managingEditor>
    <webMaster>sayed.hashimi@gmail.com</webMaster>
    <item>
      <trackback:ping>http://sedodream.com/Trackback.aspx?guid=fdcc88bf-95ac-4945-a49b-96d9d1ac35a5</trackback:ping>
      <pingback:server>http://sedodream.com/pingback.aspx</pingback:server>
      <pingback:target>http://sedodream.com/PermaLink,guid,fdcc88bf-95ac-4945-a49b-96d9d1ac35a5.aspx</pingback:target>
      <dc:creator>Ibrahim</dc:creator>
      <wfw:comment>http://sedodream.com/CommentView,guid,fdcc88bf-95ac-4945-a49b-96d9d1ac35a5.aspx</wfw:comment>
      <wfw:commentRss>http://sedodream.com/SyndicationService.asmx/GetEntryCommentsRss?guid=fdcc88bf-95ac-4945-a49b-96d9d1ac35a5</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
When we released VS2010 we add support for <a href="http://msdn.microsoft.com/en-us/library/dd465326.aspx">web.config
(XDT) transforms</a> during publish/package. <em>Note: From now on I’ll only use the
word publish from now on but the full content relates to packaging as well.</em> In
the original implementation when you published your web project the web.config file
would be transformed by the file web.{Configuration}.config, where {Configuration}
is the project build configuration. For example Debug, or Release. If you publish
on Release and there exists a web.release.config we will take your web.config and
transform it with web.release.config before publishing.
</p>
        <h3>Cascading web.config transformations
</h3>
        <p>
In VS 2012 (<em>as well as the publishing updates for VS2010 through the </em><a href="https://www.windowsazure.com/en-us/develop/net/"><em>Azure
SDK</em></a>) now support the concept of publish specific transforms. You can also
now specify the project configuration used for a profile when publishing on the publish
dialog.
</p>
        <p>
          <a href="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/SNAGHTML45b19fc.png">
            <img title="SNAGHTML45b19fc" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="SNAGHTML45b19fc" src="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/SNAGHTML45b19fc_thumb.png" width="621" height="484" />
          </a>
        </p>
        <p>
In this case I have created a profile named Production and set the Configuration to
Release. When I publish this project the following transformations will be applied
(if the files exist) in this order.
</p>
        <ol>
          <li>
web.release.config 
</li>
          <li>
web.production.config 
</li>
        </ol>
        <p>
I think that we got this wrong when we initially implemented the support. We should
have created profile specific transforms instead of ones based on build config, but
having these cascading transforms are still pretty useful. For example I may want
to remove the attribute debug=”true” from the compilation element and then inside
of the profile specific transform we would override appSettings/WCF endpoints/logging
config/etc for that environment.
</p>
        <p>
In VS there is a right-click option on web.config for Add Config Transform, but we
were not able to update the functionality of that to automatically create profile
specific transforms. Don’t worry it will be released soon with our first set of updates
for web tooling. For now you will need to create a new file with the correct name
and add it to your project. <em>Note: if you want it to show up nested under web.config
you’ll need to add the metadata &lt;DependentUpon&gt;Web.config&lt;/DependentUpon&gt;
to the item in the .csproj/.vbproj file.</em></p>
        <h3>web.config transform preview
</h3>
        <p>
Previously the only way to test the functionality for these transformation was to
actually publish or package the web project. This gets old pretty quick. In order
to simplify creating these transforms we have introduced the Preview Transform menu
option. This is the <strong>coolest feature in VS 2012</strong> (<em>OK I’m a bit
biased, but still its the coolest</em>).
</p>
        <p>
          <a href="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_4.png">
            <img title="image" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="image" src="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_thumb_1.png" width="444" height="235" />
          </a>
        </p>
        <p>
In my web.release.config I have left the default contents, which just removes the
debug attribute. Here is what I see when I select this on web.release.config for my
project.
</p>
        <p>
          <a href="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_8.png">
            <img title="image" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="image" src="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_thumb_3.png" width="644" height="321" />
          </a>
        </p>
        <p>
You can see that in the image above we can see that the debug flag was indeed removed
as expected. 
</p>
        <p>
In my web.production.config I have a transform which simply updates the email app
setting value. Here is the really cool part when I preview the transform for web.production.config
the previewer will look into the profile and determine the build configuration which
has been configured, and it will ensure that transform is applied before the profile
specific one. For example take a look at the result for web.production.config.
</p>
        <p>
          <a href="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_12.png">
            <img title="image" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="image" src="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_thumb_5.png" width="644" height="321" />
          </a>
        </p>
        <p>
In the image above you can see the note that web.release.config was applied first
followed by web.production.config. In the result we can see that web.release.config
removed the debug flag and that web.production.config updated the email address value.
</p>
        <p>
We also do a little bit to help out in case there are errors in either the web.config
or a transform. You can see errors in the Output Window and double click it to go
directly to where the error exists.
</p>
        <p>
Note: <a href="http://www.hanselman.com/blog/">Scott Hanselman</a> has a <a href="http://www.asp.net/vnext/overview/videos/visual-studio-2012-web-publishing-improvements">5
minute video showing this and other updates</a>.
</p>
        <p>
Another note: If you need to transform any file besides web.config during publish
then install my extension <a href="http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5/">SlowCheetah</a>.
</p>
        <p>
Sayed Ibrahim Hashimi | <a href="https://twitter.com/sayedihashimi">@SayedIHashimi</a></p>
      </body>
      <title>Profile specific web.config transforms and transform preview</title>
      <guid isPermaLink="false">http://sedodream.com/PermaLink,guid,fdcc88bf-95ac-4945-a49b-96d9d1ac35a5.aspx</guid>
      <link>http://sedodream.com/2012/08/19/ProfileSpecificWebconfigTransformsAndTransformPreview.aspx</link>
      <pubDate>Sun, 19 Aug 2012 22:18:16 GMT</pubDate>
      <description>&lt;p&gt;
When we released VS2010 we add support for &lt;a href="http://msdn.microsoft.com/en-us/library/dd465326.aspx"&gt;web.config
(XDT) transforms&lt;/a&gt; during publish/package. &lt;em&gt;Note: From now on I’ll only use the
word publish from now on but the full content relates to packaging as well.&lt;/em&gt; In
the original implementation when you published your web project the web.config file
would be transformed by the file web.{Configuration}.config, where {Configuration}
is the project build configuration. For example Debug, or Release. If you publish
on Release and there exists a web.release.config we will take your web.config and
transform it with web.release.config before publishing.
&lt;/p&gt;
&lt;h3&gt;Cascading web.config transformations
&lt;/h3&gt;
&lt;p&gt;
In VS 2012 (&lt;em&gt;as well as the publishing updates for VS2010 through the &lt;/em&gt;&lt;a href="https://www.windowsazure.com/en-us/develop/net/"&gt;&lt;em&gt;Azure
SDK&lt;/em&gt;&lt;/a&gt;) now support the concept of publish specific transforms. You can also
now specify the project configuration used for a profile when publishing on the publish
dialog.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/SNAGHTML45b19fc.png"&gt;&lt;img title="SNAGHTML45b19fc" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="SNAGHTML45b19fc" src="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/SNAGHTML45b19fc_thumb.png" width="621" height="484" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
In this case I have created a profile named Production and set the Configuration to
Release. When I publish this project the following transformations will be applied
(if the files exist) in this order.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
web.release.config 
&lt;/li&gt;
&lt;li&gt;
web.production.config 
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
I think that we got this wrong when we initially implemented the support. We should
have created profile specific transforms instead of ones based on build config, but
having these cascading transforms are still pretty useful. For example I may want
to remove the attribute debug=”true” from the compilation element and then inside
of the profile specific transform we would override appSettings/WCF endpoints/logging
config/etc for that environment.
&lt;/p&gt;
&lt;p&gt;
In VS there is a right-click option on web.config for Add Config Transform, but we
were not able to update the functionality of that to automatically create profile
specific transforms. Don’t worry it will be released soon with our first set of updates
for web tooling. For now you will need to create a new file with the correct name
and add it to your project. &lt;em&gt;Note: if you want it to show up nested under web.config
you’ll need to add the metadata &amp;lt;DependentUpon&amp;gt;Web.config&amp;lt;/DependentUpon&amp;gt;
to the item in the .csproj/.vbproj file.&lt;/em&gt;
&lt;/p&gt;
&lt;h3&gt;web.config transform preview
&lt;/h3&gt;
&lt;p&gt;
Previously the only way to test the functionality for these transformation was to
actually publish or package the web project. This gets old pretty quick. In order
to simplify creating these transforms we have introduced the Preview Transform menu
option. This is the &lt;strong&gt;coolest feature in VS 2012&lt;/strong&gt; (&lt;em&gt;OK I’m a bit
biased, but still its the coolest&lt;/em&gt;).
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_4.png"&gt;&lt;img title="image" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="image" src="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_thumb_1.png" width="444" height="235" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
In my web.release.config I have left the default contents, which just removes the
debug attribute. Here is what I see when I select this on web.release.config for my
project.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_8.png"&gt;&lt;img title="image" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="image" src="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_thumb_3.png" width="644" height="321" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
You can see that in the image above we can see that the debug flag was indeed removed
as expected. 
&lt;/p&gt;
&lt;p&gt;
In my web.production.config I have a transform which simply updates the email app
setting value. Here is the really cool part when I preview the transform for web.production.config
the previewer will look into the profile and determine the build configuration which
has been configured, and it will ensure that transform is applied before the profile
specific one. For example take a look at the result for web.production.config.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_12.png"&gt;&lt;img title="image" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="image" src="http://sedodream.com/content/binary/WindowsLiveWriter/Pro.configtransformsandtransformpreviews_CB5A/image_thumb_5.png" width="644" height="321" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
In the image above you can see the note that web.release.config was applied first
followed by web.production.config. In the result we can see that web.release.config
removed the debug flag and that web.production.config updated the email address value.
&lt;/p&gt;
&lt;p&gt;
We also do a little bit to help out in case there are errors in either the web.config
or a transform. You can see errors in the Output Window and double click it to go
directly to where the error exists.
&lt;/p&gt;
&lt;p&gt;
Note: &lt;a href="http://www.hanselman.com/blog/"&gt;Scott Hanselman&lt;/a&gt; has a &lt;a href="http://www.asp.net/vnext/overview/videos/visual-studio-2012-web-publishing-improvements"&gt;5
minute video showing this and other updates&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Another note: If you need to transform any file besides web.config during publish
then install my extension &lt;a href="http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5/"&gt;SlowCheetah&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Sayed Ibrahim Hashimi | &lt;a href="https://twitter.com/sayedihashimi"&gt;@SayedIHashimi&lt;/a&gt;
&lt;/p&gt;</description>
      <comments>http://sedodream.com/CommentView,guid,fdcc88bf-95ac-4945-a49b-96d9d1ac35a5.aspx</comments>
      <category>Config-Transformation</category>
      <category>MSBuild</category>
      <category>Visual Studio</category>
      <category>Visual Studio 2012</category>
    </item>
    <item>
      <trackback:ping>http://sedodream.com/Trackback.aspx?guid=d158f2b8-cdee-4257-86cd-401362deeff2</trackback:ping>
      <pingback:server>http://sedodream.com/pingback.aspx</pingback:server>
      <pingback:target>http://sedodream.com/PermaLink,guid,d158f2b8-cdee-4257-86cd-401362deeff2.aspx</pingback:target>
      <dc:creator>Ibrahim</dc:creator>
      <wfw:comment>http://sedodream.com/CommentView,guid,d158f2b8-cdee-4257-86cd-401362deeff2.aspx</wfw:comment>
      <wfw:commentRss>http://sedodream.com/SyndicationService.asmx/GetEntryCommentsRss?guid=d158f2b8-cdee-4257-86cd-401362deeff2</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Back in November I participated in <a href="http://virtualtechdays.com/">Virtual Tech
Days</a> which is an online conference presented by Microsoft. In the session I discussed
the enhancements to web deployment using Visual Studio 2010 and MSDeploy. Some of
the topics which I covered includ:
</p>
        <ul>
          <li>
web.conig (XDT) transforms 
</li>
          <li>
How to publish to local file system using Visual Studio 
</li>
          <li>
How to publish to a 3rd party host using Visual Studio via MSDeploy 
</li>
          <li>
How to publish to local IIS server using the .cmd file generated by Visual Studio 
</li>
          <li>
How to use msdeploy.exe to delete IIS applications 
</li>
          <li>
How to use the IIS Manager to import web packages 
</li>
          <li>
How to use msdeploy.exe to deploy a web package to the local IIS server 
</li>
          <li>
How to use msdeploy.exe to deploy a web package to a remove IIS server 
</li>
          <li>
How to use msdeploy.exe to deploy a web package &amp; set parameters using SetParameters.xml
to a remote IIS server 
</li>
        </ul>
        <p>
You can download the video &amp; all of my sample files at <a href="http://virtualtechdays.com/pastevents_2010november.aspx">http://virtualtechdays.com/pastevents_2010november.aspx</a>.
In the samples you will find all of the scripts that I used and a bunch of others
which I didn’t have time to cover. Enjoy!
</p>
        <p>
Sayed Ibrahim Hashimi <a href="http://twitter.com/sayedihashimi">@sayedihashimi</a></p>
      </body>
      <title>Video on Web Deployment using Visual Studio 2010 and MSDeploy</title>
      <guid isPermaLink="false">http://sedodream.com/PermaLink,guid,d158f2b8-cdee-4257-86cd-401362deeff2.aspx</guid>
      <link>http://sedodream.com/2011/01/08/VideoOnWebDeploymentUsingVisualStudio2010AndMSDeploy.aspx</link>
      <pubDate>Sat, 08 Jan 2011 20:34:08 GMT</pubDate>
      <description>
&lt;p&gt;
Back in November I participated in &lt;a href="http://virtualtechdays.com/"&gt;Virtual Tech
Days&lt;/a&gt; which is an online conference presented by Microsoft. In the session I discussed
the enhancements to web deployment using Visual Studio 2010 and MSDeploy. Some of
the topics which I covered includ:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
web.conig (XDT) transforms 
&lt;/li&gt;
&lt;li&gt;
How to publish to local file system using Visual Studio 
&lt;/li&gt;
&lt;li&gt;
How to publish to a 3rd party host using Visual Studio via MSDeploy 
&lt;/li&gt;
&lt;li&gt;
How to publish to local IIS server using the .cmd file generated by Visual Studio 
&lt;/li&gt;
&lt;li&gt;
How to use msdeploy.exe to delete IIS applications 
&lt;/li&gt;
&lt;li&gt;
How to use the IIS Manager to import web packages 
&lt;/li&gt;
&lt;li&gt;
How to use msdeploy.exe to deploy a web package to the local IIS server 
&lt;/li&gt;
&lt;li&gt;
How to use msdeploy.exe to deploy a web package to a remove IIS server 
&lt;/li&gt;
&lt;li&gt;
How to use msdeploy.exe to deploy a web package &amp;amp; set parameters using SetParameters.xml
to a remote IIS server 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
You can download the video &amp;amp; all of my sample files at &lt;a href="http://virtualtechdays.com/pastevents_2010november.aspx"&gt;http://virtualtechdays.com/pastevents_2010november.aspx&lt;/a&gt;.
In the samples you will find all of the scripts that I used and a bunch of others
which I didn’t have time to cover. Enjoy!
&lt;/p&gt;
&lt;p&gt;
Sayed Ibrahim Hashimi &lt;a href="http://twitter.com/sayedihashimi"&gt;@sayedihashimi&lt;/a&gt;
&lt;/p&gt;</description>
      <comments>http://sedodream.com/CommentView,guid,d158f2b8-cdee-4257-86cd-401362deeff2.aspx</comments>
      <category>Config-Transformation</category>
      <category>IIS</category>
      <category>MSBuild</category>
      <category>MSDeploy</category>
      <category>speaking</category>
      <category>Visual Studio</category>
      <category>Visual Studio 2010</category>
      <category>web</category>
      <category>Web Deployment Tool</category>
      <category>Web Development</category>
      <category>Web Publishing Pipeline</category>
    </item>
    <item>
      <trackback:ping>http://sedodream.com/Trackback.aspx?guid=27dcfa0d-f88c-4dc3-ace1-0e0d7ef75c1f</trackback:ping>
      <pingback:server>http://sedodream.com/pingback.aspx</pingback:server>
      <pingback:target>http://sedodream.com/PermaLink,guid,27dcfa0d-f88c-4dc3-ace1-0e0d7ef75c1f.aspx</pingback:target>
      <dc:creator>Ibrahim</dc:creator>
      <wfw:comment>http://sedodream.com/CommentView,guid,27dcfa0d-f88c-4dc3-ace1-0e0d7ef75c1f.aspx</wfw:comment>
      <wfw:commentRss>http://sedodream.com/SyndicationService.asmx/GetEntryCommentsRss?guid=27dcfa0d-f88c-4dc3-ace1-0e0d7ef75c1f</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Last week on <a href="http://stackoverflow.com">StackOverflow</a> I answered a question, <a href="http://stackoverflow.com/q/3613714/105999">Make
web.config transformations working locally</a> and in a response to my answer the
question asker asked me if I would be able to a question he posed earlier <a href="http://stackoverflow.com/q/2915329/105999">Advanced
tasks using web.config transformation</a>. Evidently <a href="http://stackoverflow.com/users/80268/diego-c">he</a> is
really interested in config transformations! I don’t blame him, I’m really into them
as well.
</p>
        <p>
In his question he asks (summarizing) can we replace portions of attribute values
instead of this entire attribute? So for instance you have the following in your web.config.
Below is two sets of appSettings one from Dev and the other from Prod (taken from
the original question).
</p>
        <pre class="brush: xml;">&lt;!-- DEV ENTRY --&gt;
&lt;appSettings&gt;
 &lt;add key="serviceName1_WebsService_Url" value="http://wsServiceName1.dev.domain.com/v1.2.3.4/entryPoint.asmx" /&gt;
 &lt;add key="serviceName2_WebsService_Url" value="http://ma1-lab.lab1.domain.com/v1.2.3.4/entryPoint.asmx" /&gt;
&lt;/appSettings&gt;

&lt;!-- PROD ENTRY --&gt;
&lt;appSettings&gt;
 &lt;add key="serviceName1_WebsService_Url" value="http://wsServiceName1.prod.domain.com/v1.2.3.4/entryPoint.asmx" /&gt;
 &lt;add key="serviceName2_WebsService_Url" value="http://ws.ServiceName2.domain.com/v1.2.3.4/entryPoint.asmx" /&gt;
&lt;/appSettings&gt;</pre>
        <p>
In the above we just want to replace dev with prod and ma1-lab.lab1.domain with ws.ServiceName2.domain.
For those wondering currently we have the following transformations out of the box.
</p>
        <ul>
          <li>
Replace – Replaces the entire element</li>
          <li>
Remove – Removes the entire element</li>
          <li>
RemoveAll – Removes all matching elements</li>
          <li>
Insert – Inserts an element</li>
          <li>
SetAttributes – Sets the value of the specified attributes</li>
          <li>
RemoveAttributes – Removes attributes</li>
          <li>
InsertAfter – Inserts an element after another</li>
          <li>
InsertBefore – Inserts an element before another</li>
        </ul>
        <p>
At the end of this article I’ve linked to another blog which has more info about these
transformations. So it sounds like SetAttributes is <strong>almost</strong> what we
want, but not quite what there. A little known fact is that you can create your own
config transformations and use those. In fact all of the out of the box transformations
follow the same patterns that custom transformations would. To solve this issue we
need to create our own config transformation, AttributeRegexReplace. This transformation
will take an attribute value and do a <a href="http://en.wikipedia.org/wiki/Regular_expression">regular
expression</a> replace on its value. In order to create a new transformation you first
reference the Microsoft.Web.Publishing.Tasks.dll which can be found in the <strong>%Program
Files (x86)%MSBuild\Microsoft\VisualStudio\v10.0\Web</strong> folder. If you are working
with a team it is best if you copy that assembly, place it in a shared folder in source
control, and make the reference from that location. After you create the reference
to that assembly you will need to create a class which extends the Transform class.
The class diagram for this abstract class is shown below.
</p>
        <p>
          <a href="http://sedodream.com/content/binary/WindowsLiveWriter/ExtendingXMLw.configConfigtransformation_12D90/image_2.png">
            <img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://sedodream.com/content/binary/WindowsLiveWriter/ExtendingXMLw.configConfigtransformation_12D90/image_thumb.png" width="455" border="0" height="394" />
          </a>
        </p>
        <p>
The only thing that you will need to implement is the Apply method. You don’t even
need to fully understand all of the properties and methods just the portions that
you are interested in. Here we will not cover all the details of this class, or other
related classes which exist, but there will be future posts which will shed more light
on this area.
</p>
        <p>
In the sample class library that I created, I called the project CustomTransformType.
Inside of that project I created the class AttributeRegexReplace. The entire contents
of that class are shown below, we will go over the details after that.
</p>
        <pre class="brush: csharp;">namespace CustomTransformType
{
    using System;
    using System.Text.RegularExpressions;
    using System.Xml;
    using Microsoft.Web.Publishing.Tasks;

    public class AttributeRegexReplace : Transform
    {
        private string pattern;
        private string replacement;
        private string attributeName;

        protected string AttributeName
        {
            get
            {
                if (this.attributeName == null)
                {
                    this.attributeName = this.GetArgumentValue("Attribute");
                }
                return this.attributeName;
            }
        }
        protected string Pattern
        {
            get
            {
                if (this.pattern == null)
                {
                    this.pattern = this.GetArgumentValue("Pattern");
                }

                return pattern;
            }
        }

        protected string Replacement
        {
            get
            {
                if (this.replacement == null)
                {
                    this.replacement = this.GetArgumentValue("Replacement");
                }

                return replacement;
            }
        }

        protected string GetArgumentValue(string name)
        {
            // this extracts a value from the arguments provided
            if (string.IsNullOrWhiteSpace(name)) 
            { throw new ArgumentNullException("name"); }

            string result = null;
            if (this.Arguments != null &amp;&amp; this.Arguments.Count &gt; 0)
            {
                foreach (string arg in this.Arguments)
                {
                    if (!string.IsNullOrWhiteSpace(arg))
                    {
                        string trimmedArg = arg.Trim();
                        if (trimmedArg.ToUpperInvariant().StartsWith(name.ToUpperInvariant()))
                        {
                            int start = arg.IndexOf('\'');
                            int last = arg.LastIndexOf('\'');
                            if (start &lt;= 0 || last &lt;= 0 || last &lt;= 0)
                            {
                                throw new ArgumentException("Expected two ['] characters");
                            }

                            string value = trimmedArg.Substring(start, last - start);
                            if (value != null)
                            {
                                // remove any leading or trailing '
                                value = value.Trim().TrimStart('\'').TrimStart('\'');
                            }
                            result = value;
                        }
                    }
                }
            }
            return result;
        }

        protected override void Apply()
        {
            foreach (XmlAttribute att in this.TargetNode.Attributes)
            {
                if (string.Compare(att.Name, this.AttributeName, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    // get current value, perform the Regex
                    att.Value = Regex.Replace(att.Value, this.Pattern, this.Replacement);
                }
            }
        }
    }
}</pre>
        <p>
In this class we have 3 properties; Pattern, Replacement, and AttributeName. All of
these values will be provided via an argument in the config transformation. For example
take a look at the element below which contains a transform attribute may look like
the following.
</p>
        <pre class="brush: csharp;">&lt;add key="two" value="two-replaced" 
         xdt:Transform="AttributeRegexReplace(Attribute='value', Pattern='here',Replacement='REPLACED')" 
         xdt:Locator="Match(key)"/&gt;</pre>
        <p>
In this example I declare that I am using AttributeRegexReplace and then specify the
values for the attributes within the <strong>()</strong>. In the class above I have
a method, GetArgumentValue, which is used to parse values from that argument string.
When your transform is invoked the string inside of () is passed in as the ArgumentString
value. If you are using a <strong>,</strong> as the argument separator, as I am, then
you can use the Arguments list. Which will split up the arguments by the <strong>,</strong> character.
Surprisingly in the 101 lines of code in the sample there are only a few interesting
lines. Those are what’s contained inside the Apply method. Inside that method I search
the TargetNode’s attributes (<em>TargetNode is the node which was matched in the xml
file being transformed</em>) for an attribute with the same name as the one specified
in the AttributeName property. Once I find it I just make a call to <a href="http://msdn.microsoft.com/en-us/library/e7f5w83z.aspx">Regex.Replace</a> to
get the new value, and assign it. Pretty simple! Now lets see how can we use this.
</p>
        <p>
Let’s say you have the following very simple web.config
</p>
        <pre class="brush: xml;">&lt;?xml version="1.0"?&gt;
&lt;configuration&gt;
  &lt;appSettings&gt;
    &lt;add key="one" value="one"/&gt;
    &lt;add key="two" value="partial-replace-here-end"/&gt;
    &lt;add key="three" value="three here"/&gt;
  &lt;/appSettings&gt;
&lt;/configuration&gt;</pre>
        <p>
If we want to be able to use our own transform then we will have to use the xdt:Import
element. You can place that element inside the xml document anywhere immediately under
the root element. This element will allow us to utilize our own transform class. It
only has 3 possible attributes.
</p>
        <ul>
          <li>
namespace – This is the namespace which the transform is contained in 
</li>
          <li>
path – This is the full path to the assembly</li>
          <li>
assembly – This is the assembly name which contains the transform</li>
        </ul>
        <p>
You can only use one of the two; path and assembly. Basically it boils down to how
the assembly is loaded. If you use path the assembly will be loaded with <a href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadfrom.aspx">Assembly.LoadFrom</a> and
if you chose to use assembly passing in the <a href="http://msdn.microsoft.com/en-us/library/system.reflection.assemblyname.aspx">AssemblyName</a>,
for instance if the assembly in in the GAC, then it will be loaded using <a href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.load.aspx">Assembly.Load</a>.
</p>
        <p>
I chose to use path, because I just placed the file inside of the MSBuild Extensions
directory (<strong>%Program Files (x86)%MSBuild</strong>) in a folder named Custom.
Then I created my config transform file to be the following.
</p>
        <pre class="brush: xml;">&lt;?xml version="1.0"?&gt;

&lt;configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"&gt;
                        
  &lt;xdt:Import path="C:\Program Files (x86)\MSBuild\Custom\CustomTransformType.dll"
              namespace="CustomTransformType" /&gt;

  &lt;appSettings&gt;
    &lt;add key="one" value="one-replaced" xdt:Transform="Replace" xdt:Locator="Match(key)" /&gt;
    &lt;add key="two" value="two-replaced" xdt:Transform="AttributeRegexReplace(Attribute='value', Pattern='here',Replacement='REPLACED')" xdt:Locator="Match(key)"/&gt;
  &lt;/appSettings&gt;
&lt;/configuration&gt;</pre>
        <p>
Then to run this I created an MSBuild file, PerformTransform.proj, which is shown
below.
</p>
        <pre class="brush: xml;">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&gt;
  &lt;UsingTask TaskName="TransformXml"
           AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/&gt;

  &lt;PropertyGroup&gt;
    &lt;TransformDest&gt;web.tranzed.config&lt;/TransformDest&gt;
  &lt;/PropertyGroup&gt;
  
  &lt;Target Name="Demo"&gt;
    &lt;Delete Files="$(TransformDest)" /&gt;
    &lt;TransformXml Source="web.config"
                  Transform="web.dev.config"
                  Destination="$(TransformDest)" /&gt;                  
  &lt;/Target&gt;
  
&lt;/Project&gt;</pre>
        <p>
This file uses the TransformXml task as I outlined in a previous post <a href="http://sedodream.com/2010/04/26/ConfigTransformationsOutsideOfWebAppBuilds.aspx">Config
transformations outside of web app builds</a>. Once you execute the Demo target with
the command msbuild PerformTransform.proj /t:Demo you will see the file web.tranzed.config
with the following contents.
</p>
        <pre class="brush: xml;">&lt;?xml version="1.0"?&gt;
&lt;configuration&gt;
  &lt;appSettings&gt;
    &lt;add key="one" value="one-replaced"/&gt;
    &lt;add key="two" value="partial-replace-REPLACED-end"/&gt;
    &lt;add key="three" value="three here"/&gt;
  &lt;/appSettings&gt;
&lt;/configuration&gt;</pre>
        <p>
So you can see that the replacement did occur as we intended. Below you will find
the download link for the samples as well as another blog entry for more info on the
out of the box transformations.
</p>
        <p>
          <strong>Resources</strong>
        </p>
        <ul>
          <li>
Source download at: <a title="http://sedotech.com/Content/samples/CustomTransformType.zip" href="http://sedotech.com/Content/samples/CustomTransformType.zip">http://sedotech.com/Content/samples/CustomTransformType.zip</a></li>
          <li>
More info on out of box transforms at: <a title="http://vishaljoshi.blogspot.com/2009/03/web-deployment-webconfig-transformation_23.html" href="http://vishaljoshi.blogspot.com/2009/03/web-deployment-webconfig-transformation_23.html">http://vishaljoshi.blogspot.com/2009/03/web-deployment-webconfig-transformation_23.html</a></li>
        </ul>
        <p>
Sayed Ibrahim Hashimi
</p>
      </body>
      <title>Extending XML (web.config) Config transformation</title>
      <guid isPermaLink="false">http://sedodream.com/PermaLink,guid,27dcfa0d-f88c-4dc3-ace1-0e0d7ef75c1f.aspx</guid>
      <link>http://sedodream.com/2010/09/09/ExtendingXMLWebconfigConfigTransformation.aspx</link>
      <pubDate>Thu, 09 Sep 2010 05:51:43 GMT</pubDate>
      <description>&lt;p&gt;
Last week on &lt;a href="http://stackoverflow.com"&gt;StackOverflow&lt;/a&gt; I answered a question, &lt;a href="http://stackoverflow.com/q/3613714/105999"&gt;Make
web.config transformations working locally&lt;/a&gt; and in a response to my answer the
question asker asked me if I would be able to a question he posed earlier &lt;a href="http://stackoverflow.com/q/2915329/105999"&gt;Advanced
tasks using web.config transformation&lt;/a&gt;. Evidently &lt;a href="http://stackoverflow.com/users/80268/diego-c"&gt;he&lt;/a&gt; is
really interested in config transformations! I don’t blame him, I’m really into them
as well.
&lt;/p&gt;
&lt;p&gt;
In his question he asks (summarizing) can we replace portions of attribute values
instead of this entire attribute? So for instance you have the following in your web.config.
Below is two sets of appSettings one from Dev and the other from Prod (taken from
the original question).
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;!-- DEV ENTRY --&amp;gt;
&amp;lt;appSettings&amp;gt;
 &amp;lt;add key="serviceName1_WebsService_Url" value="http://wsServiceName1.dev.domain.com/v1.2.3.4/entryPoint.asmx" /&amp;gt;
 &amp;lt;add key="serviceName2_WebsService_Url" value="http://ma1-lab.lab1.domain.com/v1.2.3.4/entryPoint.asmx" /&amp;gt;
&amp;lt;/appSettings&amp;gt;

&amp;lt;!-- PROD ENTRY --&amp;gt;
&amp;lt;appSettings&amp;gt;
 &amp;lt;add key="serviceName1_WebsService_Url" value="http://wsServiceName1.prod.domain.com/v1.2.3.4/entryPoint.asmx" /&amp;gt;
 &amp;lt;add key="serviceName2_WebsService_Url" value="http://ws.ServiceName2.domain.com/v1.2.3.4/entryPoint.asmx" /&amp;gt;
&amp;lt;/appSettings&amp;gt;&lt;/pre&gt;
&lt;p&gt;
In the above we just want to replace dev with prod and ma1-lab.lab1.domain with ws.ServiceName2.domain.
For those wondering currently we have the following transformations out of the box.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Replace – Replaces the entire element&lt;/li&gt;
&lt;li&gt;
Remove – Removes the entire element&lt;/li&gt;
&lt;li&gt;
RemoveAll – Removes all matching elements&lt;/li&gt;
&lt;li&gt;
Insert – Inserts an element&lt;/li&gt;
&lt;li&gt;
SetAttributes – Sets the value of the specified attributes&lt;/li&gt;
&lt;li&gt;
RemoveAttributes – Removes attributes&lt;/li&gt;
&lt;li&gt;
InsertAfter – Inserts an element after another&lt;/li&gt;
&lt;li&gt;
InsertBefore – Inserts an element before another&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
At the end of this article I’ve linked to another blog which has more info about these
transformations. So it sounds like SetAttributes is &lt;strong&gt;almost&lt;/strong&gt; what we
want, but not quite what there. A little known fact is that you can create your own
config transformations and use those. In fact all of the out of the box transformations
follow the same patterns that custom transformations would. To solve this issue we
need to create our own config transformation, AttributeRegexReplace. This transformation
will take an attribute value and do a &lt;a href="http://en.wikipedia.org/wiki/Regular_expression"&gt;regular
expression&lt;/a&gt; replace on its value. In order to create a new transformation you first
reference the Microsoft.Web.Publishing.Tasks.dll which can be found in the &lt;strong&gt;%Program
Files (x86)%MSBuild\Microsoft\VisualStudio\v10.0\Web&lt;/strong&gt; folder. If you are working
with a team it is best if you copy that assembly, place it in a shared folder in source
control, and make the reference from that location. After you create the reference
to that assembly you will need to create a class which extends the Transform class.
The class diagram for this abstract class is shown below.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://sedodream.com/content/binary/WindowsLiveWriter/ExtendingXMLw.configConfigtransformation_12D90/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" alt="image" src="http://sedodream.com/content/binary/WindowsLiveWriter/ExtendingXMLw.configConfigtransformation_12D90/image_thumb.png" width="455" border="0" height="394"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
The only thing that you will need to implement is the Apply method. You don’t even
need to fully understand all of the properties and methods just the portions that
you are interested in. Here we will not cover all the details of this class, or other
related classes which exist, but there will be future posts which will shed more light
on this area.
&lt;/p&gt;
&lt;p&gt;
In the sample class library that I created, I called the project CustomTransformType.
Inside of that project I created the class AttributeRegexReplace. The entire contents
of that class are shown below, we will go over the details after that.
&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;namespace CustomTransformType
{
    using System;
    using System.Text.RegularExpressions;
    using System.Xml;
    using Microsoft.Web.Publishing.Tasks;

    public class AttributeRegexReplace : Transform
    {
        private string pattern;
        private string replacement;
        private string attributeName;

        protected string AttributeName
        {
            get
            {
                if (this.attributeName == null)
                {
                    this.attributeName = this.GetArgumentValue("Attribute");
                }
                return this.attributeName;
            }
        }
        protected string Pattern
        {
            get
            {
                if (this.pattern == null)
                {
                    this.pattern = this.GetArgumentValue("Pattern");
                }

                return pattern;
            }
        }

        protected string Replacement
        {
            get
            {
                if (this.replacement == null)
                {
                    this.replacement = this.GetArgumentValue("Replacement");
                }

                return replacement;
            }
        }

        protected string GetArgumentValue(string name)
        {
            // this extracts a value from the arguments provided
            if (string.IsNullOrWhiteSpace(name)) 
            { throw new ArgumentNullException("name"); }

            string result = null;
            if (this.Arguments != null &amp;amp;&amp;amp; this.Arguments.Count &amp;gt; 0)
            {
                foreach (string arg in this.Arguments)
                {
                    if (!string.IsNullOrWhiteSpace(arg))
                    {
                        string trimmedArg = arg.Trim();
                        if (trimmedArg.ToUpperInvariant().StartsWith(name.ToUpperInvariant()))
                        {
                            int start = arg.IndexOf('\'');
                            int last = arg.LastIndexOf('\'');
                            if (start &amp;lt;= 0 || last &amp;lt;= 0 || last &amp;lt;= 0)
                            {
                                throw new ArgumentException("Expected two ['] characters");
                            }

                            string value = trimmedArg.Substring(start, last - start);
                            if (value != null)
                            {
                                // remove any leading or trailing '
                                value = value.Trim().TrimStart('\'').TrimStart('\'');
                            }
                            result = value;
                        }
                    }
                }
            }
            return result;
        }

        protected override void Apply()
        {
            foreach (XmlAttribute att in this.TargetNode.Attributes)
            {
                if (string.Compare(att.Name, this.AttributeName, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    // get current value, perform the Regex
                    att.Value = Regex.Replace(att.Value, this.Pattern, this.Replacement);
                }
            }
        }
    }
}&lt;/pre&gt;
&lt;p&gt;
In this class we have 3 properties; Pattern, Replacement, and AttributeName. All of
these values will be provided via an argument in the config transformation. For example
take a look at the element below which contains a transform attribute may look like
the following.
&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;&amp;lt;add key="two" value="two-replaced" 
         xdt:Transform="AttributeRegexReplace(Attribute='value', Pattern='here',Replacement='REPLACED')" 
         xdt:Locator="Match(key)"/&amp;gt;&lt;/pre&gt;
&lt;p&gt;
In this example I declare that I am using AttributeRegexReplace and then specify the
values for the attributes within the &lt;strong&gt;()&lt;/strong&gt;. In the class above I have
a method, GetArgumentValue, which is used to parse values from that argument string.
When your transform is invoked the string inside of () is passed in as the ArgumentString
value. If you are using a &lt;strong&gt;,&lt;/strong&gt; as the argument separator, as I am, then
you can use the Arguments list. Which will split up the arguments by the &lt;strong&gt;,&lt;/strong&gt; character.
Surprisingly in the 101 lines of code in the sample there are only a few interesting
lines. Those are what’s contained inside the Apply method. Inside that method I search
the TargetNode’s attributes (&lt;em&gt;TargetNode is the node which was matched in the xml
file being transformed&lt;/em&gt;) for an attribute with the same name as the one specified
in the AttributeName property. Once I find it I just make a call to &lt;a href="http://msdn.microsoft.com/en-us/library/e7f5w83z.aspx"&gt;Regex.Replace&lt;/a&gt; to
get the new value, and assign it. Pretty simple! Now lets see how can we use this.
&lt;/p&gt;
&lt;p&gt;
Let’s say you have the following very simple web.config
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;appSettings&amp;gt;
    &amp;lt;add key="one" value="one"/&amp;gt;
    &amp;lt;add key="two" value="partial-replace-here-end"/&amp;gt;
    &amp;lt;add key="three" value="three here"/&amp;gt;
  &amp;lt;/appSettings&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
If we want to be able to use our own transform then we will have to use the xdt:Import
element. You can place that element inside the xml document anywhere immediately under
the root element. This element will allow us to utilize our own transform class. It
only has 3 possible attributes.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
namespace – This is the namespace which the transform is contained in 
&lt;/li&gt;
&lt;li&gt;
path – This is the full path to the assembly&lt;/li&gt;
&lt;li&gt;
assembly – This is the assembly name which contains the transform&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
You can only use one of the two; path and assembly. Basically it boils down to how
the assembly is loaded. If you use path the assembly will be loaded with &lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadfrom.aspx"&gt;Assembly.LoadFrom&lt;/a&gt; and
if you chose to use assembly passing in the &lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.assemblyname.aspx"&gt;AssemblyName&lt;/a&gt;,
for instance if the assembly in in the GAC, then it will be loaded using &lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.load.aspx"&gt;Assembly.Load&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
I chose to use path, because I just placed the file inside of the MSBuild Extensions
directory (&lt;strong&gt;%Program Files (x86)%MSBuild&lt;/strong&gt;) in a folder named Custom.
Then I created my config transform file to be the following.
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;?xml version="1.0"?&amp;gt;

&amp;lt;configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"&amp;gt;
                        
  &amp;lt;xdt:Import path="C:\Program Files (x86)\MSBuild\Custom\CustomTransformType.dll"
              namespace="CustomTransformType" /&amp;gt;

  &amp;lt;appSettings&amp;gt;
    &amp;lt;add key="one" value="one-replaced" xdt:Transform="Replace" xdt:Locator="Match(key)" /&amp;gt;
    &amp;lt;add key="two" value="two-replaced" xdt:Transform="AttributeRegexReplace(Attribute='value', Pattern='here',Replacement='REPLACED')" xdt:Locator="Match(key)"/&amp;gt;
  &amp;lt;/appSettings&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
Then to run this I created an MSBuild file, PerformTransform.proj, which is shown
below.
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&amp;gt;
  &amp;lt;UsingTask TaskName="TransformXml"
           AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/&amp;gt;

  &amp;lt;PropertyGroup&amp;gt;
    &amp;lt;TransformDest&amp;gt;web.tranzed.config&amp;lt;/TransformDest&amp;gt;
  &amp;lt;/PropertyGroup&amp;gt;
  
  &amp;lt;Target Name="Demo"&amp;gt;
    &amp;lt;Delete Files="$(TransformDest)" /&amp;gt;
    &amp;lt;TransformXml Source="web.config"
                  Transform="web.dev.config"
                  Destination="$(TransformDest)" /&amp;gt;                  
  &amp;lt;/Target&amp;gt;
  
&amp;lt;/Project&amp;gt;&lt;/pre&gt;
&lt;p&gt;
This file uses the TransformXml task as I outlined in a previous post &lt;a href="http://sedodream.com/2010/04/26/ConfigTransformationsOutsideOfWebAppBuilds.aspx"&gt;Config
transformations outside of web app builds&lt;/a&gt;. Once you execute the Demo target with
the command msbuild PerformTransform.proj /t:Demo you will see the file web.tranzed.config
with the following contents.
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;appSettings&amp;gt;
    &amp;lt;add key="one" value="one-replaced"/&amp;gt;
    &amp;lt;add key="two" value="partial-replace-REPLACED-end"/&amp;gt;
    &amp;lt;add key="three" value="three here"/&amp;gt;
  &amp;lt;/appSettings&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
So you can see that the replacement did occur as we intended. Below you will find
the download link for the samples as well as another blog entry for more info on the
out of the box transformations.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Resources&lt;/strong&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Source download at: &lt;a title="http://sedotech.com/Content/samples/CustomTransformType.zip" href="http://sedotech.com/Content/samples/CustomTransformType.zip"&gt;http://sedotech.com/Content/samples/CustomTransformType.zip&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
More info on out of box transforms at: &lt;a title="http://vishaljoshi.blogspot.com/2009/03/web-deployment-webconfig-transformation_23.html" href="http://vishaljoshi.blogspot.com/2009/03/web-deployment-webconfig-transformation_23.html"&gt;http://vishaljoshi.blogspot.com/2009/03/web-deployment-webconfig-transformation_23.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Sayed Ibrahim Hashimi
&lt;/p&gt;</description>
      <comments>http://sedodream.com/CommentView,guid,27dcfa0d-f88c-4dc3-ace1-0e0d7ef75c1f.aspx</comments>
      <category>Config-Transformation</category>
      <category>MSBuild</category>
      <category>MSDeploy</category>
    </item>
    <item>
      <trackback:ping>http://sedodream.com/Trackback.aspx?guid=ff6dfe05-99e8-421b-aedd-d57babdeed66</trackback:ping>
      <pingback:server>http://sedodream.com/pingback.aspx</pingback:server>
      <pingback:target>http://sedodream.com/PermaLink,guid,ff6dfe05-99e8-421b-aedd-d57babdeed66.aspx</pingback:target>
      <dc:creator>Ibrahim</dc:creator>
      <wfw:comment>http://sedodream.com/CommentView,guid,ff6dfe05-99e8-421b-aedd-d57babdeed66.aspx</wfw:comment>
      <wfw:commentRss>http://sedodream.com/SyndicationService.asmx/GetEntryCommentsRss?guid=ff6dfe05-99e8-421b-aedd-d57babdeed66</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
If you are using Visual Studio 2010 then you may already be familiar with the <a href="http://msdn.microsoft.com/en-us/library/dd465326.aspx">Web.config
transformations</a> that are now available. What you might not know is that you can
use that same technology to transform config files outside of the build process. You
will need Visual Studio 2010 installed on the machine where you perform these transformations.
It is very easy to perform these transformation as well. Let’s say that we start with
the app.config file shown below.
</p>
        <pre class="brush: xml;">&lt;configuration&gt;
    &lt;connectionStrings&gt;
        &lt;clear/&gt;
        &lt;add name="Default" connectionString="Data Source=localhost;Initial Catalog=Sample01;Integrated Security=True;" /&gt;
    &lt;/connectionStrings&gt;
    
    &lt;appSettings&gt;
        &lt;add key="contactEmail" value="contact@demo.example.com"/&gt;
        &lt;add key="siteUrl" value="http://demo.example.com"/&gt;
    &lt;/appSettings&gt;
    
&lt;/configuration&gt;</pre>
        <p>
Then we create another file, transform.xml, which contains our transformations. That
file is shown below.
</p>
        <pre class="brush: xml;">&lt;configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"&gt;
    &lt;connectionStrings&gt;
        &lt;clear/&gt;
        &lt;add name="Default" connectionString="Data Source=NOT-localhost;Initial Catalog=Sample01;Integrated Security=True;" 
             xdt:Locator="Match(name)" xdt:Transform="Replace"/&gt;
    &lt;/connectionStrings&gt;

    &lt;appSettings&gt;
        &lt;add key="contactEmail" value="contact@example.com" xdt:Locator="Match(key)" xdt:Transform="Replace"/&gt;
        &lt;add key="siteUrl" value="http://example.com" xdt:Locator="Match(key)" xdt:Transform="Replace"/&gt;
    &lt;/appSettings&gt;

&lt;/configuration&gt;</pre>
        <p>
Then we can easily execute the transformations by using MSBuild. So I created a file
named trans.proj and it is shown below.
</p>
        <pre class="brush: xml;">&lt;Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&gt;
    &lt;UsingTask TaskName="TransformXml"
             AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/&gt;

    &lt;Target Name="Demo"&gt;
        &lt;TransformXml Source="app.config"
                      Transform="Transform.xml"
                      Destination="app.prod.config"/&gt;
    &lt;/Target&gt;
&lt;/Project&gt;</pre>
        <p>
This MSBuild file uses the TransformXml task which is shipped with Visual Studio 2010.
We specify the source file, transform file and the destination. Pretty straight forward.
</p>
        <p>
In order to execute this I open a Visual Studio 2010 command prompt, browse to the
directory containing both files, and enter the following command 
</p>
        <pre class="brush: plain;">msbuild trans.proj /t:Demo</pre>
        <p>
Once you do this then you will find the file app.prod.config with the following contents.
</p>
        <pre class="brush: xml;">&lt;configuration&gt;
    &lt;connectionStrings&gt;
        &lt;clear/&gt;
        &lt;add name="Default" connectionString="Data Source=NOT-localhost;Initial Catalog=Sample01;Integrated Security=True;"/&gt;
    &lt;/connectionStrings&gt;
    
    &lt;appSettings&gt;
        &lt;add key="contactEmail" value="contact@example.com"/&gt;
        &lt;add key="siteUrl" value="http://example.com"/&gt;
    &lt;/appSettings&gt;
    
&lt;/configuration&gt;</pre>
        <p>
Sayed Ibrahim Hashimi
</p>
      </body>
      <title>Config transformations outside of web app builds</title>
      <guid isPermaLink="false">http://sedodream.com/PermaLink,guid,ff6dfe05-99e8-421b-aedd-d57babdeed66.aspx</guid>
      <link>http://sedodream.com/2010/04/26/ConfigTransformationsOutsideOfWebAppBuilds.aspx</link>
      <pubDate>Mon, 26 Apr 2010 04:22:06 GMT</pubDate>
      <description>&lt;p&gt;
If you are using Visual Studio 2010 then you may already be familiar with the &lt;a href="http://msdn.microsoft.com/en-us/library/dd465326.aspx"&gt;Web.config
transformations&lt;/a&gt; that are now available. What you might not know is that you can
use that same technology to transform config files outside of the build process. You
will need Visual Studio 2010 installed on the machine where you perform these transformations.
It is very easy to perform these transformation as well. Let’s say that we start with
the app.config file shown below.
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;configuration&amp;gt;
    &amp;lt;connectionStrings&amp;gt;
        &amp;lt;clear/&amp;gt;
        &amp;lt;add name=&amp;quot;Default&amp;quot; connectionString=&amp;quot;Data Source=localhost;Initial Catalog=Sample01;Integrated Security=True;&amp;quot; /&amp;gt;
    &amp;lt;/connectionStrings&amp;gt;
    
    &amp;lt;appSettings&amp;gt;
        &amp;lt;add key=&amp;quot;contactEmail&amp;quot; value=&amp;quot;contact@demo.example.com&amp;quot;/&amp;gt;
        &amp;lt;add key=&amp;quot;siteUrl&amp;quot; value=&amp;quot;http://demo.example.com&amp;quot;/&amp;gt;
    &amp;lt;/appSettings&amp;gt;
    
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
Then we create another file, transform.xml, which contains our transformations. That
file is shown below.
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;configuration xmlns:xdt=&amp;quot;http://schemas.microsoft.com/XML-Document-Transform&amp;quot;&amp;gt;
    &amp;lt;connectionStrings&amp;gt;
        &amp;lt;clear/&amp;gt;
        &amp;lt;add name=&amp;quot;Default&amp;quot; connectionString=&amp;quot;Data Source=NOT-localhost;Initial Catalog=Sample01;Integrated Security=True;&amp;quot; 
             xdt:Locator=&amp;quot;Match(name)&amp;quot; xdt:Transform=&amp;quot;Replace&amp;quot;/&amp;gt;
    &amp;lt;/connectionStrings&amp;gt;

    &amp;lt;appSettings&amp;gt;
        &amp;lt;add key=&amp;quot;contactEmail&amp;quot; value=&amp;quot;contact@example.com&amp;quot; xdt:Locator=&amp;quot;Match(key)&amp;quot; xdt:Transform=&amp;quot;Replace&amp;quot;/&amp;gt;
        &amp;lt;add key=&amp;quot;siteUrl&amp;quot; value=&amp;quot;http://example.com&amp;quot; xdt:Locator=&amp;quot;Match(key)&amp;quot; xdt:Transform=&amp;quot;Replace&amp;quot;/&amp;gt;
    &amp;lt;/appSettings&amp;gt;

&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
Then we can easily execute the transformations by using MSBuild. So I created a file
named trans.proj and it is shown below.
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;Project ToolsVersion=&amp;quot;4.0&amp;quot; DefaultTargets=&amp;quot;Demo&amp;quot; xmlns=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&amp;quot;&amp;gt;
    &amp;lt;UsingTask TaskName=&amp;quot;TransformXml&amp;quot;
             AssemblyFile=&amp;quot;$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll&amp;quot;/&amp;gt;

    &amp;lt;Target Name=&amp;quot;Demo&amp;quot;&amp;gt;
        &amp;lt;TransformXml Source=&amp;quot;app.config&amp;quot;
                      Transform=&amp;quot;Transform.xml&amp;quot;
                      Destination=&amp;quot;app.prod.config&amp;quot;/&amp;gt;
    &amp;lt;/Target&amp;gt;
&amp;lt;/Project&amp;gt;&lt;/pre&gt;
&lt;p&gt;
This MSBuild file uses the TransformXml task which is shipped with Visual Studio 2010.
We specify the source file, transform file and the destination. Pretty straight forward.
&lt;/p&gt;
&lt;p&gt;
In order to execute this I open a Visual Studio 2010 command prompt, browse to the
directory containing both files, and enter the following command 
&lt;/p&gt;
&lt;pre class="brush: plain;"&gt;msbuild trans.proj /t:Demo&lt;/pre&gt;
&lt;p&gt;
Once you do this then you will find the file app.prod.config with the following contents.
&lt;/p&gt;
&lt;pre class="brush: xml;"&gt;&amp;lt;configuration&amp;gt;
    &amp;lt;connectionStrings&amp;gt;
        &amp;lt;clear/&amp;gt;
        &amp;lt;add name=&amp;quot;Default&amp;quot; connectionString=&amp;quot;Data Source=NOT-localhost;Initial Catalog=Sample01;Integrated Security=True;&amp;quot;/&amp;gt;
    &amp;lt;/connectionStrings&amp;gt;
    
    &amp;lt;appSettings&amp;gt;
        &amp;lt;add key=&amp;quot;contactEmail&amp;quot; value=&amp;quot;contact@example.com&amp;quot;/&amp;gt;
        &amp;lt;add key=&amp;quot;siteUrl&amp;quot; value=&amp;quot;http://example.com&amp;quot;/&amp;gt;
    &amp;lt;/appSettings&amp;gt;
    
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
Sayed Ibrahim Hashimi
&lt;/p&gt;</description>
      <comments>http://sedodream.com/CommentView,guid,ff6dfe05-99e8-421b-aedd-d57babdeed66.aspx</comments>
      <category>Config-Transformation</category>
      <category>MSBuild</category>
      <category>MSBuild 4.0</category>
      <category>MSDeploy</category>
      <category>Visual Studio</category>
      <category>Visual Studio 2010</category>
    </item>
  </channel>
</rss>