How can I prevent external MSBuild files from bein

2020-05-20 08:58发布

问题:

I have a project in my solution which started life as a C# library project. It's got nothing of any interest in it in terms of code, it is merely used as a dependency in the other projects in my solution in order to ensure that it is built first. One of the side-effects of building this project is that a shared AssemblyInfo.cs is created which contains the version number in use by the other projects.

I have done this by adding the following to the .csproj file:

<ItemGroup>
  <None Include="Properties\AssemblyInfo.Shared.cs.in" />
  <Compile Include="Properties\AssemblyInfo.Shared.cs" />
  <None Include="VersionInfo.targets" />
</ItemGroup>
<Import Project="$(ProjectDir)VersionInfo.targets" />
<Target Name="BeforeBuild" DependsOnTargets="UpdateSharedAssemblyInfo" />

The referenced file, VersionInfo.targets, contains the following:

<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <!--
      Some properties defining tool locations and the name of the
      AssemblyInfo.Shared.cs.in file etc.
    -->
  </PropertyGroup>
  <Target Name="UpdateSharedAssemblyInfo">
    <!--
      Uses the Exec task to run one of the tools to generate
      AssemblyInfo.Shared.cs based on the location of AssemblyInfo.Shared.cs.in
      and some of the other properties.
    -->
  </Target>
</Project>

The contents of the VersionInfo.targets file could simply be embedded within the .csproj file but it is external because I am trying to turn all of this into a project template. I want the users of the template to be able to add the new project to the solution, edit the VersionInfo.targets file, and run the build.

The problem is that modifying and saving the VersionInfo.targets file and rebuilding the solution has no effect - the project file uses the values from the .targets file as they were when the project was opened. Even unloading and reloading the project has no effect. In order to get the new values, I need to close Visual Studio and reopen it (or reload the solution).

How can I set this up so that the configuration is external to the .csproj file and not cached between builds?

回答1:

I've just answered what appears to be a similar question on this.

How to turn off caching of build definitions in Visual studio

Hopefully it's relevant your issue too.



回答2:

As far as I know, you can't. Visual Studio is not using 'real' MSBuild, it uses an internal build engine that behaves very similar to MSBuild.exe, but still have some subtle differences. This build engine caches the targets, so you have to restart VS once you change something. I believe, it is even documented somewhere, and there is no known workaround (I searched for it about a year ago and found nothing).

You could possibly force the VS to reload the targets via VS API - so, you'll have to create (or find) a custom add-on to do this.

Another option is to use something other than .targets file to store your configuration. For instance, you could use a plain text file and parse it with MSBuild (not that elegant, but it should work).

Upd.

That's what I did some time ago. MSBuild calls an external tool via Exec with WorkingDirectory="$(SolutionDir)", the tool "knows" all the conventions about file names, locations etc., so a working directory is enough to get the job done. Miscellaneous configuration data is stored in the external tool's config, so no problems with caching.

Also, have a look at this question about reading items from a file. I suppose, that better suites your needs.



回答3:

I had some intermittent success by modifying the project file including the custom msbuild file and making it invalid, then reloading the project, let it stay unloaded, then fixing the project file and reloading.

Sometimes it works, sometimes it doesn't, but better than restarting Visual Studio.



回答4:

If you need a quick and dirty way to fix it, you may simply reload the solution (via https://stackoverflow.com/a/6877056/182371).

You can do it either by closing-opening the solution file or by hitting Save in an external editor (then when you come back to VS it will asko if you want to reload).