Issue Using PostSharp 3.x with NuGet Auto Restore - c#

I have a solution with many projects, some of which use PostSharp. I've recently switched from using NuGet MSBuild integrated restore to NuGet Auto Restore. This causes all necessary packages to be restored for all packages before a build starts. This works great, except for now I come across an issue frequently where PostSharp will fail the build with the error:
The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://www.postsharp.net/links/nuget-restore.
When I edit the project file I see the following entry:
<Import Project="..\..\packages\PostSharp.3.1.46\tools\PostSharp.targets" Condition="Exists('..\..\packages\PostSharp.3.1.46\tools\PostSharp.targets')" />
<Target Name="EnsurePostSharpImported" BeforeTargets="BeforeBuild" Condition="'$(PostSharp30Imported)' == ''">
<Error Condition="!Exists('..\..\packages\PostSharp.3.1.46\tools\PostSharp.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://www.postsharp.net/links/nuget-restore." />
<Error Condition="Exists('..\..\packages\PostSharp.3.1.46\tools\PostSharp.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://www.postsharp.net/links/nuget-restore." />
</Target>
As you can see, there is an error condition for when the NuGet package exists on my machine and also doesn't exist on my machine. It appears that these conditions are evaluated because the variable $(PostSharp30Imported) is never set. I'm assuming this something that is dependent on the MSBuild integrated version of restore, but I don't have enough MSBuild experience to know for sure.
I am able to work around the issue by simply removing the second Error condition in the project file (since I am guaranteed to have the files by the time the project builds), but it seems like any upgrades or additions of PostSharp cause the project file to revert to the old way and prevents my solution from building.
Is this a bug in PostSharp, or is there some other way I should be working with PostSharp when using NuGet auto restore that does not cause this issue?

If you have completely migrated from the old MSBuild based package restore away then you should not see that error message if you are using a recent version of NuGet. Visual Studio checks for the existence of the .nuget/NuGet.targets file and does not use the new Visual Studio based package restore if this file exists.
The newer automatic package restore will occur when you build the project but before MSBuild is started. This means the various MSBuild properties that are defined in the PostSharp MSBuild targets file will be imported before MSBuild tries to compile your project. In this case the PostSharp30Imported should be defined so that custom target is never run. It would only be run if the PostSharp.targets file did not exist whilst MSBuild was compiling the project.
The error message is correct for the older MSBuild based package restore since the build would restore the targets file whilst MSBuild was running so they would not be available, and therefore not imported, for the first build.
Creating a new project, adding PostSharp, deleting all the packages, then recompiling the project I see no error message.

Related

Exclude Project in sln from dotnet build

I have a roslyn analyzer project based on Microsoft's default template. I can easily build the analyzer in Visual Studio or with msbuild.
The problem is that the solution includes a vsix project that relies on the microsoft.vssdk.buildtools which are not supported by dotnet build.
This results in an error message when trying to build the solution in the command line with dotnet build: microsoft.vssdk.buildtools\17.4.2119\tools\VSSDK\Microsoft.VsSDK.targets(826,5): error : VSIX deployment is not supported with 'dotnet build'
The vsix is nice to have when developing with Visual Studio, but I do publish my analyzer via NuGet package instead of as vsix so I don't need the vsix on the CLI.
Is there a way to specify in the csproj that I don't want it to be built when it is invoked from dotnet build? I'd like to avoid having a separate sln file or a specific dotnet configuration that excludes the project if possible.
Two possible approaches include using a solution filter and changing the project to not build under certain conditions.
Use a Solution Filter
dotnet build will accept a solution filter file (.slnf).
To create the solution filter:
Open the solution in Visual Studio
Go to the solution explorer window
Right-click on the VSIX project, choose 'Unload Project'
Right-click on the solution, choose 'Save As Solution Filter'
When building with dotnet the .slnf will need to be used. Using the .sln file or the VSIX project file with dotnet will be an error.
Detecting when Invoked from dotnet build
There isn't a defined property or function in MSBuild that identifies the executable that is running the MSBuild engine.
However there is a MSBuildRuntimeType property.
Prior to MSBuild 15, MSBuildRuntimeType will be undefined. In MSBuild 15 and later MSBuildRuntimeType will have a value of Full, Core, or Mono. From the documentation MSBuildRuntimeType will have a value of Core when dotnet build is used. (Further the error message "VSIX deployment is not supported with 'dotnet build'" is only displayed when '$(MSBuildRuntimeType)' == 'Core'.)
There isn't an 'exit build' task so the project can't detect and then end. We need to detect before the project really starts. But wrapping a project within a project is clunky especially if you want to be able to work with the project and change properties from the Visual Studio IDE.
Targets can be redefined and an Import can have a condition. A file can be imported when MSBuildRuntimeType is Core and the file can redefine the 'Build' target.
Add to the VSIX project file:
<Import Project="noop.targets" Condition="'$(MSBuildRuntimeType)' == 'Core'" />
The noop.targets may contain the following:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<Message Text="$(MSBuildProjectName) has been skipped." />
</Target>
</Project>
Hope this helps or at least provides some ideas.

