.net core (csproj) global.json 'projects' equivalent - asp.net-core

With .net core (project.json) I used to switch between nuget packages and source code by adding the path to source code to the projects field in the global.json. After I did that it would add all the projects that it could find in that path that could replace the nuget packages I referenced.
I used this feature alot because I have my own nuget packages that I use, but I want to test the changes in my other project before I publish. But once I switched to Sdk 1.0.0/VS 2017/csproj .net core that feature seemed to disappear.
The alternative is just manually adding each project, switch the references manually (since they are broken up into project, nuget and sdk references), and then after switch it all back.
Any thoughts or advice would be great.
UPDATE:
Sounds like there is no equivalent in csproj (as expected), but there are msbuild workarounds for now (As of the initial VS 2017/.NET Core SDK 1.0.0 release)

Yes, I too had gotten used to this functionality and built my workflow around it. I am still looking for a solution but I'm currently playing with the idea of using conditional logic in the csproj files. Since it's now msbuild, you can do things like this:
<Choose>
<When Condition="Exists('..\..\..\MyProject')">
<ItemGroup>
<ProjectReference Include="..\..\..\MyProject\src\MyProject\MyProject.csproj" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<PackageReference Include="MyProject" Version="1.0.0" />
</ItemGroup>
</Otherwise>
</Choose>
This replaces the hard reference to a package with a conditional that uses a project reference if it can find the source code (in this case the directory), and a package reference if can't.
So by default you would be referencing the package, but if you want to debug one of your projects, you check it out in the location that the conditional checks, and add the project to your solution.
This way you only need to change your solution file (by adding the project) when you want to include source code, instead of rewiring all your project references.

For others that are interested in attempting to emulate with Global.json did, I worked around this for now using a couple powershell scripts and a custom json file that mimics it. Check out my answer here:
https://stackoverflow.com/a/43795974/5504245

Related

How does msbuild resolve assembly from a multi-framework nuget package?

I have a solution with a console app ConsoleApp-net461 that references a library ClassLibrary-net452.
Both projects reference a multi-framework nuget package NuGetPackage-net452-net461.
When I build, I end up with the nuget package's net461 dll in the output folder. At runtime, I am getting errors like:
System.TypeLoadException: Inheritance security rules violated by type: 'ClassA'.
Derived types must either match the security accessibility of the base type or be less accessible.
I am suspecting this is because my ClassLibrary-net452 ends up having a dependency on the nuget package dll with the net461 framework.
Is this normal behavior? What are the best ways to ensure the net452 dll is resolved from the nuget package? BindingRedirects don't seem to let you choose a target framework.
Not 100% sure this will work, but might be worth trying:
(Relies on using SDK csproj format, this link might work for packages.config, but I know less about the area.)
It looks like what you want is something like this. However the dotnet/SDK team haven't got round to implementing it yet.
The suggested work around is:
- Grab the dll path from your package reference
- Tell the package reference to not copy compile assets (dlls).
- Use the dll path to generate a similar path for a non-package reference that redirects to the Net452 version of the package.
Explanatory links here and here.
Summary is that your csproj should contain something like this:
<ItemGroup>
<PackageReference Include="*MyPackageName*" ExcludeAssets="Compile" GeneratePathProperty="true">
<Version>x.y.z</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Reference Include="*NameYouWantToGiveThisReference(suggest dll name)*">
<HintPath>$(Pkg*MyPackageName*)lib\net452\*DLLname*.dll</HintPath>
</Reference>
Everything surrounded by ** needs to be named according to whatever your projects are actually called.
The two MyPackageNames must match up (with the caveat that all "."s in the first one should be replaced with "_" in the second one).

PackageReference condition is ignored for old project format

I'm trying to centralize some of our project configurations by using the Directory.Builds.props/Directory.Build.targets files. Unfortunately we have a mixture of the old and new (sdk-style) project format. And not all of our projects can be converted to the new format due to some features not available in in the new format.
The issues that I'm running into is that I would like to have all our test projects automatically reference certain nuget packages. For projects in the new format, this works fine. However projects in the old format seem to ignore any conditions for the PackageReferences that I specify. It doesn't seem to matter what I use for the condition.
Here is an example of a very simple Directory.Build.Targets file:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="Moq" Version="4.12.0" Condition="False" />
</ItemGroup>
</Project>
In this case I should never see the Moq package included in any project.
For all the projects in the old format it is included regardless.
I have also tried to use the condition on:
ItemGroup itself
Choose/When block
Putting a condition on a property group or property works as expected on the other hand.
I haven't see any mention in the documentation that conditions are not supported for ItemGroup or PackageReference.
Is there something I'm missing?
Thanks
I don't believe non-SDK projects support PackageReference; I suspect they are being ignored regardless of any condition you specify. Check for a packages.config file in the same directory as the project file-- if I am right it is present and references the package(s) in question.
The Nuget docs currently state:
You can use a condition to control whether a package is included, where conditions can use any MSBuild variable or a variable defined in the targets or props file. However, at presently, only the TargetFramework variable is supported.
My experience was that the Condition="" was ignored by Visual Studio, but respected by the msbuild command line. However, in my testing the <Choose><When Condition=""> block did seem to be respected by both tools.

