We have a C# custom property applied at the assembly level to a few hundred projects in the one solution. It takes a number of arguments which are a mixture of constants, values supplied at build time, and others inserted by code generation. The attribute may also be applied more than once per assembly. I'm looking to automate away some of the fragility in this setup. All the projects use csproj SDK XML.
The <AssemblyAttribute> element in a csproj <ItemGroup> looks ideal for this, but the nature of the parameters to this attribute makes it verbose to write this way. Ideally I'd like to just be able to specify the bit that varies per project, something like:
<OurCustomAttribute Value="ProjectSpecificValue"/>
<OurCustomAttribute Value="ProjectSpecificValueTwo"/>
or similar, either in an <ItemGroup>, directly inside the <Project> element itself, or a near equivalent, and have it be transformed into something like:
<ItemGroup>
<AssemblyAttribute Include="Namespace.OurCustomAttribute">
<_Parameter1>ProjectSpecificValue-InvariantValue</_Parameter1>
<_Parameter2>$(SomeProperty)</_Parameter2>
<_Parameter3>$(SomeOtherProperty)-some-static-string</_Parameter3>
<!-- ...etc... -->
</AssemblyAttribute>
<AssemblyAttribute Include="Namespace.OurCustomAttribute">
<_Parameter1>ProjectSpecificValueTwo-InvariantValue</_Parameter1>
<_Parameter2>$(SomeProperty)</_Parameter2>
<_Parameter3>$(SomeOtherProperty)-some-static-string</_Parameter3>
<!-- ...etc... -->
</AssemblyAttribute>
</ItemGroup>
We are using a Directory.Build.props, so some way of defining this behaviour in there would be ideal. Item transforms don't seem capable of this; I've seen from the docs that an inline Task could output items, but it's not clear to me how this could be (terse-ish-ly) invoked from the project file (custom Target somehow?), or if they would be picked up by the Targets which followed, or which BeforeTarget would need to be used here. We'd prefer not to have to create a custom task assembly for this.
Is this kind of parameterisation actually possible in MSBuild XML?
You can use properties and define the item inside of
Directory.Build.props.The important thing is that MSBuild performs multiple passes over the enitre project and its imports, meaning that for example it reads all the
PropertyGroupelements before it processes all theItemGroupelements. SinceDirectory.Build.propsis imported near the top of the SDK and thus logically before your actual csproj content, you can define properties with defualt values inDirectory.Build.Propsand then also define theItemGroupwith your assembly attribute item in it in the same file - the property can then still be overwritten in the maincsprojfile.For example consider a
MyCorp.ComponentNameAttributewith a name and a description and also the target framework used:Directory.Build.props:And
ComponentA.csprojcould then set:If you want to modify properties AFTER the project content has been set, you can use
Directory.Build.targetsto have more property groups with conditions on them or when you need to rely on other properties that are set during the project evaluation as defaults (e.g. theTargetFrameworkis not yet known when processingDirectory.Build.propsbut should be there whenDirectory.Build.targetsis evaluated).Directory.Build.targets: