NuGet Package Transformations

code, nuget, open source 0 comments suggest edit

Note, this blog post applies to v1.0 of NuGet and the details are subject to change in a future version.

In general, when you create a NuGet package, the files that you include in the package are not modified in any way but simply placed in the appropriate location within your solution.

However, there are cases where you may want a file to be modified or transformed in some way during installation. NuGet supports two types of transformations during installation of a package:

  • Config transformations
  • Source transformations

Config Transformations

Config transformations provide a simple way for a package to modify a web.config or app.config when the package is installed. Ideally, this type of transformation would be rare, but it’s very useful when needed.

One example of this is ELMAH (Error Logging Modules and Handlers for ASP.NET). ELMAH requires that its http modules and http handlers be registered in the web.config file.

In order to apply a config transform, add a file to your packages content with the name of the file you want to transform followed by a .transform extension. For example, in the ELMAH package, there’s a file named web.config.transform.

web.config.transform-content

The contents of that file looks like a web.config (or app.config) file, but it only contains the sections that need to be merged into the config file.

<configuration>
    <system.web>
        <httpModules>
            <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
        </httpModules>
        <httpHandlers>
            <add verb="POST,GET,HEAD" path="elmah.axd"              type="Elmah.ErrorLogPageFactory, Elmah" />
        </httpHandlers>
    </system.web>
    <system.webServer>
        <validation validateIntegratedModeConfiguration="false" />
        <modules>
            <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
        </modules>
        <handlers>
            <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd"              type="Elmah.ErrorLogPageFactory, Elmah" />
        </handlers>
    </system.webServer>
</configuration>

When NuGet sees this transformation file, it attempts to merge in the various sections into your existing web.config file. Let’s look at a simple example.

Suppose this is my existing web.config file.

Existing web.config File

<configuration>
    <system.webServer>
        <modules>
            <add name="MyCoolModule" type="Haack.MyCoolModule" />
        </modules>
    <system.webServer>
</configuration>

Now suppose I want my NuGet package to add an entry into the modules section of config. I’d simply add a file named web.config.transform to my package with the following contents.

web.config.transform File

<configuration>
    <system.webServer>
        <modules>
            <add name="MyNuModule" type="Haack.MyNuModule" />
        </modules>
    <system.webServer>
</configuration>

After I install the package, the web.config file will look like

Existing web.config File

<configuration>
    <system.webServer>
        <modules>
            <add name="MyCoolModule" type="Haack.MyCoolModule" />
            <add name="MyNuModule" type="Haack.MyNuModule" />
        </modules>
    <system.webServer>
</configuration>

Notice that we didn’t replace the modules section, we merged our entry into the modules section.

I’m currently working on documenting the full set of rules for config transformations which I will post to our NuGet documentation page once I’m done.I just wanted to give you a taste for what you can do today.

Also, in v1 of NuGet we only support these simple transformations. If we hear a lot of customer feedback that more powerful transformations are needed for their packages, we may consider supporting the more powerful web.config transformation language as an alternative to our simple approach.

Source Transformations

NuGet also supports source code transformations in a manner very similar to Visual Studio project templates. These are useful in cases where your NuGet package includes source code to be added to the developer’s project. For example, you may want to include some source code used to initialize your package library, but you want that code to exist in the target project’s namespace. Source transformations help in this case.

To enable source transformations, simply append the .pp file extension to your source file within your package.

Here’s a screenshot of a package I’m currently authoring.

Models

When installed, this package will add four files to the target project’s ~/Models directory. These files will be transformed and the .pp extension will be removed. Let’s take a look at one of these files.

namespace $rootnamespace$.Models {
    public struct CategoryInfo {
        public string categoryid;
        public string description;
        public string htmlUrl;
        public string rssUrl;
        public string title;
    }
}

Notice the highlighted section that has the token $rootnamespace$. That’s a Visual Studio project property which gets replaced with the current project’s root namespace during installation.

We expect that $rootnamespace$ will be the most commonly used project property, though we support any project property such as $FileName$. The available properties may be specific to the current project type, but this MSDN documentation on project properties is a good starting point for what might be possible.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

