Must NuGet dll.config changes be copied to exe.config? - c#

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.

Related

How to trace resolving process of nuget package references

I have a solution with multiple projects in it (~400). A lot of them are using newtonsoft.json library. Some of them are using different version of the library. In a host project for web app, there is no direct reference to newtonsoft.json. Also, I believe, there are dependencies to packages that depend on newtonsoft.json. However, in bin folder of that project I began getting newtonsoft.json 9.0 instead of newtonsoft.json 11.0 as it used to be. And it causes load exception in runtime due to invalid version. If I include direct reference to newtonsoft.json 11.0, it still puts version 9.0 in the bin folder even if I clear all bin,obj folders. I use PackageReference for managing dependencies, and everything is in .net 4.6.1; I use binding redirects to resolve issues with different versions of the same library.
My question is if there is a way to diagnose how particular dll of package ref appears in bin folder? I would like to see some sort of comprehensive trace of dependency resolution so that I can fix it without using "trial and error" approach.
Upd.
Actually, thanks guys for pointing to structured logging. You are the best! So the issue was that one of the project had <OutputPath> pointing to the bin folder of the host project. So when the project was built, it was overriding binaries in the host project. Apparently, build order has changed due to continuous reference shuffling and the project with wrong <OutputPath> started building last. To find this out 1) I Newtonsoft.Json was recorded in DoubleWrites section 2) analyzing location from double writes I found out in _CopyFilesMarkedLocal section
Copying file from "\VenomousProject\bin\Debug\Newtonsoft.Json.dll" to "HostProject\bin\Debug\Newtonsoft.Json.dll".
That was it.
You can try MSBuild Binary and Structured Log Viewer (https://msbuildlog.com/)
build the project from command line with msbuild -bl - you will get msbuild.binlog
open the binlog with the log viewer and use the dll name as a search term
inspect all records related to the dll and backtrack a place (project and msbuild' target) where the wrong file version is taken.
With PackageReference, NuGet will write a file named project.assets.json in the project's obj folder. This file is used by the rest of the build to determine what files from packages should be included in the build, but it also contains a list of all the packages that were selected, what version was selected, and what dependencies each package has (package id and version). This is the closest thing to dependency resolving debugging that NuGet has.
In the file, search for "Newtonsoft.Json/, and you should find which version of Newtonsoft.Json that NuGet selected. Remove the / and replace it with ", and you can find all the packages that have dependencies on Newtonsoft.Josn. Search for newtonsoft.json.dll to find all the packages that ship that dll in its package (sometimes package authors perfer to ship multiple dlls in their package, rather than adding dependencies, which prevents NuGet from being able to version selection.
If there are multiple packages with which contain a dll with the same filename, NuGet will tell MSBuild about all of them, and it's up to MSBuild to select which one to use (pass to the compiler and copy to the bin/publish directory). As #Serg wrote in their answer, you can use binlogs (with the -bl argument on any MSBuild command, including dotnet restore or dotnet build). NuGet's inner workings are not output to MSBuild, so when your package graph has multiple packages that list Newtonsoft.Json as a dependency, it won't tell you why NuGet chose a specific version, but binlogs are very useful at debugging other build related issues.

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.

dotnet pack project references

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.

Common used class library release method

I have a class library project, it releases Common.dll file. I use this dll in my another projects. I wonder that which release method is the best?
Compile class library project in release mode
and add Common.dll as reference to another projects from dlls Release folder.
and copy Common.dll from dlls Release folder to another place and add as reference to another projects from new place.
or another method?
All of these methods have positive and negative sides.
If I use 1st method, when I release Common.dll accidentally it overwrites the other projects referenced old version Common.dll.
If I use 2nd method, when I release Common.dll I have to copy it from Release folder and paste to another place. It will be manually and extra work.
Actually maybe all of these methods are wrong but I hope I could explain my problem. I have a Common.dll project which it is referenced another projects. How should I release this dll?
You have three options:
Add the Common project to your solution and add a project reference: This way you can always edit the Common project and do refactorings.
Add the Common.dll as assembly reference from your repository: The problem is that you can only reference the newest version (latest) of your assembly (or you reference into another branch).
Add the Common.dll as NuGet package: Each package is versioned and you can reference a specific version and only upgrade to a new version if you need to. You can publish the package publicly on nuget.org or you can create your own feed (also possible by using a file directory)

"An assembly with the same simple name has already been imported" error without duplicate reference

I'm getting the following error:
error CS1704: An assembly with the same simple name
'Interop.xxx.dll, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null has already been imported. Try removing one of the
references or sign them to enable side-by-side.
Everything I've seen says that I am referencing two assemblies with the same name and I need to remove one of them. However, I've checked and I'm only referencing it once.
This also only happens when I'm using msbuild to build from the command line on my dev box. If I build through Visual Studio or do a clean build on our CI server I don't see this error.
I've tried completely removing all of my source and building from scratch to more closely resemble the build machine but no luck.
So it looks like I can't read today!
The project had a reference to the Interop and a COM reference that generated the "same" interop. So there were two and I just didn't search very well. I still don't understand why it worked in other places but this did fix it.
In the Error List window, the project that was triggering this error was listed in the Project column. I got around the error by doing the following:
I unloaded the listed project (right-click => Unload Project)
Opened the XML for edit (right-click the unloaded project => Edit {ProjectName.csproj}).
Searched for the offending .dll, and noticed it was listed multiple times in the XML
Removed the entire Reference tag related to the offending dll, and did so for every copy of the reference except the first one listed
The reason it was listed multiple times was because several referenced libraries used that dll. This shouldn't be a problem, in and of itself, so I'm not sure what caused this error to suddenly pop up for me. I'll update this answer if I figure that out.
In my case the duplicate entry was caused by a NuGet package reference and a direct file reference to the same assembly in the packages folder. I am not sure how the project got into this state, but unloading the project and searching the XML file for the offending assembly name resolved the issue for me.
Note that in my case this started happening after updating a NuGet package to a newer version with no other changes to the project, so this maybe caused by a bug in NuGet.
If this is a web project, are there any strong-named references to the other version there? Those won't show up as a project dependency, but will cause a run-time error like you describe. Hope that helps
I had this problem but in my case, I had an old copy placed in the current folder for the EXE loading my component, that was loaded together with the current one, that was loaded by hand from my projects folder. Deleting that old copy solved my problem.
I used Debug > Windows > Modules window to see which modules were loaded at that time and that solved my problem.
For others facing the same as me: if building via command line using property AssemblyName, it will overwrite all assemblies generated by all solution projects - in other words, you will end up with (N -1) assemblies named the same where N is the no. of projects - the startup one (which generally will generate an exe).
This happens because all build command line properties are global and overwrite any project-specific setting. See this and this.
From the msdn link mentioned above:
Global properties are properties that are set by using the
/property switch on the command line, or properties that are set by
the integrated development environment (IDE) before a project is
built. These global properties are applied to all projects that are
built by using this Engine.
In my specific case, where Jenkins is the CI tool, I ended up adding a windows batch command at the end to rename the .exe only to what I originally intended when passing the AssemblyName parameter.
For those developing UWP projects that have project references that include specifically the Microsoft.Windows.SDK.Contracts nuget package (or other dependencies that reference it), this is a common error when the version of the SDK contracts is targeting a different version of the runtime to how your project is configured.
For instance, when targeting Windows 10, version 1903:
Any dependencies or reference projects should target or at least support the same runtime version.
it is common thought process to update all NuGet packages when a new stable version is available, but this is not always a helpful practise on its own. Just because a new stable version of a package is available does not mean that you should or that you can easily use that version.
Even though this package for SDK contracts has a stable update, it is not compatible with my main project configuration, Nuget does not know this so it allows the update.
This package is specifically designed to provide windows dlls for project types that DO NOT have windows platform targeting support, it copies the same dlls that are included by the UWP targeting config. By installing later versions of the package the references from the satellite project will be included in the output along with those provided due to platform targeting, ultimately causing OPs error.
There are similar SDK and targeting packs for Windows IoT Device Runtimes, this information should help you identify and resolve those issues if you get stuck on this issue as my team often does :)
In my case, the issue was on wrong characters in the ProjectReference section of my csproj file.
Background
I have a project that references another library I maintain, which I publish as a NuGet package.
Whenever I make changes to my library, I usually reference the local dll in my project to test and make sure everything looks good before I publish the library as a NuGet package.
When testing, I just comment out the PackageReference line and uncomment the ProjectReference one so it references my local dll, like so:
<ProjectReference Include="..\..\my-class-library\MyClassLibrary.csproj" />
<!--<PackageReference="MyClassLibrary" Version="2.0.1"/>-->
Root cause
I had the slashes inverted, so I was using / rather than \ in the path, like so:
<ProjectReference Include="../../my-class-library/MyClassLibrary.csproj" />
Once corrected, the issue went away.
Try this instead: remove Interop.xx.dll from the reference section in Solution Explorer and Rebuild the project
In our case this error was shown when we had a duplicate reference inside the .csproj file (although I have no idea how this happened).
The difference to an already posted answer is that, in our case, one was a project reference and another one was direct binary reference to a dll.
Once we removed one of those, project correctly compiled.

Categories

Resources