How to write a NuGet package that updates the binding redirects when the package reference is upgraded?

隐身守侯 提交于 2019-12-25 17:20:10

问题


We use VS 2017 and consume NuGet packages the old way. We do not use PackageReference as of yet.

When a NuGet package reference is updated through the NuGet Manager in VS, the respective assembly binding redirect is not updated automatically - we have to do it manually.

So, I suppose it is up to the package to take care of it through the tools\install.ps1 script. Now, I think I know how to implement it, but I do not want to invent the wheel. Surely the code already exists somewhere, but where?

Clarification

Our application is strongly signed and it targets .NET 4.5.2 currently (soon to be upgraded to 4.7.2). We use packages.config.

I need to explain what is going on. There are three players on the field:

  1. A tool - DbUpgrade
  2. The tool plugin Api - DbUpgradeApi
  3. An implementation of the plugin Api - LogDbUpgradeProgress

Let us inspect the DbUpgradeApi package. 3 versions of it are relevant to us:

  1. The version against which LogDbUpgradeProgress is compiled - A
  2. The version against which DbUpgrade is compiled - B
  3. The latest version of DbUpgradeApi - C

The DbUpgrade tool loads the plugin LogDbUpgradeProgress at runtime. The binding redirects are needed, because A is not the same as B (and because the code is signed, nothing to do here currently)

If C is higher than B, then we should update the reference to DbUpgradeApi in DbUpgrade. But doing so must be accompanied with updating the binding redirect. And this is the essence of this question.


回答1:


Ok, so I just spent the last hour testing, and I didn't need to do anything that I consider special for binding redirects to work.

But first, are you sure you need binding redirects? .NET Core doesn't need it. If you're using .NET Framework, but with a project using PackageReference, then it's resolved at build time, your app.config doesn't need the binding redirect in the version that's checked in with your code, but when you build and check the [your exe name].config file it does have the binding redirects. Also, binding redirects only matter when your assembly has strong naming. If you didn't sign your assembly, then binding redirect isn't needed.

Here are the steps that I took to create a reproduction of getting binding redirects in a console app using packages.config.

  1. Create an empty folder to start with. I used dotnet new sln, dotnet net nugetconfig to generate a new sln and nuget.config file. I edited the nuget.config file to add the folder localFeed as a source, and set the globalPackagesFolder to gpf so I didn't pollute my real global packages folder with test packages. Also created a strong name key with sn -k snk.snk.
  2. Create first test classlib. dotnet new classlib -n someLib. I edited Class1.cs to change the class name to SomeClass and added a property that retusns the value "Version 1". Used Visual Studio to set snk.snk as the signing key. dotnet pack to generate V1 of the package. I then edited SomeClass to change the message to "Version 2" and then ran dotnet pack /p:version=2.0.0. Finally, used nuget.exe add -source localFeed someLib\bin\Debug\someLib.1.0.0.nupkg and again for v2 of the nupkg.
  3. Create the second test classlib, dotnet new classlib -n anotherLib and set the signing key to snk.snk. Changed Class1.cs to AnotherClass and added a property public string Message => new someLib.SomeClass().Message;. Added a reference to someLib version 1 in the csproj, then built, packed and used nuget.exe to add the nupkg to localFeed.
  4. Opened Visual Studio and created a .NET Framework console app. Added a reference to anotherLib, which automatically brought in v1 of someLib. Upgraded the reference of someLib to v2, and confirmed that packages.config now has a binding redirect for someLib.
  5. Created another .NET Framework console app and did the same as step 3, but this time using PackageReference instead of packages.config. The project app.config doesn't have binding redirects, but the .config file in the bin folder after build does.

edit: perhaps an important part to understanding NuGet/MSBuild binding redirect behaviour is the following: In both steps 3 and 4, if I add a reference only to anotherLib, then no binding redirect is created because all assembles that reference someLib reference the same version. Only by making my console app reference a different version of someLib than anotherLib uses, then the binding redirect is created.

In an app with plugins, the building the app assembly won't have a binding redirect, because it's the only assembly in the compile command line that uses the plugin contract dll, so no conflict to need a binding redirect. When the plugin assembly is built, only the plugin depends on the plugin contract dll, so again no conflict so no binding redirect. If you copy all the dlls into a single folder, then there can be a conflict in the required version, but this is a deployment time issue, not a build/compile time issue, so build tools may not help. One way to resolve this would be to add a reference to the plugin project from the app assembly. This way at compile time the build tools can see that two different versions of the plugin contract dll is used, so a binding redirect can be created. This only works if you build the app assembly. If the app is just a binary that you're given, then changing the binding redirects becomes a deployment time responsibility, so development/build tools may not help.



来源:https://stackoverflow.com/questions/54009529/how-to-write-a-nuget-package-that-updates-the-binding-redirects-when-the-package

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!