问题
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:
- A tool - DbUpgrade
- The tool plugin Api - DbUpgradeApi
- An implementation of the plugin Api - LogDbUpgradeProgress
Let us inspect the DbUpgradeApi package. 3 versions of it are relevant to us:
- The version against which LogDbUpgradeProgress is compiled - A
- The version against which DbUpgrade is compiled - B
- 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.
- 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 folderlocalFeed
as a source, and set theglobalPackagesFolder
togpf
so I didn't pollute my real global packages folder with test packages. Also created a strong name key withsn -k snk.snk
. - Create first test classlib.
dotnet new classlib -n someLib
. I editedClass1.cs
to change the class name toSomeClass
and added a property that retusns the value "Version 1". Used Visual Studio to setsnk.snk
as the signing key.dotnet pack
to generate V1 of the package. I then editedSomeClass
to change the message to "Version 2" and then randotnet pack /p:version=2.0.0
. Finally, usednuget.exe add -source localFeed someLib\bin\Debug\someLib.1.0.0.nupkg
and again for v2 of the nupkg. - Create the second test classlib,
dotnet new classlib -n anotherLib
and set the signing key tosnk.snk
. Changed Class1.cs toAnotherClass
and added a propertypublic 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. - Opened Visual Studio and created a .NET Framework console app. Added a reference to
anotherLib
, which automatically brought in v1 ofsomeLib
. Upgraded the reference ofsomeLib
to v2, and confirmed thatpackages.config
now has a binding redirect forsomeLib
. - Created another .NET Framework console app and did the same as step 3, but this time using
PackageReference
instead ofpackages.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