Copy all of the required dlls to folder - c#

I have a MonoAndroid10 project and it has a lot of dependencies(NuGet packages too). I would like to be able to copy all of the DLL dependencies to the output folder.
Normally in a .Net Standard 2.0 project the following
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
would make that possible. But in the MonoAndroid project, nothing happens.
If what I posted above doesn't work for a MonoAndroid project, how could I copy everything that I need in some folder, preferably in a post-build action?
I'm trying to do this because after copying all of the required DLLs in one folder I can merge them together with ILRepack.

I've come across this today, solved by adding
<CopyNuGetImplementations>true</CopyNuGetImplementations>
to android project .csproj file (under the desired PropertyGroup section).
Note: there is no need to set CopyLocalLockFileAssemblies to ture neither in android project nor in any of the dependencies.

Related

Debugging .net core 3.1 library code published on github private nuget repository is broken?

In the last few days I've battled against an issue with debugging nuget packages that I still wasn't able to solve the way I want.
All this has been tested with visual studio 2022, updated to the latest version available.
We have a .NET 3.1 library published on github (private package).
We consume such library in many .NET 3.1 WebAPI backends that we develop.
We need to be able to debug such library.
GitHUB doesn't seem to support symbol servers at the moment, so I thought we had these 2 possibilities:
embed the pdb in the dll: this seemed the most straightforward solution and was the first I tried. By doing so on the core library, when we import that in a .NET webapi project and inspect the "modules" window, we can see that symbols for the dll have been loaded correctly; symbol file column reads: "OurLibrary.dll (embedded)"
include the pdb in the nupkg and then add a piece of code (found here https://github.com/dotnet/sdk/issues/1458#issuecomment-420456386) in the .csproj of consuming .NET webapi project that ensures that the dll pdb, contained in the nuget package, is copied to the bin folder. Also in this case, inspecting the modules window, it looks that the symbols have been loaded from metadata (which I guess is the pdb file itself).
STILL, in both cases, if the project is running, when I try to set a breakpoint in the Startup.cs file of the consuming WebAPI project, and step into an IServiceCollection extension method, which is defined in the library, I'm able to do so, but many symbols used in that file (referring to PUBLIC types defined in the library, or from the framework itself) are white, and I can't explore them by doing "go to definintion".
Instead, if I try to peek at the source code of the extension method mentioned before, when the project is not running, I'm able to peek at code by doing "go to definition" without issues. So, I set a breakpoint..
Then, when I launch the project:
you can see that it's a different "SessionFactory" file, and all the symbols have become white. If I try to go back to the original file (with all the types correctly resolved by intellisense), and set a breakpoint inside it, visual studio automatically switches to the other file (with "broken" intellisense) and sets the breakpoint there, which is very frustrating..
At the moment the only solution that really behaves the way I want requires me to remove the library nuget package from the project and reference the library as an "Existing project" inside the solution. By doing so everything works perfectly (of course, now library source code is part of the project) but of course seems wrong / time consuming / error prone.
Somebody is able to shed some light on what is going on? Thanks
EDIT: FURTHER DETAILS FOR USER #Transformer
I tried your suggestion to include the supplied code in .csproj of both the library and the consuming application:
By doing so in the library .csproj, it contains these settings related to PDB generation, in a property group:
<EmbedAllSources>true</EmbedAllSources>
<DebugSymbols>true</DebugSymbols>
<DebugType>portable</DebugType>
<AllowedReferenceRelatedFileExtensions>.pdb</AllowedReferenceRelatedFileExtensions>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
It also includes this, outside of the property group:
<Target Name="AddReferenceRelatedPathsToCopyLocal" AfterTargets="ResolveAssemblyReferences">
<ItemGroup>
<ReferenceCopyLocalPaths Include="#(_ReferenceRelatedPaths)" />
</ItemGroup>
</Target>
Unfortunately, by doing so, the pdb doesn't seem to be included in the nupkg. Instead, if I add the following (a setting I've already found in the past):
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
then the pdb is included in nupkg, but still, I experience the same debugging problem in the consuming library, even if I add the code you supplied to the consuming library as well...any other idea?
Thanks a lot for your kind help
The issue is probably because the nuget packages are built with Release configuration which optimizes out the symbols. One way you can debug the package itself is if you open the project (from which you deploy the nuget), build it with Debug configuration, then copy the dll and pdb file into the bin\Debug\ folder of your consumer app. Then start the consumer app with no debugger attached, after it starts, you can attach your nuget project to that process, and your nuget code breakpoints will be hit.
Hello, from what I can see - that's because the embedded files are not copied to local, please try this in your cs.proj file and paste your comments
<PropertyGroup>
<AllowedReferenceRelatedFileExtensions>.pdb</AllowedReferenceRelatedFileExtensions>
</PropertyGroup>
<Target Name="AddReferenceRelatedPathsToCopyLocal" AfterTargets="ResolveAssemblyReferences">
<ItemGroup>
<ReferenceCopyLocalPaths Include="#(_ReferenceRelatedPaths)" />
</ItemGroup>
</Target>
Question from Carlo Arnaboldi : Where does this go?
Update: These are settings that go into the .proj file.
You you to do this in your nuget pacakge && your consuming project to see the pdb for symbol debugging
Also delete you old pdbs - exist visual studio/code and then delete the bin and obj folders

