Is it possible to include a web.config or app.config file in the azure functions folder structure to allow assembly binding redirects?
Assuming you are using the latest (June'17) Visual Studio 2017 Function Tooling, I derived a somewhat-reasonable config-based solution for this following a snippet of code posted by npiasecki
over on Issue #992.
It would be ideal if this were managed through the framework, but at least being configuration-driven you have a bit more change isolation. I suppose you could also use some pre-build steps or T4 templating that reconciles the versions of the nugets in the project (and their dependencies) before writing out this config or generating code.
So the downside.... becomes having to remember to update the BindingRedirects
config when you update the NuGet package (this is often a problem in app.configs anyway). You may also have an issue with the config-driven solution if you need to redirect Newtonsoft
.
In our case, we were using the new Azure Fluent NuGet that had a dependency on an older version of Microsoft.IdentityModel.Clients.ActiveDirectory
than the version of the normal ARM management libraries which are used side-by-side in a particular Function.
{
"IsEncrypted": false,
"Values": {
"BindingRedirects": "[ { \"ShortName\": \"Microsoft.IdentityModel.Clients.ActiveDirectory\", \"RedirectToVersion\": \"3.13.9.1126\", \"PublicKeyToken\": \"31bf3856ad364e35\" } ]"
}
}
FunctionUtilities.cs
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
namespace Rackspace.AzureFunctions
{
public static class FunctionUtilities
{
public class BindingRedirect
{
public string ShortName { get; set; }
public string PublicKeyToken { get; set; }
public string RedirectToVersion { get; set; }
}
public static void ConfigureBindingRedirects()
{
var config = Environment.GetEnvironmentVariable("BindingRedirects");
var redirects = JsonConvert.DeserializeObject<List<BindingRedirect>>(config);
redirects.ForEach(RedirectAssembly);
}
public static void RedirectAssembly(BindingRedirect bindingRedirect)
{
ResolveEventHandler handler = null;
handler = (sender, args) =>
{
var requestedAssembly = new AssemblyName(args.Name);
if (requestedAssembly.Name != bindingRedirect.ShortName)
{
return null;
}
var targetPublicKeyToken = new AssemblyName("x, PublicKeyToken=" + bindingRedirect.PublicKeyToken)
.GetPublicKeyToken();
requestedAssembly.Version = new Version(bindingRedirect.RedirectToVersion);
requestedAssembly.SetPublicKeyToken(targetPublicKeyToken);
requestedAssembly.CultureInfo = CultureInfo.InvariantCulture;
AppDomain.CurrentDomain.AssemblyResolve -= handler;
return Assembly.Load(requestedAssembly);
};
AppDomain.CurrentDomain.AssemblyResolve += handler;
}
}
}