Technology

Deploying app.config transformation through NuGet packages

There is a not-very-well-documented, and in my opinion limited, library from Microsoft called XML Document Transformation (XDT) that can be used to transform XML files by using XML attributes and a transformation file. The syntax reference information can be found here. The library itself is also distributed via NuGet. Many online articles have discussed the *.config transformation, including Custom web.config transforms and mergeUsing web.config transforms with app.config files and XDT (web.config) Transforms in non-web projects. Additionally, deploying XDT in NuGet packages have also been discussed in a few articles, such as How to use XDT in NuGet – Examples and Facts, and Configuration File and Source Code Transformation.

The limitations of the XDT are observed by the number of out-of-the-box verbs available to perform the transformation: Insert, Replace, InsertBefore, Remove, etc. (See source code for a complete list.) At first glance, they seem enough. But depending on the complexity, the initial and the end state of the XML file, those verbs won’t suffice. Luckily, the developers can write their own transform verb, as seen here.

The problem this article addresses is the transformation of app.config (or web.config) files with custom transforms during the installation of NuGet packages. This article shows the example of a NuGet package that requires the <configSections> to be added, if missing, as the first element inside the app.config  <configuration> element, and a child  <section> element also to be added to the app.config file of the Visual Studio project where the package is installed. Subsequently, the <section>  element references a <system.identitymodel> element that was also dynamically included in the app.config file.

The specific limitation with the existing XDT verbs was that if the  <configSections> existed, the child <section>  element would not be added. Well, maybe if the right combination of InsertIfMissing and Insert attributes was employed it would be possible. But I decided to take on the challenge of writing a custom transform that is a combination of the InsertBefore and InsertIfMissing verbs:

There was also a limitation of inserting child elements using the Insert verb when there was at least one existing child element in the XML file. The InsertChildElementIfMissing custom transform was written:

The transformation file (app.config.install.xdt):

At this point, the DLL with the custom transform classes and the .install.xdt file were completed. The .install.xdt file was added to the Content folder in the NuGet package. However, during the package installation, NuGet.exe would fail to find the custom transform classes. The first reaction is to add the custom transform DLL also to the NuGet Content folder. But still fails!!! Apparently, during the package installation and execution of XDT transformation, NuGet.exe requires the custom transformation DLL to be installed in the GAC or be in the executing folder of the caller. Installing the custom transformation DLL in the GAC was not an option for me, since the DLL would be packaged in the NuGet and only called during the package installation. The second option: where is the executing folder or NuGet.exe or whatever process that installs the NuGet package? Admittedly I didn’t look for it. Even if I found it, I would need to read it from the environment where the package would be installed to guarantee success installation on different machines, and I would need to create an install.ps1 to copy the DLL to that folder before the XDT transformation is executed.

The Workaround

After many hours trying deploy custom XDT transform via NuGet package, the solution (or workaround) was settled by packaging the .install.xdt and custom transform DLL in the NuGet Tools folder, and write an install.ps1 that call the transformation out. Similar solution is described here.

Since install.ps1, the custom transform DLL and the .config.xdt file are all copied to the NuGet Tools folder, the custom transform DLL is always found since it is the same location as the ps1 script file.

Conclusion

This solution couldn’t take advantage of the automatic invocation of app.config.install.xdt as described here due to problems encountered for properly packaging custom transform in the NuGet package. If only out-of-the-box verbs are used, the app.config.install.xdt in the Content folder works flawlessly. But the support for custom transform in NuGet turned out to be a non-trivial task. The use of install.ps1 PowerShell script came to address the problems and potential limited support for custom transform deployment via NuGet.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.