Nuget Update-Package incorrectly updating assembly binding redirects

ぃ、小莉子 提交于 2019-11-27 16:07:32

问题


I have an internal NuGet package that contains a single dll, no external NuGet package dependencies, and no web.config transforms.

Yet when i run Update-Package on my projects (class lib and website) for this specific NuGet, it automatically is updating my website web.config assembly binding redirects to older versions of System.Web.Mvc and Newtonsoft.Json. The website web.config currently has them bound to the latest version being used.

Using the GUI, utilizing Manage NuGet packages for Solution... I choose to UPDATE this NuGet for applicable projects that have a reference to the old version. Then choose Update

Here is the output from Package Manager: http://pastebin.com/3ySwTRFR

And my web.config went from:

  <dependentAssembly>
    <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
    <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
  </dependentAssembly>

  <dependentAssembly>
    <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
  </dependentAssembly>

To:

  <dependentAssembly>
    <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
    <bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
  </dependentAssembly>

  <dependentAssembly>
    <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-4.5.0.0" newVersion="4.5.0.0" />
  </dependentAssembly>

The NuGet package I am updating has a dll which references Newtonsoft.Json (but is not explicitly made a NuGet package dependency)

When unknowing developer updates this NuGet package it breaks the runtime looking for old version of MVC or JSON.NET dlls.

In the past I have attempted to use the -IgnoreDependencies powershell command switch, but this appears to have no impact on the issue.

Any idea on what could be transforming my web.configs (without an explicit transform) during update-package?

Edit: VS2015 w/ NuGet 3.3.0 seems to be behaving better... during random package update it found an old BAD binding redirect and corrected it!


回答1:


Skip applying binding redirects is an option now in NuGet 3.3.0: Issue #1147




回答2:


I have a better solution. Because I gets absolutely crazy when I have to update over 72 references everytime I update my packages, I've developed a PowerShell script that updates your Web.Config based on the packages in your packages.config and the DLLs you have published in the BIN directory.

param (
    [Parameter(Mandatory=$false)]
    [string] $webConfigPath,
    [string] $packagesConfigPath,
    [string] $binPath
)

[bool]$isWindowsFormsAssemblyLoaded = $false
[System.Xml.Linq.XNamespace]$ns1 = "urn:schemas-microsoft-com:asm.v1"

