Odpowiedz

2

Dziś nie jest to bezpośrednio możliwe, ale zastanawiamy się, jak to osiągnąć. Czy możesz otworzyć numer na https://github.com/Azure/azure-webjobs-sdk-script/issues, aby upewnić się, że Twój konkretny scenariusz jest rozpatrywany? Dzięki!

+1

nowy problem związany: wiążące przekierowań dla CSX ładowanie wielu DLL # 1239 https://github.com/Azure/azure-webjobs-sdk-script/issues/1239 –

8

Zakładając, że używasz najnowszej (June'17) Visual Studio 2017 Function Tooling, że pochodzi nieco config-rozsądne rozwiązanie oparte na to następujący fragment kodu wysłana przez npiasecki nad na Issue #992.

Byłoby idealnie, gdyby to było zarządzane przez framework, ale przynajmniej będąc sterowanym konfiguracją, masz nieco więcej izolacji zmiany. Przypuszczam, że można również użyć kroków wstępnego budowania lub szablonowania T4, które uzgadnia wersje nugetów w projekcie (i ich zależności) przed wypisaniem tego kodu konfiguracyjnego lub generującego.

Więc minusem ..

.. staje konieczności pamiętania zaktualizować BindingRedirects config podczas aktualizacji pakietu Nuget (to często problem w app.configs zresztą). Możesz również mieć problem z rozwiązaniem opartym na konfiguracji, jeśli musisz przekierować Newtonsoft.

W naszym przypadku używaliśmy nowego Azure Fluent NuGet, który był zależny od starszej wersji Microsoft.IdentityModel.Clients.ActiveDirectory niż wersja normalnych bibliotek zarządzania ARM, które są używane obok siebie w konkretnej funkcji.

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<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; 
      } 
     } 
    } 
+0

Dzięki za to. Jest to prawie niezbędne w przypadku większości projektów nuget. Mając nadzieję, że wkrótce to rozwiążą. – Grapes

+1

Dla każdego, kto boryka się z tym problemem: jeśli masz więcej niż jedną wersję, która wymaga odbicia, musisz usunąć linię AppDomain.CurrentDomain.AssemblyResolve - = handler; Ponieważ oznaczało to tylko pierwszą wersję, którą odnaleziono, została przekierowana. – bech

1

Zainspirowany zaakceptowanej odpowiedzi Pomyślałem, że zrobię bardziej ogólny jeden, który bierze pod uwagę także rozbudowę.

Pobiera wszystkie złożenia, zleca ich zstępowanie, aby uzyskać najnowszą wersję na wierzchu, a następnie zwraca najnowszą wersję po rozwiązaniu. Sam to nazywam statycznym konstruktorem.

public static void RedirectAssembly() 
{ 
    var list = AppDomain.CurrentDomain.GetAssemblies().OrderByDescending(a => a.FullName).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; 
    }; 
}