2017-04-12 1 views
2

Alors d'abord, j'utilise le billet de blog pour me aider à convertir ma CSX Azure fonction d'une bibliothèque de classes précompilés - https://blogs.msdn.microsoft.com/appserviceteam/2017/03/16/publishing-a-net-class-library-as-a-function-app/?utm_source=Directprécompilés Azure Fonction lancer erreur sur HttpClientExtensions.SetBearerToken utilisation, CSX ne

I J'en suis au point où je pense que ça devrait fonctionner, mais en tant que fonction précompilée, il lance une exception 'Méthode introuvable' sur SetBearerToken (qui est dans System.Net.Http.HttpClientExtensions) mais il n'a pas de problème de trouver cette méthode dans la version CSX. Voici la pleine erreur:

Exception while executing function: Functions.notifications-queue-trigger Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: Functions.notifications-queue-trigger ---> System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. ---> System.MissingMethodException : Method not found: 'Void System.Net.Http.HttpClientExtensions.SetBearerToken(System.Net.Http.HttpClient, System.String)'.

Le code est à peu près identitcal entre la fonction précompilé & le script CSX (autre que les différences nécessaires évidemment).

Qu'est-ce qui me manque ici? Pourquoi lance-t-il une exception 'Méthode non trouvée' pour SetBearerToken dans System.Net.Http.HttpClientExtensions dans la version précompilée alors qu'elle n'a pas de problème lorsqu'elle est écrite en tant que script CSX? Toute aide appréciée.

Voici ma fonction en tant que script CSX, cela fonctionne:

#r "IdentityModel.dll" 
#r "Sorbet.DataTransferObjects.dll" 
#r "Newtonsoft.Json" 

using System; 
using System.Text; 
using System.Threading.Tasks; 
using System.Net.Http; 

using IdentityModel.Client; 
using Newtonsoft.Json; 
using Sorbet.DataTransferObjects; 

public static void Run(NotificationDto myQueueItem, TraceWriter log) 
{ 
    log.Info($"C# ServiceBus queue trigger function processed message"); 
    TokenResponse idToken; 
    using (var tokenClient = new TokenClient("https://myidserver", "myclientid", "myclientsecret")) 
    { 
     var response = tokenClient.RequestClientCredentialsAsync("myscope"); 
     idToken = response.Result; 
     log.Info($"Access token retrieved : {idToken.AccessToken}"); 
    } 

    using (var apiClient = new HttpClient()) 
    { 
     var apiUrl = "https://myapiurl/"; 
     var endpoint = "myendpoint"; 
     string data = JsonConvert.SerializeObject(myQueueItem); 
     log.Info($"Hitting API..."); 

     apiClient.SetBearerToken(idToken.AccessToken); 
     var response = apiClient.PostAsync($"{apiUrl}{endpoint}", new StringContent(data, Encoding.UTF8, "application/json")).Result; 
    } 
} 

Voici ma fonction en tant que classe C#, cela jette l'erreur ci-dessus sur l'appel SetBearerToken:

using System; 
using System.Text; 
using System.Threading.Tasks; 
using System.Net.Http; 

using IdentityModel.Client; 
using Microsoft.Azure.WebJobs.Host; 
using Newtonsoft.Json; 
using Sorbet.DataTransferObjects; 

namespace FunctionsClassLibTest 
{ 
    public class NotificationQueueTrigger 
    { 
     public static void Run(NotificationDto myQueueItem, TraceWriter log) 
     { 
      log.Info($"C# ServiceBus queue trigger function processed message"); 
      TokenResponse idToken; 
      using (var tokenClient = new TokenClient("https://myidserver", "myclientid", "myclientsecret")) 
      { 
       var response = tokenClient.RequestClientCredentialsAsync("myscope"); 
       idToken = response.Result; 
       log.Info($"Access token retrieved : {idToken.AccessToken}"); 
      } 

      using (var apiClient = new HttpClient()) 
      { 
       var apiUrl = "https://myapiurl"; 
       var endpoint = "myendpoint"; 
       string data = JsonConvert.SerializeObject(myQueueItem); 
       log.Info($"Hitting API..."); 

       apiClient.SetBearerToken(idToken.AccessToken); 
       var response = apiClient.PostAsync($"{apiUrl}{endpoint}", new StringContent(data, Encoding.UTF8, "application/json")).Result; 
      } 
     } 
    } 
} 