function ClearBindings([System.Xml.Linq.XDocument] $xml) {

    $elements = $xml.Root.Element("runtime").Element($ns1 + "assemblyBinding").Elements()
    $l1 = New-Object "System.Collections.Generic.List[System.Xml.Linq.XElement]"
    $l1.AddRange($elements)

    $l1 | ForEach-Object { $_.Remove() }
}
function GetPackageList([System.Xml.Linq.XDocument] $xml, [string] $binPath) {

    $elements = $xml.Root.Elements("package")
    $l1 = New-Object "System.Collections.Generic.List[System.Xml.Linq.XElement]"
    $l1.AddRange($elements)

    [System.Collections.Generic.List[string]]$packageList = New-Object "System.Collections.Generic.List[string]"
    $l1 | ForEach-Object { $packageList.Add("$binPath\" + $_.Attribute("id").Value + ".dll") }
    return $packageList
}
function ExtractPublicKey([System.Reflection.Assembly]$asm) {
    $bytes = $asm.GetName().GetPublicKeyToken()
    return [System.BitConverter]::ToString($bytes).Replace("-", "")
}
function ExtractCulterInfoName($asm) {
    if ($asm.GetName().CultureInfo.TextInfo.CultureName -eq "") {
        return "neutral"
    } else {
        return $asm.GetName().CultureInfo.TextInfo.CultureName
    }
}
function CreateBindingElement([System.IO.FileInfo] $fi) {

    [System.Reflection.Assembly]$asm = [System.Reflection.Assembly]::LoadFile($fi.FullName)
    $publicKey = ExtractPublicKey $asm
    $culterInfo = ExtractCulterInfoName $asm

    $assemblyIdentity = [System.Xml.Linq.XElement]::new($ns1 + "assemblyIdentity")
    $assemblyIdentity.Add([System.Xml.Linq.XAttribute]::new("name", $asm.GetName().Name))
    $assemblyIdentity.Add([System.Xml.Linq.XAttribute]::new("publicKeyToken", $publicKey))
    $assemblyIdentity.Add([System.Xml.Linq.XAttribute]::new("culture", $culterInfo))

    $bindingRedirect = [System.Xml.Linq.XElement]::new($ns1 + "bindingRedirect")
    $bindingRedirect.Add([System.Xml.Linq.XAttribute]::new("oldVersion", "0.0.0.0-65535.65535.65535.65535"))
    $bindingRedirect.Add([System.Xml.Linq.XAttribute]::new("newVersion", $asm.GetName().Version<#$fi.VersionInfo.FileVersion#>))

    return [System.Xml.Linq.XElement]::new($ns1 + "dependentAssembly", $assemblyIdentity, $bindingRedirect)
}
function UpdateBindings([string] $webConfigPath, [string] $packageConfigPath, [string] $binPath) {

    $webConfig = [System.Xml.Linq.XDocument]::Load($webConfigPath)
    ClearBindings $webConfig

    [System.Xml.Linq.XDocument] $packageConfig = [System.Xml.Linq.XDocument]::Load($packageConfigPath)
    $packages = GetPackageList $packageConfig $binPath

    [System.Xml.Linq.XElement]$assemblyBinding = $webConfig.Root.Element("runtime").Element($ns1 + "assemblyBinding")

    $packages | ForEach-Object {

        [System.IO.FileInfo]$fi = [System.IO.FileInfo]::new($_)
        if ($fi.Exists) {
            $newElement = CreateBindingElement $fi
            $assemblyBinding.Add($newElement)
        }
    }

    $webConfig.Save($webConfigPath)
}
function LoadWindowsFormsAssembly() {
    if (!$isWindowsFormsAssemblyLoaded) {
        [void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
        $isWindowsFormsAssemblyLoaded = $true
    }
}
function PromptForFile ([string]$title, [string]$filter) {

    LoadWindowsFormsAssembly
    [System.Windows.Forms.OpenFileDialog]$dialog = New-Object System.Windows.Forms.OpenFileDialog
    $dialog.Multiselect = $false
    $dialog.Title = $title
    $dialog.Filter = $filter

    if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { return $dialog.FileName }
    else { return $null }
}
function PromptForDirectory ([string]$title) {

    LoadWindowsFormsAssembly
    [System.Windows.Forms.FolderBrowserDialog]$dialog = New-Object System.Windows.Forms.FolderBrowserDialog

    if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { return $dialog.SelectedPath }
    else { return $null }
}
function MessageBox([string]$title) {

    LoadWindowsFormsAssembly
    [System.Windows.Forms.MessageBox]::Show($title)
}

if ([System.String]::IsNullOrEmpty($webConfigPath)) {
    $webConfigPath = PromptForFile 'Please select the web.config file' '.NET Configuration File (web.config)|web.config'
    if ([System.String]::IsNullOrEmpty($webConfigPath)) {exit}
}

if ([System.String]::IsNullOrEmpty($packagesConfigPath)) {
    $packagesConfigPath = PromptForFile 'Please select the packages.config file' 'NuGet Package  File (packages.config)|packages.config'
    if ([System.String]::IsNullOrEmpty($packagesConfigPath)) {exit}
}

if ([System.String]::IsNullOrEmpty($binPath)) {
    $binPath = PromptForDirectory "Please select your application's BIN directory"
    if ([System.String]::IsNullOrEmpty($binPath)) {exit}
}


UpdateBindings $webConfigPath $packagesConfigPath $binPath



回答3:


Use following command in Package Manager Console

PM> Get-Project –All | Add-BindingRedirect

Refer https://weblog.west-wind.com/posts/2014/nov/29/updating-assembly-redirects-with-nuget for detailed explanation.



来源:https://stackoverflow.com/questions/30358370/nuget-update-package-incorrectly-updating-assembly-binding-redirects

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