Récemment, on nous a demandé de migrer quelques flux de données fonctionnant sur un logiciel propriétaire vers Azure. Les flux n’étaient pas compliqués ; la seule particularité était que nous devions appeler certaines fonctions SAP RFC. Comme nous avons déjà mis en œuvre plusieurs workflows Logic Apps en utilisant des connecteurs SAP capables de faire de tels appels, nous n’avons pas vu de problème. Cependant, lorsque nous avons essayé de nous connecter à l’instance SAP cible, nous avons reçu le message d’erreur suivant : « Required parameters ‘[rfcGroupFilter]’ not set or invalid« . Nous avons revérifié les paramètres de connexion, puis les logs d’erreur sur la data gateway on-premise, mais nous n’avons rien trouvé d’anormal. Mais lorsque nous avons comparé côte à côte la Logic App qui fonctionne correctement avec celle qui nous donne l’erreur, nous avons réalisé que dans le cas de l’erreur, nous ciblons une version différente (plus ancienne) de SAP et qu’il pourrait y avoir un problème de compatibilité.
Comme nous n’avons pas réussi à trouver comment le faire dans une Logic App, nous avons commencé à chercher une autre solution. Ne serait-il pas possible de le faire avec Azure Function ? Voyons rapidement ce que nous savons, et ce dont nous avons besoin pour cela :
Commençons par le provisionnement des ressources Azure. Tout d’abord, j’ai provisionné une Azure Function App hébergée sur un App Service Plan et j’ai créé la connexion hybride à SAP. Le port SAP par défaut est 3300, mais il peut varier en fonction de la configuration. Si vous avez besoin d’aide pour créer la connexion hybride, vous pouvez trouver des informations dans un article que j’ai écrit il y a quelque temps (https://www.middleway.eu/using-azure-hybrid-connections/).
Nous pouvons maintenant créer et déployer notre fonction. Dans mon cas, j’ai créé la fonction avec Visual Studio en utilisant le template pour Azure Functions et en choisissant Function worker : « .NET Framework Isolated v4 ».
Une fois le projet de fonction créé, nous devons ajouter les références NCo comme indiqué précédemment. Vous pouvez soit installer la dernière version officielle du connecteur NCo 3.0 depuis le site web de SAP (vous aurez besoin du compte client SAP pour le télécharger), soit l’installer en tant que paquet NuGet. Par exemple, le package sapnco_x64 fait le job :
Ce package NuGet ne contient pas la dernière version du NCo mais ce n’est pas grave. Nous avons tout ce qu’il faut pour commencer à mettre en œuvre notre Azure Function qui peut effectuer des appels SAP.
L’implémentation de la fonction Azure pour appeler la fonction SAP RFC ne diffère pas beaucoup de l’implémentation d’autres types d’applications .NET. Le code fonctionnel est simplement placé dans le trigger de la fonction. Dans notre démo, nous allons créer une fonction HTTP trigger où je vais :
[Function("SapRfcCallDemo")] public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req) { // Reading input JSON with parameters dynamic inputParameters = await req.ReadFromJsonAsync<dynamic>(); HttpResponseData response = req.CreateResponse(); response.Headers.Add("Content-Type", "text/plain; charset=utf-8"); try { // Setting up the connection parameters RfcConfigParameters rfcPar = new RfcConfigParameters(); rfcPar.Add(RfcConfigParameters.Name, "ApplicationServer"); rfcPar.Add(RfcConfigParameters.Client, "100"); rfcPar.Add(RfcConfigParameters.User, "sap_user_name"); rfcPar.Add(RfcConfigParameters.Password, "sap_user_password"); // The server host is the same as the one in hybrid connection rfcPar.Add(RfcConfigParameters.AppServerHost, "demosap.domain.com"); rfcPar.Add(RfcConfigParameters.AppServerService, "sapservice"); rfcPar.Add(RfcConfigParameters.SystemNumber, "00"); rfcPar.Add(RfcConfigParameters.Language, "en"); rfcPar.Add(RfcConfigParameters.SncQOP, "Authentication"); // Create the destination RfcDestination dest = RfcDestinationManager.GetDestination(rfcPar); RfcRepository rfcRepository = dest.Repository; IRfcFunction sapFunction = rfcRepository.CreateFunction("MY_RFC_FUNCTION"); sapFunction.SetValue("I_PARAM1", inputParameters.param1); sapFunction.SetValue("I_PARAM2", inputParameters.param2); sapFunction.SetValue("I_PARAM3", inputParameters.param3); // Calling the RFC function sapFunction.Invoke(dest); // Obtaining the result var result = sapFunction.GetTable("MY_RESULT_TABLE"); response.StatusCode = HttpStatusCode.OK; if (result != null) { response.WriteString(result.ToString()); } } catch (Exception ex) { response.StatusCode = HttpStatusCode.InternalServerError; response.WriteString(ex.Message.ToString()); _logger.LogError($"Error occured: {ex.Message}"); } return response; }
Les paramètres d’entrée et la configuration doivent bien sûr être adaptés à vos besoins. Il en va de même pour l’analyse des résultats. Notez que la valeur du paramètre AppServerHost doit être la même que celle spécifiée dans la connexion hybride.
Ce qui est important de mentionner est que la fonction doit être compilée pour une plateforme cible spécifique afin que le connecteur NCo fonctionne correctement. Dans mon cas, je destine la compilation à la plateforme « x64« . Le code compilé pour « Any CPU » ne fonctionnera pas.
Appeler des fonctions SAP RFC en utilisant Azure Function est un peu plus laborieux que d’utiliser le connecteur Logic App. Cependant, notre solution avec Azure Function nous a aidées à surmonter les problèmes de compatibilité que nous avions. Nous avons également pu bénéficier de l’exécution d’Azure Function dans un process isolé. Il découple les fonctions .NET de l’hôte Azure Functions, ce qui nous a permis d’utiliser .NET Framework 4.x et NCo tout en étant en mesure d’utiliser la dernière interface de trigger d’Azure Function et de la déployer sur la dernière version d’Azure Function v4.