Is it possible to utilize OctoPack with the new PackageReference NuGet format?

We recently upgraded our assemblies to use the PackageReference format instead of the packages.config for our NuGet dependencies. One of the packages, OctoPack, stopped working after doing this. Is there any way to get OctoPack to work while still using the PackageReference format?
Yes, but you have to use Octo.exe pack (same process as for ASP.NET Core applications)
Yes. Recent Nuget versions will autogenerate imports for the MSBuild tasks in the obj/xxx.csproj.nuget.g.targets file.
If it doesn't...
When using packages.config, Nuget will add something like this to your csproj.
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\OctoPack.3.6.4\build\OctoPack.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\OctoPack.3.6.4\build\OctoPack.targets'))" />
and
<Import Project="..\packages\OctoPack.3.6.4\build\OctoPack.targets" Condition="Exists('..\packages\OctoPack.3.6.4\build\OctoPack.targets')" />
The EnsureNuGetPackageBuildImports target is probably already there, even before.
If you add this to your csproj (or keep it, if you converted from packages.config) it will sort of still work. The problem is that packages are not stored in "..\packages".
This is easily fixed by replacing e.g "..\packages\OctoPack.3.6.4" with "$(NuGetPackageRoot)\octopack\3.6.4". Of course you need the PackageReference to octopack. It will be enough to make a restore operation put the package in $(NuGetPackageRoot).
YMMV, but it works for me, both locally and in CI (TeamCity)

How ad-hoc aliasing of NuGet-referenced assemblies work?

We had issues in our build with some of our dependencies forcing really old version of a library we were using ourselves at a newer version. This got slightly worse with transitioning towards the new style of project files that no longer explicitly mention DLL resources brought in by NuGet packages, because we lost the ability to mark such assemblies by aliases.
Now, I found out a solution of basically the same problem at NuGet's GitHub. I adapted it for our needs in the following way:
<Target Name="AliasLog4Net" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'log4net'">
<Aliases>l4n</Aliases>
</ReferencePath>
</ItemGroup>
</Target>
It works magically. I want to know why though.
I can't find documentation for ReferencePath. Specifically, I would love to know what can I test for in the Condition attribute, apart from %(FileName)?
How can I log this logic? Is there a way to write something out for every ad-hoc application of the alias in this way?

Include additional files in build using MSBuild

In the past we have used a combination of TeamCity and MsDeploy to deploy our projects. We've recently moved into using Octopus deploy, and TeamCity purely for the Build. This meant changing the build process in TeamCity and removing any references to MsDeploy.
In the past we've used confiiguration such as the below in our project file which included additional files and directories:
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<Target Name="CustomCollectFiles" BeforeTargets="BeforeBuild">
<ItemGroup>
<UCommerceAssemblies Include="$(MSBuildThisFileDirectory)..\..\Resources\UCommerce\ucommerce\*" />
<FilesForPackagingFromProject Include="%(UCommerceAssemblies.Identity)">
<DestinationRelativePath>bin\uCommerce\%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
However this now doesnt seem to get invoked whatsoever. It appears (to me anyhow) that these pipelines were created for use with Publishing from Visual Studio, or using MSDeploy, however we need to just include these files in the directory either before or after the build has taken place. There seems to be tons of references across the web about doing this, however they all refer to using MSDeploy.
Can anyone shed any light on how I can include additional files/directories in the build without using MSDeploy?
Thanks for your time in advance
dotdev
As you are using Octopus for deployment you only need to include additional files (reference assemblies, etc.) into code package sent to Octopus.
To do this one needs to use OctoPack for project packaging. Then add .nuspec file into the project, for example this line in .nuspec will add all files from some different location into the .nupkg package under "bin\additional" and will be deployed correctly by octopus.
 
Nuspec docs
Similar solution is discuses here.