How to create symbols for multi-project Nuget package? - c#

So I'm really struggling to figure this out.
I have a solution with a few projects, say, A, B, and C. A references and uses B and C (both project references). I wanted to create a Nuget package from A, and I did so, successfully, although I had to jump a few hoops, using things like this:
<ProjectReference Include="..." PrivateAssets="All" />
...
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" />
</ItemGroup>
</Target>
However, I would like to also debug through my Nuget package, so I found a few tricks to do so. One would be to copy the pdb into the nupkg, although that's not recommended. It supposedly works with this line in your csproj file. That adds the pdb to the nupkg, but only A.pdb is added.
Otherwise one could/should create a A.symbols.nupkg file. I tried doing that using tags like DebugSymbols, DebugType, EmbedSources, and IncludeSymbolsInPackage, but to no avail.
I also tried > dotnet pack A.csproj --include-symbols --include-source, and that generates a A.nupkg and a A.symbols.nupkg, but within the symbols, only A.pdb and not B.pdb and C.pdb.
So I guess my question is: How to create a nuget package from a multi-project solution which you can debug into (so including either pdb's or symbols/sources, not one, but from all referenced projects)?
TLDR: I've already seen a lot of potential solutions, but so far, none worked.
Nuget git issue thread
StackExchange thread
Some blog on GeekLearning.io
And many more...
Some of my last resorts may be: just adding all contents of B and C to A, so that there's only one project left, or creating a powershell script to manually add all the pdb's in the the A.symbols.nupkg. Of course, I'd like a more straightforward solution, if there is any.

The steps that should work:
Ensure that the references are indeed project references and not referencing the built DLLs directly.
Ensure that all of the PDBs are being copied to the output folder after building.
Use either of the methods you have tried (symbols package or hardcoding the inclusion of the .pdb extension).
If this is not working as expected, I would recommend providing additional details such as the csproj file for 'A' and any nuspecs tried.

Related

How to change SpecificVersion to false for NuGet packages?

I would like to change SpecificVersion to false for internally used NuGet packages.
I am using PackageReference and not packages.config, if that makes a difference.
While searching a solution for this topic, I have found those results
GitHub Nuget: https://github.com/NuGet/Home/issues/1380
Which states
In project.json (NuGet3) we are moving to a mode where NuGet does not touch the csproj file at all (where scenarios you are describing are partly the inspiration for the change).
I didn't manage to find the mentioned "project.json" file, where this could be possible? (Notice: the linked url is 7+ years old)
What can you do
You probably need to come up with a different way to define the
settings in your csproj file. Instead of putting them on the reference
that we know if going to change, we are going to use an msbuild
feature that lets you apply the settings to a reference.
You can go with the approach outlined by this SO post and use an
msbuild target.
I did try to read the linked StackOverflow post but frankly speaking I don't understand how this can be used for my scenario.
Also I found this:
Why is the NuGet Package Manager removing SpecificVersion False from the project file
Where it states
You would probably have to write a PowerShell script to fix up the references that are changed on updating.
But I seem to fail to understand where a powershell script should write the necessary changes to make SpecificVersion false?
As I mentioned at the beginning, I am talking about internally used NuGet packages, so if there is a solution revolving around defining something in the nuspec or in the csproj file that gets packed into a NuGet package this would also be a approach I can take.
Taking "whatever necessary steps" literally, you could explicitly reference the assemblies within the package instead of relying on PackageReference default behavior. This ties your csproj to the folder structure of the package, though.
It will also probably break anything the package does to the consumer's csproj with its own .props and .targets files.
I did not test this:
<!-- Define assets so that the package is basically ignored,
because we want to manually reference its assemblies. -->
<PackageReference Include="MyPackage.SomeWhere" PrivateAssets="all" IncludeAssets="none" GeneratePathProperty="true" />
<!-- Reference assemblies manually with the path property from above as base folder
Repeat for all assemblies in the package -->
<Reference Include="$(PkgMyPackage_SomeWhere)/lib/net461/SomeAssembly.dll" SpecificVersion="false" />

How NOT to debug a referenced dll?

I'm using a Release version of a dll which is referenced in other project. This dll has tampering detection when debugger is running (dll is also mine, I don't plan to do something illegal) which gives false positive results when debugging.
Is there an option in Visual Studio (2017-1019) not to "debug" referenced dll, but still be able to debug code which is being developed? "Debug" means that I don't want to Step-In in this specific dll, but just to get the data from the method the same way I could get it in Release.
E.g:
//Release dll
int Sum (int a, int b)
{
bool TamperingDetected = CheckForTampering();
if (TamperingDetected)
return 0;
else
return a + b;
}
//Other project
MessageBox.Show(dll.Sum(1, 1));
If I run this part of the code in Release I can easily get the correct value. No tampering will be detected, if someone would like to reverse engineer this method, it's very easy to do it in Release "legally". If I run in Debug, I will always get 0. As said before, I don't want to Step-In in Sum method, so no debugging should be done in this dll, but everything else should work like in Debug.
Just My Code option makes no difference.
The background is that one team creates this dll with tampering detection and the other is using it as a NuGet. Now they cannot debug their part of the code since our is detecting tampering and returning false values.
It would be too much for the other team to have the source code, since we then risk that they do something wrong during the build on that part of the code which they don't know.
One option would be to give them Debug and Release dll's and they could switch between them like explained here: https://stackoverflow.com/a/7284102, but then we lose the simplicity of sharing a NuGet and we still risk that Debug dll is copied instead of Release dll, thus losing tampering detection in the final product. NuGet is then always in Release.
Switching NuGets automatically with switching the Debug and Release configuration is not possible, or I still didn't find a way to it, but this would also be a good option. Only if some completely other project is used just to download both Debug and Release NuGets and then using the above mentioned answer, but I don't like it either.
Since there is a very small chance that it's possible to do what I first wanted, second best solution is to automatically switch between NuGets and this works with Choose-When-Otherwise. Condition in PackageReference or in ItemGroup doesn't work (at least not in VisualStudio, according to this). So I'll create two NuGets, one will be Release with tampering detection and the other will also be Release but without tampering detection ("-debug" suffix is added to this version). NuGet is then not installed through NuGet Manager but only the dllVersion is updated in .csproj:
<PropertyGroup>
<dllVersion>1.2.3</dllVersion>
</PropertyGroup>
<Choose>
<When Condition="'$(Configuration)'=='Debug'">
<ItemGroup>
<PackageReference Include="dllNuGet" Version=$(dllVersion)-debug/>
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<PackageReference Include="dllNuGet" Version=$(dllVersion)/>
</ItemGroup>
</Otherwise>
</Choose>
It seems that you want to decide whether to debug the dll according to a certain switch under Debug mode.
Obviously, the method you gave is problematic. After all, it is based on the current configuration of the project. Once the release mode is enabled, you cannot debug the code of your main project. Essentially, you still want to debug the code.
However, that disable Enable Just My Code option under Tools-->Options-->Debugging-->General will make you debug code under the Release mode. But it's not a perfect Debug mode and sometimes I cannot hit the breakpoint and cannot debug further, it is not recommended.
I have two solutions:
=====================================================
Tip One) Use Assembly dll directly rather than nuget
1) create a new Configuration called Debug_NotDLL which inheritances Debug mode.
Also, make two dlls of Debug and Release mode.
2) Add these on the csproj file:
<Reference Include="test" Condition="'$(Configuration)'=='Debug'">
<HintPath>..\test\bin\Debug\xxx\xxx.dll</HintPath>
</Reference>
<Reference Include="test" Condition="'$(Configuration)'=='Debug_NotDLL'">
<HintPath>..\test\bin\Release\xxx\xxx.dll</HintPath>
</Reference>
Then, you can switch Debug and Debug_NotDLL configuration to get what you want.
====================================================
Tip two) Use nuget
create new package, in this situation, I recommend that you should use net standard class library project.
I suggest you could create two nuget package of your dll.
You would better rename the dll of Release mode into xxx_Release.dll and xxx_Debug.dll for Debug mode.
To create a release nuget package, you should directly right-click on the lib project under Release mode--> click Pack. To rename the nuget package, you could use PackageId msbuild property to set its name to xxx_Release under csproj file. Check this document.
Note that if you create the nuget package under the local machine, you can always enter the nuget source code because there is a cache of the project source code on the current machine. It is a special siuation. So you should test the nuget package on another machine.
To create a debug nuget package, the dll and pdb file is not enough, you should also add the source files into the nuget package.
Then, pack such nuget package called xxx.Debug.x.x.x.nupkg under Debug mode. This is one link and two link about the steps of creating a debug nuget package.
When you finish it, you can install these two nuget packages, and add these under tha main project,
<ItemGroup>
<PackageReference Include="xxx.Debug" Version="1.0.0" Condition="'$(Configuration)'=='Debug'" />
<PackageReference Include="xxx.Release" Version="1.0.0" Condition="'$(Configuration)'=='Debug_NotDLL'" />
</ItemGroup>

