2

I have a netstandard2.0 csproj (let's call it MyPackage) that is packed at build time (as specified by GeneratePackageOnBuild) into a nuget package. This nuget package has custom props and targets in the build directory (so referencing projects get these imported).

I have another project (let's call it MyConsumer) in the same solution for testing MyPackage. I want MyConsumer to have the build asset props and targets imported from MyPackage at build time, just as if it were consuming it as a PackageReference from some remote nuget source.

How can I get this working (most simply)?

I have been able to do it via a very convoluted method where I have MyConsumer add a PackageReference to MyPackage and override the RestoreSources in MyConsumer to point to the bin directory of MyPackage. This gets very weird when running dotnet build or Visual Studio build of the sln, because project metadata is generated upfront for all projects during Restore and thus MyPackage doesn't exist at that point. The resolution was to add nested calls to MSBuild within the MyConsumer project, but then this becomes even worse, since Visual Studio restores operate quite differently than that automatic restores performed by dotnet build.

Is there any simple way of doing this?

This is what I have now

<Project> 
  <Target Name="Build">    
    <Message Text="Running inner build" Importance="high" />

    <!-- 
    Need to call MSBuild twice, once to restore, then again to restore and build to get the restore of the Sdk to work
    because of this bug in MSBuild: https://github.com/Microsoft/msbuild/issues/2455
    Note the trailing Prop=1 is required to get MSBuild to invalid it's cache of the project target imports
    -->
    <MSBuild Projects="$(MSBuildProjectFullPath)" Targets="Restore" Properties="Configuration=$(Configuration);Version=$(Version);IsInnerBuild=true;Prop=1" />
    <!-- Have to use dotnet build instead of another call to MSBuild because of another bug that prevents proper imports within the same physical process  -->
    <Exec Command="dotnet build /p:Configuration=$(Configuration) /p:Version=$(Version) /p:IsInnerBuild=true" />
    <Message Text="Finished inner build" Importance="high" />
  </Target>

  <Target Name="Restore" />

  <Target Name="RemoveBin">
    <RemoveDir Directories="bin" />
  </Target>

  <!-- Don't do real cleans old rebuild since it breaks MSBuild due to the same above bug -->
  <Target Name="Rebuild" DependsOnTargets="RemoveBin;Build">
  </Target>
</Project>
Jeff
  • 35,755
  • 15
  • 108
  • 220

1 Answers1

2

Treat ProjectReference as PackageReference or allow PackageReference to local csproj

If I understand you correct, you want to generate the package with project MyPackage, then install it to the test project MyConsumer and have the build asset props and targets imported from MyPackage at build time.

To accomplish this goal, you need to complete the following few things:

  • Make sure the project MyPackage build before the project MyConsumer.
  • Set the package into the packager source
  • Add the package MyPackage.nupkg to the test project MyConsumer during the build time.

Details for above:

  • Make sure the project MyPackage build before the project MyConsumer.

Since you wan to test the package which generated by the project MyConsumer, you should make sure this package grnerate before test project using it, so we need set the project MyConsumer reference the the project MyPackage.

  • Set the package into the packager source

You can use a post-build event for the project MyPackage to copy the package MyPackage.nupkg to the local feed, or you can just add the bin directory of MyPackage.nupkg to the package source.

  • Add the package MyPackage.nupkg to the test project MyConsumer during the build time.

Using VS 2017 and the PackageReference style of the test project MyConsumer, you can set a Directory.Build.props file into the root of your solution containing the test project MyConsumer you need:

<Project>
  <ItemGroup>
    <PackageReference Include="MyPackage" Version="1.0.* />
  </ItemGroup>
</Project>

This will add these NuGet packages to the test project MyConsumer in the solution, it will be used as a PackageReference from some remote nuget source.

Check the Martin`s answer for some more details.

Hope this helps.

Leo Liu
  • 71,098
  • 10
  • 114
  • 135
  • 1
    This is great - but exactly what I'm doing. The problem with this approach is MSBuild "issues/bugs/whatever you want to call them" with regard to restoring packages and resolving package specific build targets. See answer question above on all the complexity required to get this working... – Jeff May 14 '18 at 17:54
  • 1
    @Jeff, Yes, you are right. If you are using dotnet build the solution, you would have the issue "project metadata is generated upfront for all projects during Restore and thus MyPackage doesn't exist at that point.". To resolve this, you can use MSBuild to build the project `MyPackage` first, then use `msbuild /t:restore` to restore the package for the solution. At this moment, seems we have no any simple solution. – Leo Liu May 15 '18 at 09:16
  • Thanks Leo. The enhancements to MSBuild 15 and nuget integration are great, but without a way to test and develop, we are left with buggy, immature solutions. I’ll stick with the convoluted approach. Note that it’s not quite as simple as build/restore even because of various bugs in how MSBuild does the caching (see comments in the code sample I posted above) – Jeff May 16 '18 at 04:39