Does MSBuild always copies nuget PackageReference of csproj files to the build output directory?

In the net core world, you have to invoke the publish command to bring the assemblies, referenced through nuget, into your projects output directory.
In the .NET Framework world, there is no publish command. My assumption was that msbuild always resolves the referenced nuget packages and copies the assemblies to the output directory. On my developer machine this works always.
Now we see problems that this does not happen during an automated build and colleagues started to add references with the GeneratePathProperty and do an explicit copy action with CopyToOutputDirectory. In my eyes that's wrong and error prone because transitive dependencies are not resolved automatically.
Can someone point me to a piece of msbuild documentation which explains the nuget handling?

VS Build fails for .NET project because of NuGet package restore errors

I am working on an MVC.NET project using .NET 4.5.2 in Visual Studio 17 which is unable to build due to the error:
The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://www.postsharp.net/links/nuget-restore.
My version of PostSharp is 4.1.30.
This error happens every time I build or rebuild the proejct and doesn't disappear after building several times in a row. The error is happening for several projects which reference PostSharp.
The error only occurs after I make a change within the solution. If I checkout a fresh copy of Trunk, I can load the website. It's only after making a chance that these errors occur. The change can be small, such as adding a new controller file in an unrelated project to where the errors reference.
I've tried restoring my NuGet packages, rebooting my machine, even deleting my repo and re-checking out a clean install of Trunk. How can I get past this error? I'm not sure if it's definitely related to PostSharp, or a more general NuGet error.
After looking in the .csproj file to see what is causing the error in one of the projects, I found these lines:
<Import Project="packages\PostSharp.4.1.25\tools\PostSharp.targets" Condition="Exists('packages\PostSharp.4.1.25\tools\PostSharp.targets')" />
<Target Name="EnsurePostSharpImported" BeforeTargets="BeforeBuild" Condition="'$(PostSharp30Imported)' == ''">
<Error Condition="!Exists('packages\PostSharp.4.1.25\tools\PostSharp.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://www.postsharp.net/links/nuget-restore." />
<Error Condition="Exists('packages\PostSharp.4.1.25\tools\PostSharp.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://www.postsharp.net/links/nuget-restore." />
</Target>
I tried removing it to see what would happen but perhaps unsuprisingly it didn't build and didn't report any errors.
This looks like an issue with upgrading of the PostSharp NuGet package. In your .csproj file, there is PostSharp 4.1.25 installed, but you say you are using PostSharp 4.1.30.
One of the following might help:
Either change the package version in packages.config to 4.1.25, check if the project builds and then use NuGet Package manager to upgrade to a newer version if needed,
or remove PostSharp from packages.confing and .csproj (the lines you are showing + reference to PostSharp.dll and any other PostSharp.*.dll), then install PostSharp using NuGet package manager.
Please note that PostSharp 4.1 is no longer supported. See https://www.postsharp.net/support/policies#support for list of supported versions.

NuGet package refuses to uninstall in .NET Core library

