Azurefunction绑定重定向

是否可以在azure函数文件夹结构中包含web.config或app.config文件以允许程序集绑定重定向?

假设您使用的是最新的(2017年6月)Visual Studio 2017函数工具,我在npiasecki在问题#992上发布了一段代码后, npiasecki了一个有点合理的基于配置的解决方案。

如果通过框架管理它将是理想的,但至少在配置驱动下你有更多的变更隔离。 我想你也可以使用一些预构建步骤或T4模板来协调项目中的nugets版本(及其依赖项),然后再写出这个配置或生成代码。

所以缺点..

..当你更新NuGet包时,必须记得更新BindingRedirects配置( 这在app.configs中通常是一个问题 )。 如果您需要重定向Newtonsoft您可能还会遇到配置驱动解决方案的问题。

在我们的示例中,我们使用的新Azure Fluent NuGet依赖于旧版本的Microsoft.IdentityModel.Clients.ActiveDirectory不是在特定Function中并排使用的常规ARM管理库的版本。

local.settings.json

 { "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>(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; } } } 

刚刚发布了一篇新的博客文章,解释了如何解决问题,看看:

https://codopia.wordpress.com/2017/07/21/how-to-fix-the-assembly-binding-redirect-problem-in-azure-functions/

它实际上是JoeBrockhaus代码的调整版本,即使对于Newtonsoft.Json.dll也能很好地运行

今天不可能直接实现,但我们正在考虑实现这一目标的方法。 您能否在https://github.com/Azure/azure-webjobs-sdk-script/issues上打开一个问题,以确保查看您的具体方案? 谢谢!

受到接受的答案的启发,我认为我会做一个更通用的考虑到升级的问题。

它获取所有程序集,命令它们降序以获得最新版本,然后返回最新版本。 我自己在一个静态构造函数中调用它。

 public static void RedirectAssembly() { var list = AppDomain.CurrentDomain.GetAssemblies() .Select(a => a.GetName()) .OrderByDescending(a => a.Name) .ThenByDescending(a => a.Version) .Select(a => a.FullName) .ToList(); AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var requestedAssembly = new AssemblyName(args.Name); foreach (string asmName in list) { if (asmName.StartsWith(requestedAssembly.Name + ",")) { return Assembly.Load(asmName); } } return null; }; } 

当您需要特定组件的确切版本时,这是另一种解决方案。 使用此代码,您可以轻松部署缺少的程序集:

 public static class AssemblyHelper { //-------------------------------------------------------------------------------- ///  /// Redirection hack because Azure functions don't support it. /// How to use: /// If you get an error that a certain version of a dll can't be found: /// 1) deploy that particular dll in any project subfolder /// 2) In your azure function static constructor, Call /// AssemblyHelper.IncludeSupplementalDllsWhenBinding() /// /// This will hook the binding calls and look for a matching dll anywhere /// in the $HOME folder tree. ///  //-------------------------------------------------------------------------------- public static void IncludeSupplementalDllsWhenBinding() { var searching = false; AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // This prevents a stack overflow if(searching) return null; var requestedAssembly = new AssemblyName(args.Name); searching = true; Assembly foundAssembly = null; try { foundAssembly = Assembly.Load(requestedAssembly); } catch(Exception e) { Debug.WriteLine($"Could not load assembly: {args.Name} because {e.Message}"); } searching = false; if(foundAssembly == null) { var home = Environment.GetEnvironmentVariable("HOME") ?? "."; var possibleFiles = Directory.GetFiles(home, requestedAssembly.Name + ".dll", SearchOption.AllDirectories); foreach (var file in possibleFiles) { var possibleAssembly = AssemblyName.GetAssemblyName(file); if (possibleAssembly.Version == requestedAssembly.Version) { foundAssembly = Assembly.Load(possibleAssembly); break; } } } return foundAssembly; }; } }