Custom Nuget package shows missing dependency error

I have two class libraries in a single solution (.NET Core). One of them (cl1) is a main library and it depends on another library (cl2). I have added a .nuspec file with the required metadata only (no dependencies, no files) for the cl1 project in the project folder (same location of .csproj file) and I have set GeneratePackageOnBuild propery to true.
Whenever I am building the class library (cl1), the .nupkg is created automatically in the debug/release folder.
When I check the generated .nupkg file, I am see two strange things:
The generated .nuspec file is different than what I have added in the project folder
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the DLL for cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this package in another solution, I am getting the error No packages exist with this id in source(s) for the cl2.
I have surfed in internet, but was not able to find a proper solution for the above error.
And I have added a .nuspec file [...] in the project folder(same location of .csproj file)
You have to specify the path to your own NuSpec file in the .csproj using the NuspecFile tag, otherwise it will be ignored and the package will be created with the metadata from the .csproj file instead, see reference. You need to use either a relative or an absolute path to the file, for example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NuspecFile>cl1.nuspec</NuspecFile>
</PropertyGroup>
</Project>
The generated .nuspec file is different than what I have added in the project folder
As already stated, your NuSpec file is probably not included. However, even if it is, there can be differences, because some information, e.g. source file locations are unnecessary and the target locations are in most cases given by the internal package file structure itself, so it is not there because it is redundant.
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the dll for the cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this nupkg in other solution, I am getting error " No packages exist with this id in source(s)" for the cl2.
Dependencies are meant for packages. So when NuGet restores the package it searches for other packages that this package depends on, here cl2, but there is none, hence the error. When packing a project, referenced projects are not included in the package. That is an open issue and there are workarounds that you can try.
The most reliable, but inconvenient solutions are to avoid the issue at all.
Only use a single project, everything will be included in the package
Pack each project on its own and use the generated package instead of the referenced project

New Microsoft.NET.Sdk projects build output files in subdirectories. How to change it back?

Recently upgraded an old version of an open source project. The new project file is is the newer SDK project type, and i'm having a problem with something that should be super simple.
When building the old project, the output files were copied directly into the folder I specified in the project properties, build tab, "Output Path" field. Which I specified as either bin\x64\Debug or bin\x64\Release depending on the Configuration.
With this new project format, however, the actual DLLs are output into bin\x64\Debug\net461 instead. If I change the target framework, the output file is in a different location. bin\x64\Debug\net462 for instance.
I need it to never copy to the framework subdirectory. It royally screws up the nmake build scripts we use. How do I fix this?
What's more, the build directory is FULL of useless dependency DLLs copied from God knows where. I don't want anything in the output directory except the output.
How do I go about making this new project format work like the old one?
Add it to your csproj
<PropertyGroup>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
AppendTargetFrameworkToOutputPath controls framework name
AppendRuntimeIdentifierToOutputPath controls x64/x86

Assembly Version of [MyMvcProject].Views.dll

