dotnet pack project references - c#

I quite like separating functionality across a few assemblies, for example a facade to a data provider, contracts for the data provider and the data provider implementation itself... to my mind, it makes it easy to unit test the individual components of a piece of functionality and easy to swap out one thing in the future (in the case of my example, it makes the data provider easy to swap out).
If I create a solution with 3 projects and use project references, when I dotnet-build on the entry assembly, all the references are copied to the output folder. When I dotnet pack the entry assembly project to create a NuGET package, only the entry asembly (not the contracts or the data provider) are included in the NuGET package
This appears to be by design; the documentation for .NET Core dotnet-pack states that
Project-to-project references aren't packaged inside the project.
Currently, you must have a package per project if you have project-to-project dependencies.
My question is - why is this the case? If I want to separate my code into logical assemblies, I am forced to either create separate NuGET packages and reference those, or simply lump all my code into a single assembly. Is there any way to include project references in a NuGET package?
I am using VS2017 / .NET Core v1.1 (csproj, not xproj)

A possible way to achieve the needed is to use a custom .nuspec file where you can specify the dlls you want to be packed
<PropertyGroup>
<NuspecFile>App.nuspec</NuspecFile>
</PropertyGroup>
Having this, dotnet pack will produce the package with respect to MyPackage.nuspec.
Furthermore, if you have like 3 projects with contracts and implementation and you don't want to add 3 package references, you can create a meta-package that simply has those 3 as dependencies and reference that single meta-package.

Related

How can my NuGet package add another package reference at runtime based on the current runtime identifier?

I'm creating multiple OS-specific NuGet packages. Each one of them contains a fairly large native process. I can't combine them in a single NuGet package, it'll be too big. So it looks like this:
- MyProject.win-x86-x64
- MyProject.macos-x86-x64
- MyProject.ubuntu1804-x86-x64
- MyProject.ubuntu1804-arm64
- MyProject.debian10-x86-x64
- ...
I'd like to create another netstandard2.0 package that references the right OS-specific package based on the current OS runtime identifier, using a .targets file included in the build and buildTransitive package directory.
So far the best I can do is use $([MSBuild]::IsOsPlatform()) which only tells if the consumer is targeting Windows, OSX or Linux. It doesn't provide the current Linux distribution.
I know it's also possible to retrieve the runtime identifier using the source code of the soon deprecated Microsoft.DotNet.PlatformAbstractions package, as suggested by Dan Moseley from MS. However, I have no idea how I cound integrate this code into my custom .targets file.
Does anybody knows how I could reference the right OS-specific package in a custom .targets file?

Possibility to avoid adding nuget package reference in favor of assembly reference incl. dependencies?

is there a way to avoid nuget package references to ease development on a developers machine?
we are currently about to move some of our projects in our "shared" solution to the new csproj file structure (using <Project Sdk="Microsoft.NET.Sdk">) and using <TargetFramework>netstandard2.0</TargetFramework>.
By doing so we had to include <PackageReference Include="System.Text.Encodings.Web" Version="4.7.0" /> and changing some of our code in project "S" of our shared solution.
Within another solution backend we are having multiple projects. Some of them are referencing the assembly of project S by using assembly reference to S.dll like so:
<Reference Include="ournamespace.S">
<HintPath>..\..\artifacts\Shared\ournamespace.S\ournamespace.S.dll</HintPath>
</Reference>
When we build every works fine. However when running our web application W from backend solution we get this exception:
System.IO.FileNotFoundException: Could not load file or assembly 'System.Text.Encodings.Web, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified.
Before we have migrated our shared projects to the "new SDK" project file format, before using .netstandard2.0 (we were using .net framework 4.7.2) and before we switched the package reference to System.Text.Encodings.Web (we were using <PackageReference Include="AntiXSS" Version="4.3.0" />) we have not received any error.
The only way i can think of is that we would need to switch from assembly reference for S.dll to use nuget - to get S dependencies.
However using nuget packages for our shared solutions projects and developing in backend projects would become a nightmare as we would need to create a new nuget package (and publishing it) on every change of S and would need to increase the version number in the package references in backend projects all the time. Also this would become very impractical as our developers are using various git feature branches too (thinking about versioning conflicts; having to release unfinished packages and maybe using version suffix "alpha_"+{branchName} to distinct the branch that this version is coming from).
How to develop on localhost? Is there a way to avoid nuget (but getting its dependencies resolved correctly!)?
I was already reading about having assembly references for local development while using nuget package references for CI builds by using conditionals in the csproj file (however this is also not working very well with VS2017; also this would not resolve our problem with the dependency problem written above on localhost)
What other possibilities are there? Is there a best way on how to handle this?
Thanks in advance!
P.S. I dont want to include S's dependencies to every project that references S by using package references there as well. This would not be a solution and becomes more cumbersome when S might get new dependencies for whatever reason.
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
solved my problems (see How to get .NET Core projects to copy NuGet references to build output? for details)

Missing DLL's own dependencies in consuming projects

