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.

Client Side Package Management in Visual Studio 2015

If like me you’ve always had one foot in the open source development camp, then you’ll be really pleased by the recent changes in ASP.NET 5. Microsoft have stopped reinventing the wheel and accepted that the existing open source tools for client-side package management should be integrated into Visual Studio.

Gulp, Grunt, Bower, NPM – what’s the difference exactly?

I’ll start with a summary:

  • NPM, is the package manager that installs the other package managers discussed in this post, as they all run on node.js locally.
  • Gulp and Grunt are both task runners running on the node.js runtime, and their main functions are to pre-process and/or bundle our client side JavaScript and CSS.
  • Bower is a package manager for all the HTML, JavaScript, CSS, fonts, and images that are bundled with a modern UI package or framework.

The NPM and Bower package managers are smart enough to resolve all the dependencies required by a package, and make sure that we only download a single instance of a given dependency.

NPM

NPM is a JavaScript package manager, and became the standard package manager for node.js a number of years ago. Every NPM package comes with a package.json file which has details of the package’s current version, dependencies, contact info and documentation, and scripts that should be run at specific points in its life-cycle.

Gulp

ASP.NET Gulp Docs

Gulp is so named as it is based on piping streams through multiple commands until all the commands are complete. This piping means that Gulp takes more advantage of the asynchronous nature of node.js, and can give better performance.

The standard ASP.NET 5 project templates use Gulp as the default task runner, so if you create an ASP.NET 5 project with Visual Studio, Gulp will be available straight away. If you right-click on the gulpfile.js in the Solution Explorer and then click the Task Runner Explorer, then you will be able to see all the individual tasks that are defined.

Gulp Tasks

Tasks are defined using a JavaScript function, and can have dependent tasks specified as an array of strings of existing task names. If tasks are going to take a long time to run it can be good to split them up if we only want to run one.

Gulp Modules

Tasks run code from modules that are required by the gulpfile to do things such as cleaning out your build directory. You would do this by requiring the rimraf module and then calling it within a “clean” task, passing your build directory in as a parameter.

Gulp modules are installed using NPM.

Grunt

ASP.NET Grunt Docs

Grunt is a Task Runner similar to Gulp, and also has integration in Visual Studio 2015. It takes more of a declarative approach to defining tasks: you require already available Grunt tasks, and specify parameters for them by using JSON. I won’t go into as much detail on Grunt here as I’m planning to stick with Gulp for task running in future.

Bower

ASP.NET Bower Docs

Bower is a package manager for client-side code, it was created by the team behind Bootstrap to give people a standard way of obtaining updates to it. We require so much client side code from so many sources, each with their own dependencies, that it has become too much of a handful to just commit random snippets into version control and expect ourselves to manually keep everything up to date.

You can think of Bower as NuGet for the static third-party code that your web application requires. Rather than downloading packages from the web, including possibly resolving dependencies manually, it will take care of downloading everything we need for a particular package.

If you have experience of working on an application with a decent amount of JavaScript, then you will know that formally managing your third-party JavaScript, and the dependencies that it brings with it, really pays off in the long-term.

Yeoman

ASP.NET Yeoman Docs

Yeoman is like Bower except it just generates projects from templates. It does the same job as the project templates that already exist within Visual Studio, so I’m not going to go into too much detail on it in this post.