Refreshing .NET Assembly Binding Redirects in a Visual Studio Solution

What Exactly are Binding Redirects?

Binding Redirects are there to solve the issues of two libraries requiring different versions of the same assembly, as only one can be loaded. For example:

  • Library A depends on v1.1 of Library C
  • Library B depends on Library A
  • Library B depends on v1.2 of Library C

So in this case, Library B wants to use v1.2 of Library C, but its dependency Library A expects v1.1. So NuGet will install v2 of Library C, and in order to reassure Library A that we can satisfy its dependency of Library C it adds a Binding Redirect to say “sorry we don’t have v1.1 of Library C, but we have v1.2 and that should be fine, and you should be good to use it in its place.”

The following binding redirect specifies this:

<dependentAssembly>
    <assemblyIdentity name="LibraryC" … >  
        <bindingRedirect oldVersion="1.1.0.0" newVersion="1.2.0.0" />
    </assemblyIdentity>
</dependentAssembly>

Of course there is a risk here that v1.2 of Library C won’t be compatible with Library A, leading to errors at runtime, and that is something only the app developer can verify using all of those integration tests they remembered to write.

Keeping your binding redirects in order

Maintaining all of these binding redirects can become a bit of a problem if you have a large number of projects in your solution. Old redirects will stick around, as NuGet won’t automatically remove them due to the risk of those runtime errors that only testing can confirm.

I’ve found that they can cause headaches with source code merges if your team is maintaining multiple branches.

The NuGet package manager provides a cmdlet Add-BindingRedirect that will add all of the necessary binding redirects to a project, however it won’t remove the old binding redirects that no longer apply.

The following PowerShell run in the Package Manager console will apply this:

PM> Get-Project -All | Add-BindingRedirect 

My solution to refreshing binding redirects

DISCLAIMER: This code is provided with no warranty whatsoever. Any changes to your Binding Redirects should be tested thoroughly.

To go that extra step I implemented a Remove-BindingRedirect cmdlet which will remove the assemblyBinding entries in the Project’s config, and can be included in the PowerShell pipeline before the call to Add-BindingRedirect:

function Remove-BindingRedirect {
    param(
        [parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [object[]]
        $Project
    )

    process {
        $ProjectDir = Split-Path $Project.FullName

        $ConfigFileName = $Project.ProjectItems | Where-Object { $_.Name -eq 'web.config' -or $_.Name -eq 'app.config' }
        if ($null -ne $ConfigFileName) {    
            $ConfigPath = Join-Path -Path $ProjectDir -ChildPath $ConfigFileName.Name
            $Xml = [xml](Get-Content $ConfigPath)
            $Ns = @{ ms = "urn:schemas-microsoft-com:asm.v1" }

            $Xml | Select-Xml '//ms:assemblyBinding' -Namespace $Ns | ForEach-Object {
                $Xml.configuration.runtime.RemoveChild($_.Node)
            } | Out-Null

            $Xml.Save($ConfigPath)

            Write-Host "Removed bindingRedirects from $ConfigPath"
        }  
        else {
            Write-Host "Couldn't remove bindingRedirects from $($Project.Name) as couldn't find a config file"
        }

        return $Project
    }
}

I save this in a file RemoveBindingRedirect.ps1, dot source it within the Package Manager console, and then to refresh all of the bindingRedirects within all of the projects in a solution I run:

PM> . "RemoveBindingRedirect.ps1"
PM> Get-Project -All | Remove-BindingRedirect | Add-BindingRedirect 

Please ensure your configs are version controlled prior to running this. After running for a good few minutes all of the configs in the solution should be refreshed.

Leave a Reply

Your email address will not be published. Required fields are marked *