I created a class library project using C# and .Net.
In this project I used two external dependencies(to be more specific: Microsoft.Win32.Registry(4.6.0) and System.Data.SqlClient(4.7.0) Nuget packages).
After I build this project, I can see the generated DLL file under /bin/debug folder.
Now I want to import this generated DLL in another project and consume its methods. Once imported and I run this project, it complains about not being able to find those two external dependencies I had in class library project.
As a temporary fix, I can import these two missing references in this project and it will work fine and as expected. But this is not what I want(and I guess is not a clean solution as well).
I want to know why the dependencies of class library project is not reflected in generated dll file? And is there any way to fix this?
Many thanks for your help.
If your class library is in the same solution or source control repository as the app that's using it, you should use a project-to-project reference, rather than referencing the assembly directly. As the docs say, this way it automatically detects changes to the class library when you compile the app, but what the docs didn't say is that dependencies flow though as well.
Otherwise, as Lance Li wrote, you should create a NuGet package from your class library. Unfortunately there's a bit of a barrier to get started. Creating the package is easy, but then you need to publish the nupkg file somewhere. For early development (before the package is ready to be shared), the easiest option is to use a local file feed. You'll then need a nuget.config in the app that will use the package to add that local feed as a source, then you can install the package in your consuming project, which will bring dependencies.
As you can see, for development, this is slow and difficult because if your consuming app finds a bug in your package, or if you're trying to develop a new feature in both the consuming app and class library at the same time, it means every time you make code changes to class library, you need to increment the version number, pack a package, publish the package, then update the package version in the consuming project. It's far, far easier to use a ProjectReference which lets you simply edit code, compile, run. Nothing else to think about.
See this, the way you reference that assembly is not a recommended way when both the projects are in same machine.
You're using the file reference(Add reference => browse...). And that's why you have to import these two missing references in this project manually.
So I suggest you add the project reference, if both the two projects are in same solution, you can right-click current project=>add reference=>project tab find that assembly you need.(instead of browsing...)
If the referenced project is not in same solution. Right-click solution in solution explorer=>add existing project to import it. Then add project reference.

Must NuGet dll.config changes be copied to exe.config?

If I add a NuGet package reference to DLL project MyLib (i.e. output type Class Library), the package manager sometimes creates an app.config in the project (for example with a bindingRedirect) that gets built as MyLib.dll.config. Microsoft.Owin 2.1.0 does this, for example.
When my Windows desktop application loads MyLib.dll, it ignores the bindingRedirect in MyLib.dll.config, and I get a FileLoadException. I can fix the problem if I manually copy the bindingRedirect to the app.config for the EXE project.
Is this manual copy-paste between app.config files really the only way to get a NuGet bindingRedirect to work?
It seems terribly tedious and error-prone given that NuGet is supposed to handle dependencies automatically.
It is the only way: app.config files in Class Library projects are essentially just sample code that you can copy into the main application's config file if needeed.
In the case of bindingRedirect - I would expect it only to be necessary in two cases:
if you have multiple dlls accessing different versions of the MyLib assembly. In which case, you need to make an explicit decision as to which version you're going to use.
If your main application's assembly contains configuration elements that reference an older version of the MyLib assembly. In which case you can do one of:
Update the versions in your main configuration file
Add a bindingRedirect to the main configuration file
Add the Nuget package to the main application project, in which case it will presumably add the bindingRedirect for you.
All that package specific config file does is show you the configuration that is specific to that package. You may or may not want to put it into your actual config file, you may need to tweek it for your purposes (EntityFramework or log4net are good examples of that). In the case of installing the package into a class library a config file makes no sense at all, that config needs to be moved into the appropriate executable app.config - how could that be automated.
Before nuget you would download the dll from somewhere and then follow the instructions on how to set up the necessary configuration. This is definitely an improvement on that.
So in summary, yes you do need to copy it if you need it and it does make sense.
There is a better way. I just needed to add some local project references before adding the NuGet package reference.
When I originally added the Microsoft.Owin NuGet reference to MyLib, I had not yet added a MyLib reference to MyApp (aka the EXE project). With the MyLib reference in MyApp, I uninstalled the Microsoft.Owin NuGet package, then added Microsoft.Owin back to MyLib. Bada-bing-bada-boom. The bindingRedirect was automagically added to MyApp's app.config file.
So, when creating a new Class Library, one should apparently add new-library references to existing projects before adding NuGet package references to the new library.

TFS and Libraries not available in nuget

So we have a ASP.net MVC 4 solution that is composed of the 3 projects BusinessLibrary.UI, BusinessLbrary.Domain, BusinessLibrary.Tests
We use nuget to manage all of our libraries like json.net, entity, etc. But we also have some private libraries that we have added. What is the best way to manage of the private libraries we have. I would like to be able to have a new developer to get all the DLL's associated with this project when they start.
Ive read that I could create a library or lib folder, and then just reference the DLL's to there. But should that be checked in with the Project' s Source Control then? Would I only want to copy over the non-nuget private libraries. Is this the best way to go?
What is the standard practice for situations like this, how should I be storing my private libraries?
Personally, I create a dependencies folder at the solution level. I put all non-NuGet libraries that I reference there. When I add the reference, I'm sure to reference the assembly from the dependencies folder. Make sure you add the dependencies folder to Source Control.
That way any developer pulling down the solution from Source Control will automatically have the correct version of all of the dependencies.
Optionally you can install your own NuGet server and place your libraries there after successfull server build of those libraries
We create a library directory, add the assemblies there and use relative paths to reference them. We also check in this directory, so every team member immediately has the newest assemblies.
Another option would be to setup a private NuGet feed (such as MyGet) and publish your assemblies there as packages.
In our project we created lib folder for private dll's and checked in it to TFS along with source code. NuGet packages are added to TFS automatically.

Categories

Resources