Et voici mon fichier function.json pour ma fonction précompilée (la CSX est presque la même mais elle n'a que la section des liaisons)

{ 
    "scriptFile": "..\\bin\\FunctionsClassLibTest.dll", 
    "entryPoint": "FunctionsClassLibTest.NotificationQueueTrigger.Run", 
    "bindings": [ 
    { 
     "name": "myQueueItem", 
     "type": "serviceBusTrigger", 
     "direction": "in", 
     "queueName": "notifications", 
     "connection": "dev-bus", 
     "accessRights": "manage" 
    } 
    ], 
    "disabled": false 
} 
+0

Apparemment, 'IdentityModel.dll' ne se charge pas correctement. Comment faites-vous référence? D'un côté, essayez de minimiser votre échantillon de code au minimum nécessaire pour reproduire le problème. – Mikhail

+0

Merci Mikhail. Je n'ai posté que du code complet cette fois-ci parce qu'il me semble que c'est un problème si étrange, un de ceux qui pourraient être à quelque chose de minuscule! IdentityModel a été ma première pensée aussi, mais il semble que je passe les choses d'IdentityModel d'accord, c'est le truc dans la première instruction using qui va à mon serveur d'identification et obtient mon jeton. Il tombe sur l'appel à SetBearerToken dans la deuxième instruction using qui est une méthode d'extension pour HttpClient dans System.Net.Http.HttpClientExtensions avec une exception MissingMethod – yellowbrickcode

+0

Ah, oui, mon mauvais - il se plaint de 'HttpClientExtensions' en effet.Vous voyez pourquoi j'ai demandé un plus petit exemple;) Vous êtes toujours dans la meilleure position pour essayer de supprimer certaines parties de la fonction (par exemple IdentityServer) et voir si cela change le résultat ou non - et ajuster votre question en conséquence. – Mikhail

Répondre

1

Ok, donc j'ai trouvé une solution pour ça. Le problème était où je pensais qu'il aurait pu être juste au début, dans la bibliothèque IdentityModel. J'ai été jeté par l'espace de noms que l'erreur a été jeté à partir de laquelle m'a envoyé sur une chasse aux oies sauvage pendant quelques heures. En fait, les extensions de HttpClient étaient définies dans la bibliothèque IdentityModel. Sachant exactement où le problème était en réalité, j'ai regardé les extensions et juste remplacé la ligne apiClient.SetBearerToken("mytoken"); avec le code utilisé dans cette méthode d'extension apiClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "mytoken); et cela fonctionne maintenant dans ma fonction précompilée.

Cela ne répond pas à la question de pourquoi cela fonctionne dans le CSX et pas la fonction précompilée cependant. Si quelqu'un a des idées sur pourquoi cela pourrait être, je serais vraiment intéressé de savoir! Je sais que ce n'est pas un problème avec l'importation de la bibliothèque IdentityModel car j'utilise cela pour obtenir le jeton de mon serveur d'ID et ça marche bien, donc ça doit être quelque chose de spécifique aux méthodes d'extension. Les méthodes d'extension en question peuvent être vues ici - https://github.com/IdentityModel/IdentityModel/blob/master/source/IdentityModel.Shared/Client/HttpClientExtensions.cs

+0

Il serait intéressant de voir quelle version de System.Net.Http vous référencez à partir de votre fonction pré-compilée. Nous sommes peut-être confrontés à des incompatibilités de type conduisant à un échec de liaison à ces méthodes lors de l'exécution. –

+0

Voici l'élément de mon 'packages.config'. C'était juste la version installée quand j'ai créé le projet '' – yellowbrickcode

+0

Désolé, je viens de remarquer que le System.Net Le paquet .Http est installé en tant que dépendance du paquet IdentityModel donc il n'est pas là depuis la création du projet. – yellowbrickcode