Search code examples
c#parametersmsbuild.net-4.5

How to read a MSBuild property in a given project in runtime?


I want to access a MSBuild variable inside an unit test, which is a .NET 4.5 class library project (classic csproj), but I failed to find any articles discussing a way to pass values from MSBuild into the execution context.

I thought about setting an environment variable during compilation and then reading that environment variable during execution, but that seems to require a custom task to set the environment variable value and I was a bit worried about the scope of the variable (ideally, I only wanted it to be available to the currently executing project, not globally).

Is there a known solution to reading an MSBuild property from inside a DLL project in runtime? Can MSBuild properties be "passed as parameters" during execution somehow?


Solution

  • I finally made it work by using the same code generation task that is used by default in .Net Core projects. The only difference is that I had to manually add the Target in the csproj file for it to work, as code creation is not standard for framework projects:

    <Target Name="BeforeBuild">
      <ItemGroup>
        <AssemblyAttributes Include="MyProject.SolutionFileAttribute">
          <_Parameter1>$(SolutionPath)</_Parameter1>
        </AssemblyAttributes>
      </ItemGroup>
      <WriteCodeFragment AssemblyAttributes="@(AssemblyAttributes)" Language="C#" OutputDirectory="$(IntermediateOutputPath)" OutputFile="SolutionInfo.cs">
        <Output TaskParameter="OutputFile" ItemName="Compile" />
        <Output TaskParameter="OutputFile" ItemName="FileWrites" />
      </WriteCodeFragment>
    </Target>
    

    The lines with Compile and FileWrites are there for it to play nicely with clean and such (see linked answers in my comments above). Everything else should be intuitive enough.

    When the project compiles, a custom attribute is added to the assembly, that I can then retrieve using normal reflection:

    Assembly
        .GetExecutingAssembly()
        .GetCustomAttribute<SolutionFileAttribute>()
        .SolutionFile
    

    This works really well and allows me to avoid any hardcoded searches for the solution file.