21 responses

  1. Avatar for Paulo
    Paulo November 19th, 2010

    Hi Phil,
    It's nice to see how deployment and configuration features of the .NET platform are maturing (either by Microsoft or community's hands).
    I still remember how happy I was when MSBuild Community Tasks were released, giving us XmlMassUpdate. Old times...
    -- Paulo

  2. Avatar for Ryan
    Ryan November 19th, 2010

    Any plans for project file transformations? I'm kicking around the idea of using nuget as a means of sharing our Code Analysis ruleset. The only missing piece is setting the ruleset in the project properties.

  3. Avatar for Thomas Eyde
    Thomas Eyde November 19th, 2010

    It's nice to see config transformation done right. I really hope the awful, terrible xslt thing in visual studio will be replaced soon.

  4. Avatar for haacked
    haacked November 19th, 2010

    @Ryan you could probably do this by adding an Install.ps1 file. We have a PowerShell method Get-Project which gives you access to the Project's DTE. From that, you could modify the project.

  5. Avatar for Martin
    Martin November 19th, 2010

    I really find the Transformations annoying.
    Mostly because its reformats the entire config file.
    Also I already had Elmah added so it added double registrations everywhere.
    Could you please rename the package.config file to be named with a capital P (in "Package") ?
    All other files created (Web.Config, Global.asax ...) are starting with a capital letter.

  6. Avatar for Developer Seer
    Developer Seer November 19th, 2010

    This is looking Awesome Phil!
    I'm wondering how much time will it be to nuget be released, although I don't like the name, its a freeking awesome tool. And together with HanselScafold and ASP.NET MVC 3 we can rule the world!
    I'm wondering when will MVC 3 and Nuget RTM!

  7. Avatar for MartinF
    MartinF November 20th, 2010

    It really needs to be easier to upload your package to Nuget.
    The idea is really great it is much needed, makes life a lot easier.

  8. Avatar for Harry McIntyre
    Harry McIntyre November 20th, 2010

    Hi Phil,
    I've been trying to get the author one of my favourite OS projects Genuilder (an AMAZING code pre-processor) to put it on NuGet, but the problem is that it needs to add a custom msbuild target into the project. Is there any way to alter the csproj file currently in NuGet?

  9. Avatar for Harry McIntyre
    Harry McIntyre November 20th, 2010

    Oops I only just read your response to Ryan, above. Maybe that will solve the problem.

  10. Avatar for Jim Geurts
    Jim Geurts November 21st, 2010

    Hey Phil,
    Is there a way to modify certain parts of source files, similar to the web.config transforms? For example, I have a package that requires initialization code to be added to the Application_Start method and tear down code added to the Application_End method in Global.asax.cs. Additionally, it requires a static field variable to be added to that class.
    I know I could move that logic to a http module and use a config transform to register the module, but I prefer to keep it in the global.asax.cs, in this case.
    Thanks,
    Jim

  11. Avatar for Jeroen Trappers
    Jeroen Trappers November 22nd, 2010

    Hi Phil,
    I saw a presentation about this at Tech-Ed Berlin. I really like it, however something is missing concerning source-control. The linked external libraries should be put in a solution folder for them to be checked in. Otherwise other team members wouldn't get the new references, and run into compilation issues.
    It this the responsibility of the framework, the nuget-package creators or that of the users?
    Kind regards,
    Jeroen

  12. Avatar for Andreas Knuden
    Andreas Knuden November 22nd, 2010

    Hi Phil, the simplicity and readability of the config transformations is great!
    Just a thought, instead of introducing a somewhat cumbersome transformation language to the files, you could achieve the same if you only added support for defining one magic word like "DELETEME" for instance.
    you would be able to delete attributes by setting their value to that magic word like this someattributevalue="DELETEME", you would also be able to delete whole nodes by setting DELETEME="true" as per this implementation of n-tier web.config transformations using T4: ilearnable.net/.../t4-for-complex-configuration/
    just a thought

  13. Avatar for ashic
    ashic December 1st, 2010

    Any reason why VS config transform syntax can't be used for the config transforms? I know there wouldn't be much use of all syntax options, but since we already have a syntax for config transforms in 2010, why not reuse that?

  14. Avatar for haacked
    haacked December 1st, 2010

    @ashic We plan to support that in the future. But we wanted something even simpler.
    Based on looking at a large number of libraries, most of them need little to no configuration. We felt it would be easier for package authors to simply cut and paste the section of their existing configuration file as a means of writing a config transform rather than having to learn a new config transform language.
    If supporting VS Config transforms is important to you, vote it up: http://nuget.codeplex.com/workitem/232

  15. Avatar for haacked
    haacked December 7th, 2010

    @Jim there's no way currently for NuGet to add code to parts of an existing file. In general, that type of feature is problematic. Not everyone wants a package manager to modify existing code. Instead, we do have a WebActivator package for that purpose.

  16. Avatar for Jim Geurts
    Jim Geurts December 10th, 2010

    Thanks for the link Phil. That looks like it will work nicely until a cleaner solution is available in asp.net.

  17. Avatar for Tony
    Tony February 28th, 2011

    Is there a way to combine the effects of pp and transform extensions? I am trying to apply a code transformation into a web.config (basically $assemblyname$ and $rootnamespace$) and then merge the resulting config file transform. I was hoping for naming my config file web.config.transform.pp would do the trick but no such luck.

  18. Avatar for Trevor Germain
    Trevor Germain April 14th, 2011

    Definately implement the native config file transformation language. It is very powerful, and easy to understand!

  19. Avatar for Calabonga
    Calabonga June 18th, 2011

    How I can transform css-files or cshtml-files?

  20. Avatar for Vince Panuccio
    Vince Panuccio September 26th, 2011

    Hi Phil,
    Any news on more powerful config transforms features? It's been almost a year since this article was posted and I can't seem to find any information on removing elements using transform files.
    Thanks,
    Vince

  21. Avatar for Саша Махов
    Саша Махов November 27th, 2013

    Hello guys!
    You know, some project contains Web.config and come - App.config. Does transformation correctly solves a problem of modifying actual *.config file?