When compiling a .net core Web MVC project VS / Compiler creates an assembly called [MyMvcProject].Views.dll with an AssemblyFileVersion of 0.0.0.0.
Is it possible to change the Version for this generated file (and maybe also change other Assembly properties?
UPDATE
I've added Manually AssemblyInfo.cs and edited my csproj with <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
With this constellation it seems that the data is not propagated to [MyMvcProject].Views.dll
I would like to stick with AssemblyInfo.cs because I share the this file over several projects. (Unless there's another solution to have consistent Assembly Versions over many projects).
Still would like to give [MyMvcProject].Views.dll a specific version.
Any idea?
I would like to stick with AssemblyInfo.cs because I share the this file over several projects. (Unless there's another solution to have consistent Assembly Versions over many projects).
You can use a Directory.Build.props file to achieve this. This file is recognised automatically by the dotnet build system (it's part of MSBuild) and will apply to all projects within the same directory or lower. If you want to apply a Version property for an entire solution, for example, you can drop a Directory.Build.props file next to the .sln file, with the following contents:
<Project>
<PropertyGroup>
<FileVersion>1.0.0.404</FileVersion>
</PropertyGroup>
</Project>
As you might expect, this AssemblyFileVersion property will also apply to your [MyMvcProject].Views.dll assembly.
Here's a detailed list of the AssemblyInfo properties you can specify when using this approach: AssemblyInfo properties.
Addition by #gsharp:
If there's also a version set in the project properties, then the project version will "win" over the Directory.Build.props version.
Go to your project "Properties" and on "Package" tab you have most of the properties that are in AssemblyInfo in classic .Net Framework projects like "Assembly version" and "Assembly file version".
Also you could try to use this command to build your project: dotnet publish /p:Version=1.2.3

System.Data.SQLite from NuGet, interop dll not copied to output directory

I installed System.Data.SQLite Core (x86/x64) from NuGet. It built without warnings but threw System.DllNotFoundException regarding SQLite.Interop.dll. I rigged my projects to copy the SQLite.Interop.dll from under the NuGet package's directory to the output directory, and now it runs without the exception.
Why didn't the NuGet package configure my projects to put the appropriate interop dll in the output directory? It seems like it should be able to do that.
I'm new to interop and I inherited this codebase, which previously referenced System.Data.SQLite.dll directly by path. I switched to NuGet to get rid of warnings about a mismatch between the processor architecture of the project vs System.Data.SQLite. I'm trying to build all projects as AnyCPU.
Copy this to your project file:
<PropertyGroup>
<ContentSQLiteInteropFiles>true</ContentSQLiteInteropFiles>
<CopySQLiteInteropFiles>false</CopySQLiteInteropFiles>
<CleanSQLiteInteropFiles>false</CleanSQLiteInteropFiles>
<CollectSQLiteInteropFiles>false</CollectSQLiteInteropFiles>
</PropertyGroup>
Source: SQLite.Interop.dll files does not copy to project output path when required by referenced project
In my case, the problem was the fact that I was using SQLite inside a class library project that was then used by another WPF (gui type) project.
Solved the SQL.Interop.dll not getting copied to output directory, by using the following Post-Build command, inside Project Properties -> Build Events:
xcopy "$(SolutionDir)packages\System.Data.SQLite.Core.1.0.101.0\build\net451\x86\SQLite.Interop.dll" "$(OutputDir)" /y /f
/y overwrites
/f displays actual filenames being copied
I thought this was happening to, as I was copying the files from my output folder to another location when I deployed them. I missed the fact that the interop files WERE being copied, but they are copied to x64 and x86 folders within your output folder.
If you run msbuild in debug on the project, you can look for references to the CopySQLiteInteropFiles target to ensure that it is running.
With the System.Data.SQLite.Core NuGet package version 1.0.104, I had the same problem as #Eternal21 and #Patrick. That is, project A references SQLite and project B references A where SQlite.Interop.dll is not copied into the output directory of B.
I found a solution that solves the trouble in project A rather than B which is a more robust solution since it fixes the problem once for all future projects refering to A. The .targets file of the NuGet package contains the following section:
<ItemGroup Condition="'$(ContentSQLiteInteropFiles)' != '' And
'$(ContentSQLiteInteropFiles)' != 'false' And
'#(SQLiteInteropFiles)' != ''">
<Content Include="#(SQLiteInteropFiles)">
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
This section adds SQLite.Interop.dll as a reference that has to be copied to project A's output and also to the output of refering projects (like B). But the MSBuild property ContentSQLiteInteropFiles is undefined by default (I don't know why) disabling the reference by the first condition. To enable it, I added the following line to a PropertyGroup element of projects A's .csproj file:
<ContentSQLiteInteropFiles>true</ContentSQLiteInteropFiles>
Please note that this line must prececde the Import element for the .targets file of the NuGet package.
In my case the SQL.Interop.dll was not copied by Nuget in any way, manually put the right version of the dll in the x86 and x64 folder solved the issue.
If you've installed Sqlite from Nuget, you can find the SQL.Interop.dll in this folder (for .NET 4.0)
PROJECT_FOLDER\packages\System.Data.SQLite.Core.1.0.*.*\build\net40
In my case the myProject.csproj file did not have the System.Data.SQLite.Core.targets defined. I added the following line and both x64 and x86 versions of SQLite.Interop.dll are now copied for all build targets.
<Import Project="..\packages\System.Data.SQLite.Core.1.0.98.1\build\net45\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.98.1\build\net45\System.Data.SQLite.Core.targets')" />
I'm not sure what will happen when the NuGet package for System.Data.SQLite.Core gets updated and if the package path will need to be manually altered.
in my case using NuGet for installing SQLite and still I need to add manually SQliteinterop.dll as a Resource. Then I build muy proyect and when I publish it works fine. (Working with x86 configuration)
I added
<PropertyGroup>
<ContentSQLiteInteropFiles>false</ContentSQLiteInteropFiles>
<CopySQLiteInteropFiles>false</CopySQLiteInteropFiles>
<CleanSQLiteInteropFiles>false</CleanSQLiteInteropFiles>
<CollectSQLiteInteropFiles>false</CollectSQLiteInteropFiles>
</PropertyGroup>
In the csproj of the project that references the nuget package. This part needs to be above the 'Import' of the 'System.Data.SQLite.Core.targets'.
Then, added the following to the csproj-file, so that the x64-version of the 'SQLite.Interop.dll' is placed in the bin folder.
<ItemGroup>
<Content Include="..\packages\System.Data.SQLite.Core.1.0.111.0\build\net46\x64\SQLite.Interop.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
Although this statement needs to be changed when the nuget package is updated.
None of the answers above seemed to work for me, perhaps because I am on VS2015, but that struck me as a good reason to add my own solution to this problem.
My specific situation is the same as #Eternal21 - I have a WPF UI consuming a client library which is the one that has SQLite added to it via nuget. And, yes, the problem was that the Interop.dll was not copied to the startup application (i.e the WPF UI that does not have SQLite installed).
The solution of simply adding SQLite to the WPF project using nuget is a quick and easy fix if you are in a hurry.
My slightly heavy-handed solution uses XCOPY but does have the advantage of copying both the x86 and the x64 directories and also copes with Debug and Release builds. Its downside is that it contains hard-coded project names. I can see how you could use a macro to get rid of the first one but I couldn't easily see how to get rid of the second, so you would have to change it manually if the project name changed (but this is fairly rare).
My solution is to use these XCOPY commands in the post-build of the startup project:
xcopy $(SolutionDir)DALProject\bin\$(ConfigurationName)\x64\SQLite.Interop.dll $(SolutionDir)WPFProject\bin\$(ConfigurationName)\x64\*.* /C /F /S /E /Y
xcopy $(SolutionDir)DALProject\bin\$(ConfigurationName)\x86\SQLite.Interop.dll $(SolutionDir)WPFProject\bin\$(ConfigurationName)\x86\*.* /C /F /S /E /Y
/C - Continues copying even if error (maybe this is not needed).
/F - Displays full paths of files being copied (could be omitted to clean-up build output).
/S - Copies subdirectories (which was the only way I could get it to create the /x86 and /x64 folders).
/E - Copies directories and subdirectories (maybe duplicates /S).
/Y - Suppresses prompt if destination file already exists.
I set this to run only on successful build and it works a treat for me. Hope it helps someone.
I have a DLL project that uses the SQLite package from nuget but a test project for it would always raise the DLL not found exception.
The simplest solution I found was to add the SQLite nuget package to the test project too.

Categories