I have 2 Projects Libraries in my Example Solution > Visual Studio.
I directly reference one of them in the other. When I now publish my nuget package, on the dependency overview I get that my directly referenced nuget is >= 1.0.0.0, when I do it via nuget the reference means no direct reference because same solution I get the right version number under >= dependency overview. I won't change the default dependency behavior lowest.
What I've tried is to update my nuspec file with dependencies / references / files elements none of them worked for me.
I would like to see the same version of the given nuget in the directly referenced nuget as dependency.
From the last sentence in you question and your emphasis on direct references makes me feel I know what you are after:
NuGet defines the -IncludeReferencedProjects option to instruct nuget.exe how it should treat referenced projects, either as dependencies or as part of the package:
If a referenced project has a corresponding .nuspec file that has the same name as the project, then that referenced project is added as an explicit NuGet dependency.
Otherwise, the referenced project is added as part of the package.
My guess is that you are after the former.
Let us simplify the problem to its most basic form: Let's say you have a solution where LibraryA references LibraryB directly as a project reference. When you build the solution, the assembly output from LibraryA is copied to LibraryB
~/
│ Solution.sln
├───LibraryA
│ │ ClassA.cs
│ │ LibraryA.csproj
│ │ LibraryA.nuspec
│ ├───bin
│ │ ├───Debug
│ │ │ LibraryA.dll
│ │ │ LibraryA.pdb
│ │ └───Release
│ └───Properties
│ AssemblyInfo.cs
└───LibraryB
│ ClassB.cs
│ LibraryB.csproj
│ LibraryB.nuspec
├───bin
│ ├───Debug
│ │ LibraryA.dll
│ │ LibraryA.pdb
│ │ LibraryB.dll
│ │ LibraryB.pdb
│ └───Release
└───Properties
AssemblyInfo.cs
Setup
For illustration purposes I will use the pattern [assembly: AssemblyVersion("1.0.*")] in my AssemblyInfo.cs files and will do a couple of separate builds on each project to ensure my assemblies get some different interesting versions.
Make sure that each project contains a .nuspec file with the same name as the project. This is specially important for project LibraryA, as it is the project being referenced by LibraryB. I'll do it for both as good practice. Let us use a basic template for now:
In the .nuspec below, the replacement tokens $id$ and $version$ will get their values inferred when you run nuget.exe against a .csproj file that has been built.
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$version$</version>
<authors>The author... (**mandatory element**)</authors>
<description>Your description... (**mandatory element**)</description>
</metadata>
</package>
Use nuget pack -IncludeReferencedProjects
Now, I am going to run nuget.exe in the command line from the solution directory (~) on project LibraryB:
PS> nuget pack .\LibraryB\LibraryB.csproj -IncludeReferencedProjects -Verbosity detailed
Attempting to build package from 'LibraryB.csproj'.
Packing files from '~\LibraryB\bin\Debug'.
Using 'LibraryB.nuspec' for metadata.
Add file '~\LibraryB\bin\Debug\LibraryB.dll' to package as 'lib\net451\LibraryB.dll'
Id: LibraryB
Version: 1.0.5993.6096
Authors: The author... (**mandatory element**)
Description: Your description... (**mandatory element**)
Dependencies: LibraryA (= 1.0.5993.7310)
Added file 'lib\net451\LibraryB.dll'.
Successfully created package '~\LibraryB.1.0.5993.6096.nupkg'.
PS>
Generated packages
The above command will create a NuGet package LibraryB.1.0.5993.6096.nupkg with a explicit NuGet dependency to LibraryA.1.0.5993.7310.nupkg.
When you inspect the contents of LibraryB.1.0.5993.6096.nupkg, you will see that the .nuspec generated by nuget.exe will have replaced all the $version$ replacement tokens to that of the actual versions used.
One last thing, the command above will create the NuGet package only for LibraryB but obviously you can create the one for LibraryA just by running it again targeting LibraryA.csproj
I hope this is what you were after, or that at least sheds some light to what you can do.
Related
I have a solution with a sample .NET Core microservice that has dependencies on two projects (one of which is dependent on another and dependencies are set up using Git submodules). It builds fine, but when I try to debug the microservice, I get the error:
An unhandled exception of type 'System.IO.FileNotFoundException'
occurred in Unknown Module. Could not load file or assembly
'CommonLibrary, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null'. The system cannot find the file specified.
I checked the bin\Debug\net6.0 folder and the CommonLibrary.dll file is there along with all other dependencies.
I made a copy of the solution, included both dependency projects without using Git submodules, and it worked fine. I compared the Debug\net6.0 folders in both solutions and they contain the same files (only the timestamps of the assemblies from the three projects are different). Any idea what could be going on here?
Here are some details (with project names redacted for clarity). The three .NET 6 projects include:
CommonLibrary (has no dependencies on other projects)
CommonControllerLibrary (depends on CommonLibrary)
SampleMicroservice (depends on both CommonLibrary and CommonControllerLibrary)
I created 3 repos in GitLab and linked project dependencies via the Git submodules. On the file system, the directory structure for the SampleMicroservice project looks like this:
…
└── sample-microservice
│
├── common-library
│ └── CommonLibrary
│ ├── CommonLibrary.csproj
│ …
├── common-controller-library
│ ├── common-library
│ │ └── CommonLibrary
│ │ ├── CommonLibrary.csproj
│ │ …
│ └── CommonControllerLibrary
│ ├── CommonControllerLibrary.csproj
│ …
├── SampleMicroservice.sln
│
├── SampleMicroservice
│ ├── SampleMicroservice.csproj
│ ├── Bin
│ │ └── Debug
│ │ └── net6.0
… …
The CommonLibrary project is referenced twice in the solution, so in the Solution Explorer, it looks like this (I use solution folders to isolate the dependencies in the submodules from the main project):
Solution 'SampleMicroservice' (4 of 4 projects)
│
├── Submodules (folder)
│ ├── CommonLibrary (folder)
│ │ └── CommonLibrary (project)
│ │
│ └── CommonControllerLibrary (folder)
│ ├── CommonLibrary (project)
│ └── CommonControllerLibrary (project)
│
└── SampleMicroservice (project)
The SampleMicroservice project is dependent on the CommonLibrary project in the CommonLibrary solution folder and the CommonControllerLibrary in the CommonControllerLibrary solution folder.
I'm not sure if I messed up the projects when I set up the submodules, but I can't think of any other way to configure it. The main goal is to reuse projects across GitLab repos considering that some of the shared projects have nested dependencies (shared project B depends on shared project A, and project C depends on both A and B). TIA
i'm trying to use MediatR in my ASP.NET 6 application, but i need to write builder.Services.AddMediatR(typeof(ExampleCommandHandler).Assembly); for every handler. I was looking for a way to add just in single line like builder.Services.AddMediatR(typeof(Startup).Assembly);. But all the examples i saw throw the exception with message Register your handlers with the container.
I think this problem is because my Commands and my Command Handlers are in different class library, example of my folder structure:
.
└── MyApp/
└── src/
├── MyApp.API/
│ ├── Startup.cs
│ └── ...
├── MyApp.ClassLibrary1/
│ ├── Handlers/
│ │ └── ExampleCommandHandler.cs
│ └── ...
└── MyApp.ClassLibrary2/
├── Commands/
│ └── ExampleCommand.cs
└── ...
Can someone help me?
try builder.Services.AddMediatR(AppDomain.CurrentDomain.GetAssemblies());
Problem Statement:
Optimal way of importing dependent DLLs in PowerShell script.
Explanation:
I have a DLL, namely a.dll which has almost 10 dependencies on b.dll, c.dll,.... When I import the a.dll from the Nuget Package A in a PowerShell script then as the Dependent DLLs are not present in the same Directory it throws an error. I only have the DLLs in Nuget packages. The packages as usual will be in the
├── Nuget-A
│ ├── 1.0
| | |── a.dll
│
├── Nuget-B
│ ├── 2.0
| | |── b.dll
In the PoweShell script I will import the a.dll,
Import-Module "Nuget-A/1.0/a.dll"
This throws me an error so I do the following
Import-Module "Nuget-B/2.0/b.dll"
Import-Module "Nuget-A/1.0/a.dll"
In the same way I have to do for the 10 DLLs.
What is the optimal way of handling the scenario? I am open to any other approaches too
I'm not terribly experienced with PowerShell, but I expect that if all the assemblies were in the same directory, then when you import a.dll, it will automatically find the references, such as b.dll. That's how the .NET runtime loads assemblies, more or less, regardless of PowerShell, a console app, web app, and so on.
Therefore, instead of creating a package A that contains only a.dll and a dependency on package B, have package A not have any dependencies, and contain all 10 dlls in it.
There are a few ways to achieve that. One is to re-use csproj's PackAsTool. It publishes the project (using the equivalent of dotnet publish), and then packs everything in the publish folder. Since it's designed to pack console apps so that they can later be installed via dotnet tool install, you might have to do some hackery to get it to work. Another way is to run dotnet publish, then get nuget.exe from nuget.org/downloads, and cd to the publish directory run nuget.exe spec to create a template .nuspec file, edit that nuspec with all the metadata you want, then run nuget.exe pack. It will pack all the files in the directory into a nupkg. There are other ways too, for example try nugetizer, a community created tool, but this question is about how to solve referenced assembly loading, not how to pack, so I'll leave it at that. My point is that when you have a package that contains a PowerShell cmdlet, you shouldn't need to worry about loading all the dependencies in the powershell script/environvment using the package, so make sure the package is "self contained". It shifts the burden from consuming time to packing time, but at packing time all the dependencies are known, so it's an easier problem to solve.
Here is the sample project structure:
{ ProjectA }
{ packages } <-- packages are created here
{ ProjectA }
- ProjectA.csproj <-- references ProjectB and C.
- packages.config
- ProjectA.sln <-- contains all projects: A, B and C.
{ ProjectB }
- ProjectB.csproj
- packages.config
{ ProjectC }
- ProjectC.csproj
- packages.config
*{ packages} <-- *When I manually paste packages here. So one level above ProjectB.csproj file, then ProjectB compiles.
ProjectA solution has all three projects: A, B and C. ProjectA reference ProjectB and ProjectC.
When I compile ProjectA (projects B and C are compiled as well), all nuget packages are downloaded into {packages} folder on the same level as solution file. The problem is that ProjectB is not compiling. Yes... only ProejctB. I'm not even gonna investigate why only one project compiles although their configuration is exactly the same. Anyway...
In both ProjectB and C, when I expand References dlls from nuget are seen as they were missing (with the yellow rectangle). Somehow ProjectC compiles anyway, but ProjectB doesn't. The errors says it can't find the reference which is clearly in the packages folder.
My question is, how do I program/configure that sentance (psuedo code):
"Dear ProejctB, Please look for the references in the package folder generated on the same level as the solution file. The solution file, which is trying to compile you right now. Thank you"
PS. So technically, the path to the dll (reference) will be kinda dynamic. It will change depending on which solution file is opening/compiling the project. Is it possible?
The easiest way to fix it is by setting HintPath to:
<HintPath>$(SolutionDir)\packages\...
in .csproj files of ProjectB and ProjectC. It literally means: "look for the references in the package folder generated on the same level as the solution file. The solution file, which is trying to compile you right now"
This problem was reported multiple times. I believe it was fixed here. There is also NuGetReferenceHintPathRewrite, but I didn't test it.
Since packages.config is slowly becoming deprecated, you could migrate your projects from packages.config to ProjectReference, where the NuGet packages are specified inside the csproj file and a shared global location is used to store the packages (and there aren't any references with HintPath that would need changing).
In VS 2017 version 15.7, there will be an option to migrate in the context menu of the references node (already available in the preview):
PackageReference is already supported in VS 2017 since around 15.1 or 15.2, only the migration tool is in preview.
For new projects, VS 2017 (current version!) you can already select the default package reference style and allow for choosing it for new projects:
Nuget 3.x has packages.config concept and in this package name & version are mentioned at 2 place (In package.config and in .csproj file)
Reference in package config should be like this:
<package id="NewtonsoftJson" version="9.0.1" targetFramework="net46" />
Hint path in csproj should be like this:
<HintPath>..\packages\NewtonsoftJson.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
Here "..\packages" says go one level up(means at solution level) and look for "packages" folder.
You should verify that hint path is exists or not. and Package version should be same (9.0.1) in both the files(package.config and .csproj)
As your Porject C compiles successful, it seems some issue in the packages which is used by only ProjectB.
If you are still facing issue, please provide below detail for further analysis.
"package config"
"ProjectB.csproj"
msbuild compilation log, to know that in which package you
are facing issue.
I have a hobby project that is written in C# using MonoDevelop. I've been trying for some time now to get my head around linux packaging, but I keep coming away feeling frustrated and overwhelmed.
My program consists of:
A library project ("Generator") that does stuff with the data created by my program.
An ui ("Interface") project using Gtk#. This project has two subdirectories: "glade" (xml files that gtk uses to build widgets) and "book" (data used by my program).
A utility project ("Utils") used by both the library and interface projects.
A main project ("MyProgramName") that just starts the interface.
What (I think) I want to do is really very simple (I think):
Compile my application
Copy the .exe and .dll files (to /usr/local/bin?)
Copy the "book" directory (to /usr/local/bin?)
Copy the "glade" directory (to /usr/local/bin?)
Oh, and I want to do this as a .deb package. I think if I can get the tarball working, a .deb package shouldn't be too much trouble, but that's what I want to do eventually.
I'm still not really sure how to do this. I've used MonoDevelop to create a Tarball. When I install the tarball (using ./configure, make, sudo checkinstall), it seems to install the executable code (and even create a command to run the program), but forgets about the "book" and "glade" directories.
How would I go about doing this? Sorry if this is a basic/broad question. I've been googling around about this, and I can't seem to find anything that doesn't assume I know the basics of packaging (even if it claims it doesn't assume this).
Debian packages are like tar files - they contain a copy of the file system. To create a Debian package...
Install the tarball in a build directory.
Add a DEBIAN directory with the control files. I found this article helpful.
Create the package with dpkg --build.
I would start by learning GNU's autotools: autoconf and automake. They make it very easy to install the program in a build directory. You mentioned ./configure. So I assume ythis project already has some of the structure. From the description, it sounds like the project might need...
Entries in configure.in for files in "book" and "glade".
Makefile.am files in "book" and "glade".
Putting it all together, the following commands result in a package file named project.deb.
# ./configure --prefix build/usr
# make && make install
# dpkg --build build project.deb
Perhaps this blog post may be of help to you.
It thoroughly describes the structure of a deb package, which is as follows:
<YOUR PACKAGE NAME>
└── deb
├── DEBIAN
│ ├── conffiles
│ ├── control
│ └── preinst
└── opt
└── <YOUR APPLICATION>
└── <Your Application Contents>
Basically, you have a deb folder inside the package with the following 2 mandatory folders inside:
DEBIAN - containing files that describe the deb package itself
file-system structure mirroring the destination for the package
installation. In the above example, the package will be deployed inside /opt/<YOUR APPLICATION> directory.
From the DEBIAN directory, you must have at least the control file, which is plain text. It needs to contain entries in specific format that is described in detail in the linked page. Here is a mere example (taken from there) with a sample control file:
Package:packagingmono
Version:1.0
Maintainer:Mikael Chudinov <mikael#chudinov.net>
Architecture:amd64
Section:net
Description:Template for Debian packaged Mono application.
Depends:mono-complete (>=3)
Package must be your package name. Allowed is upper/lower latin letters, numbers and -.
Version - the package version. I'd recommend using the assembly version for that field.
Maintainer - the package developer(s) name and contact info.
Architecture - either i386 or amd64. If you want to distribute your application optimized for x86 and x64 as separate executables per platform (I mean built explicitly for x64 or x86, not using AnyCPU), then you should produce separate .deb packages for each, and set the Architecture field appropriately. The rest of the fields may still be the same.
Section - optional, could be any of the allowed package categories in the debian apt system.
Description. Consist of two tokens - short description (the first item before a new line symbol) and optionally longer one (the text after the first new line).
Depends - a list of dependencies to your package. The example states mono-complete which is the package name for the mono runtime, and further restricts it to be higher or equal to version 3
Important thing to know about a deb package is that you can actually put an entire application (the contents of the bin folder) into a single package.
There is no need to put the referenced libraries in separate packages and mark them as dependencies, the latter makes sense if you plan to install other applications that would rely on the same libraries. Besides, packing the application together would not allow the dll-hell problem to one day become a package-hell problem. A drawback to this is that the size of the package might become larger.
The article also recommends some native GNU/Linux tools that will aid you in the package creation. For example xbuild can be used to run an MSBuild file that will do the packaging for you. This will help make things more familiar to Windows developers. The lintian tool may also assist you in fixing issues with the produced .deb file. The rest of the tools are intermediate utilities that are invoked during the MSBuild packaging process.