Specifying files to add to a nuget package in .csproj file

I am creating a nuget package from some code, but also need to deploy some tools with the package.
In a .nuspec file, I can do this with the <files> element, and this all works well.
However when using a .nuspec file, the packageReferences from the csproj file aren't included, and I am seeing some problems when including them manually (with the <dependencies> element).
The package created also always seems to restore as a .net framework package, even though it is targetting .net, as in this question.
I am hoping that all these problems would go away if I moved to using the .csproj format for specifying the nuget package details, but having read the docs I can't find out how to do it.
Does anyone know how it is done?
If not, can anyone shed any light on created a .net framework / .net core nuget package from a .nuspec file, that restores to the correct target version and respects package dependencies?
It's not easy to find/discover, but NuGet's MSBuild tasks docs page has a section called "including content in a package", which tells you about the PackagePath metadata on MSBuild items, that NuGet uses to copy files into the package.
So, in your csproj, you could have something like this:
<ItemGroup>
<None Include="..\MyTool\Tool.exe" PackagePath="tools" Pack="true" />
</ItemGroup>
and then your package will contain tools\Tool.exe. The Pack="true" attribute is required for None elements.
You can use MSBuild's globbing to copy entire directories, if that's easier. Include="..\MyTool\*". My MSBuild skills are not so advanced, so I don't know how to glob ..\MyTool\**\*, which means all files in all subdirectories, while maintaining the correct directory layout in the PackagePath="???" metadata. So the best I can suggest is one glob per directory.

Get WIX to include references within a project

I'm completely new to WiX and setting up custom installers in general, so I apologise for the topic of the question!
I have a internal business application (a diary), which builds and works well, so I followed tutorials/official documentation as to adding the WiX project and referencing the Diary's csproj to it.
After then building and running this most basic version of a WiX installer, the output directory has a lone exe file, which crashes moments after loading with a File Not Found Exception.
My guess is that it has not built in either Crystal Report or NLog, both of which are referenced in my CSProj.
My question is this, how do I get WIX to include and build those project references to the output???
Any help is greatly appreciated!
/Antony
Unfortunately you will have to do some manual labor in order to get your projects right. I would take either of the two following approaches which require you to edit the .wixproj file:
Use HeatProject task. You will have to do this for all referenced projects and it will give you separate .wxs files for all of them. After this reference the component groups in those files in a feature of your WIX based setup.
<Target Name="BeforeBuild">
<HeatProject ToolPath="$(WixToolPath)" AutogenerateGuids="true" OutputFile="OutputFile.wxs" SuppressFragments="true" Project="ReferencedProject.csproj" ProjectOutputGroups="Binaries" />
</Target>
Use HeatDirectory task. Following will pick up everything in the bin folder of your project, including any binaries for the referenced projects, and give you a single .wxs containing UniqueComponentGroupName which can be included in any feature.
<Target Name="BeforeBuild">
<PropertyGroup>
<DefineConstants>BINFOLDER=PATH\TO\YourProject\bin\$(Configuration)</DefineConstants>
</PropertyGroup>
<HeatDirectory OutputFile="OutputFile.wxs" Directory="PATH\TO\YourProject\bin\$(Configuration)" KeepEmptyDirectories="true" DirectoryRefId="INSTALLFOLDER" ComponentGroupName="UniqueComponentGroupName" SuppressCom="true" SuppressFragments="true" SuppressRegistry="true" SuppressRootDirectory="true" GenerateGuidsNow="true" ToolPath="$(WixToolPath)" PreprocessorVariable="var.BINFOLDER" />
</Target>
Unlike the (now defunct) Setup Project project in older versions of Visual Studio, WiX does not do automatic reference detection. You'll have to add each referenced project to the WiX project manually, just as you did for the main project.

Creating one NuGet package from multiple projects in one solution

I have a solution that I'm working on that contains 4 class library projects (A, B, C, D). A and B could be considered the top level projects in the solution. Both A and B reference C, and D stands alone.
These four projects represent a group of services that I have made that handle an automated workflow. They are all closely related, and will only be used in one location (the service manager) so I don't want to split them into different solutions.
My problem is that I want to create a single NuGet package that will contain all 4 libraries, without having to build them all and gather up their DLLs manually. I know that I could technically achieve this by having either A or B reference the remaining projects, but that's not a true relationship and I feel it should be avoided.
I've done a lot of searching on this problem and I can't find a solution other than manually collecting the DLLs and building the package myself. Is there a way to achieve the result that I want using NuGet's features/abilities?
NOTE: In case the tags don't make it clear I'm currently using VS2010 with a TeamCity build server. In case it's relevant I'm also using Git through a Stash server.
EDIT: I just realized this might be important enough to mention. These projects do reference other NuGet packages that I will need to mark as dependencies.
If you have downloaded NuGet.exe
You can run: nuget pack Myproject.csproj -IncludeReferencedProjects and this should include all of your projects. Here's a note from the NuGet docs:
If the project references other projects, you can add the referenced projects as part of the package, or as dependencies with -IncludeReferencedProjects option. This is done recursively. For example, suppose you have project A.csproj, which references B.csproj and C.csproj, while B.csproj references D.csproj & E.csproj, C.csproj references F.csproj & G.csproj. Then, when you run:
nuget pack A.csproj -IncludeReferencedProjects
the generated package will contain files from projects B, C, D, E, F & G, in addition to files from project A.
If a referenced project has a corresponding nuspec file with the same name, then that referenced project is added as a dependency instead. Using the same example, suppose now there is file C.nuspec in the same directory as project file C.csproj. When you run:
nuget pack A.csproj -IncludeReferencedProjects
the generated package will contain files from projects B, D, E, in addition to files from project A, and the package has dependency on C.
Please also see the Command line reference.
You have to define your own nuspec manifest. You can list containing assemblies in files section:
<file src="A\bin\Release\A.dll" target="lib\net40" />
<file src="B\bin\Release\B.dll" target="lib\net40" />
...
For more details read NuSpec reference.
Then reference that nuspec file in NuPack build step instead of proj.
2020 UPDATE
I personally prefer to use the dotnetcommand wherever possible.
The solution that works for me is changing the default project reference in the main project <ProjectReference></ProjectReference> as below:
<ItemGroup>
<ProjectReference Include="..\{ProjectFolder}\{ProjectName}.csproj">
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
<IncludeAssets>{ProjectName}.dll</IncludeAssets>
</ProjectReference>
</ItemGroup>
This solution is confirmed to work when targeting netstandard2.0 and above.
Microsoft does not recommend multiple assemblies in one package. But if you really want to, then do this:
Open main project file and replace this:
<ItemGroup>
<ProjectReference Include="..\SecondClassLibrary\SecondClassLibrary.csproj" />
</ItemGroup>
on this:
<ItemGroup>
<ProjectReference Include="..\SecondClassLibrary\SecondClassLibrary.csproj" PrivateAssets="all" />
</ItemGroup>
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="BuildOnlySettings;ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" />
</ItemGroup>
</Target>
Source: https://github.com/NuGet/Home/issues/3891
this probably will solve this exact:
nuget.exe pack proj.csproj -IncludeReferencedProjects
you can see:
Create nuget package for a solution with multiple projects
If you have more than one project in VS and your Pack file is dependant on another project then both need to be packed. Pack the dependency first, then pack your project. When adding the package using NuGet Package manager make sure your source is not nuget.org but instead your testing folder. Unless you have uploaded both to Nuget.org.
How do I install a NuGet package .nupkg file locally?

Categories

Resources