msbuildnamingname-collisionmsbuild-propertygroup

How do I ensure my MSBuild properties are not already defined somewhere else?


Is there a way to know if the name for a MSBuild property I want to create is not already being used somewhere else in my solution? How do I create MSBuild customizations that are safe from property name conflicts?

For context, I just spent several hours trying to debug an issue that started after I updated Visual Studio to v17.3: a new NuGet warning was introduced that would alert to duplicate package references being added, and this warning started to fire in a few of my projects even though I didn't (at first glance) have duplicate packages added.

I initially documented the problem here:

However, after investigating it further, I found out that the source of the problem was due to me using an existing MSBuild property for our customization that was already defined by another process. This created a conflict where sometimes the property was true even though I defined it as false, because it was defined as true somewhere else, and I was completely oblivious to it.

Once I renamed the property to avoid the conflict, the problem immediately went away.

When I found out this was the issue, I immediately changed MSBuild log level to Diagnostic, to see if I could find where the property was being defined: if I found it this way, I could use the same approach in the future when creating new variables, so that I wouldn't run into conflicts again. This however wasn't effective: I could still not find the existing property anywhere in the build logs.

How can I be sure that I'm not inadvertently reusing some property defined elsewhere when coming up with new property names for my own MSBuild customizations? Similarly, how would external parties ever safely create their properties without risking a conflict with properties already defined in consumer's projects for other purposes? Is there such a thing as a "scope" or "namespace" that can be used with MSBuild to ensure isolation of such properties?


Solution

  • You can test if a property is already defined or not.

    <Message Text="MyProperty: $(MyProperty)" Condition="'$(MyProperty)' != ''" />
    

    The following PropertyGroup will set MyProperty when it doesn't already have a value. (This example is from MSBuild best practices.)

    <PropertyGroup>
      <MyProperty Condition="'$(MyProperty)' == ''">MyDefaultValue</MyProperty>
    </PropertyGroup>
    

    There is no scope or namespace for properties from different sources.

    You can name all your properties (and ItemGroups and Targets) with a specific prefix to reduce the risk of name collisions. The underscore character is safe to use in property names. A leading underscore is sometimes used to indicate an 'internal' property but is otherwise uncommon in a property name. (There is no scope or access protection. It is just a naming convention.)

    You could use an underscore as the last character of your prefix. As an example, if your company were "Acme Corporation" you might use:

    <PropertyGroup>
      <ACME_MyProperty Condition="'$(MyProperty)' == ''">MyDefaultValue</ACME_MyProperty>
    </PropertyGroup>