I'm creating a .NET Core xUnit test project library in VS2017. I accidentally installed the System.Collections.Immutable NuGet package, and now I want to uninstall it.
First, I tried editing the csproj file and removing this line:
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
That didn't work, since the types from that package were still highlighted in the editor. So I tried running Uninstall-Package System.Collections.Immutable in the Package Manager Console.
The console said it couldn't find the package, so I tried putting the <PackageReference... line above back and running Uninstall-Package again. The console said the uninstall succeeded, but VS still recognized the types.
I tried closing VS, deleting .vs/, and reopening. It still recognized the types.
I tried git stashing my changes, running git clean -xdf, and running dotnet restore from the command line. Somehow, it still outputs
$ dotnet restore
Restoring packages for C:\cygwin64\home\james\Code\cs\BlockList\src\BlockList\BlockList.csproj...
Restoring packages for C:\cygwin64\home\james\Code\cs\BlockList\src\BlockList.Tests\BlockList.Tests.csproj...
...
Installing System.Collections.Immutable 1.2.0.
Installing System.Collections.Immutable 1.3.0.
...
I also tried restoring from Visual Studio instead of the command line. Still no luck.
When I searched all the files in my repo for the word Immutable, the only thing popping up is project.assets.json in the obj directory. Not a single source file contains the word Immutable. I'm confused, then, as to how it's still being referenced. How can I uninstall it?
A few other things:
I checked the 'Dependencies' drop-down for my project in Solution Explorer, and it's not listed there.
I don't want to delete my local copy of the repo and re-clone it, since I have other work stashed.
System.Collections.Immutable.dll doesn't show up at all in the bin/ directory, yet when I use one of the types in my library and run it, it works fine.
Thanks!
edit: Adding this line to the library:
System.Diagnostics.Debug.WriteLine(typeof(ImmutableArrayExtensions).GetTypeInfo().Assembly.Location);
And running it says that the assembly is located in this location:
C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.1.2\System.Collections.Immutable.dll
After about an hour, I found out what the problem was. My .NET Core library referenced Microsoft.NETCore.App, which referenced System.Collections.Immutable. I looked at the dependencies for the former, but overlooked System.Collections.Immutable because that package references maybe 50 other packages. I ended up finding this out by creating a brand-new xUnit test project, and trying to see if ImmutableArray<> was present without installing anything. Sure enough, I could use it out of the box.
I had a similar issue with VS2017 and a different nuget package that wouldn't fully uninstall. I ultimately had to create a new project and cut and paste all my code into it. Kind of a sledge hammer approach, but faster than crawling through dependencies.

How to add a nuget package to the package.config the proper way?

For my C# project I am maintaining a packages.config which includes all the dependencies my project requires. Over the time I have been copy-pasting the entries manually using a regular text editor, checking in the version number I found on the NuGet website and so on. To restore the package upon a checkout, I use nuget -o nuget-packages install packages.config which worked good so far (I am using Xamarin Studio on non-windows systems, so no VS available).
I was just realizing that messing with the packages.config in a text editor couldn't be the intended way. I know from npm and bower that a npm install --save-dev <pkg-xy> will to the job and write the package version back to the config. Is there an equivalent of this in NuGet.exe?
From the command line this not supported. You will have to edit the packages.config file manually, or write a utility to do this work for you, or extend NuGet.exe with this feature.
There is no equivalent in NuGet to NPM's npm install -save
Currently the only way to have the packages.config file automatically updated when you want to install a new NuGet package to your project is to use an IDE, such as Visual Studio or Xamarin Studio, and actually install the package. Using NuGet.exe from the command line does not have an option to add/remove entries in to/from the packages.config file when installing a new package.
NuGet.exe does have an update command which will update the package to the latest version. Whilst this would update your packages.config file it also updates your project file by adding any assembly references that the NuGet package needs.
You really shouldn't be editing packages.config. Package Restore doesn't do what you think it does. It simply downloads any missing packages that are listed in packages.config.
You might think this is what you want, but Package Restore does NOT add references to your project. It also doesn't do any of the other things the package creator had intended like running an install.ps1 script.
When installing a package, NuGet handles all of this, so your project files have added references, content, etc. This and the packages.config file is what you would commit to source control. You can leave out the actual packages folder, so you don't have to commit large binary files.
When you open the solution and build, NuGet will see that the packages are missing and will download them as if you had checked them in. The actual "install" was already done (and committed). That is all that Package Restore does: no more, no less.
If you are using Xamarin Studio, you can install NuGet by following the instructions here:
https://github.com/mrward/monodevelop-nuget-addin

Categories