L’Integration Account est un service Azure qui permet de gérer des composants d’intégration de type « schéma » ou « map ». Ces artefacts peuvent être ensuite utilisés dans des Logic Apps pour valider la forme d’un message ou encore réaliser des transformations (mapping). L’Integration Account est un service qui peut représenter un coût conséquent pour le run d’un projet. C’est pourquoi ici je vais vous faire part d’une alternative peu coûteuse à l’Integration Account. Nous allons utiliser des fonctions Azure pour exécuter nos transformations XSLT.
Il y a plusieurs raisons à cela :
Pour exécuter les feuilles XSLT que nous allons mettre à disposition, nous allons utiliser la classe XslCompiledTransform qui permet de charger une feuille XSLT, la compiler, configurer son exécution et récupérer le résultat.
var xsl = new XslCompiledTransform(); var mapsFolder = Path.GetFullPath(Path.Combine(GetScriptPath(), "maps")); var xsltFullPath = Path.GetFullPath(Path.Combine(mapsFolder, $"{name}.xslt")); // Ajout des configurations d'execution du XML XmlReaderSettings settings = new XmlReaderSettings(); settings.IgnoreWhitespace = true; settings.IgnoreComments = true; // Creation du reader XML XmlReader reader = XmlReader.Create(xsltFullPath, settings); // Configuration d'execution de la XSLT XsltSettings sets = new XsltSettings(true, false); var resolver = new XmlUrlResolver(); // Chargement de la map xsl.Load(reader, sets, resolver); string result = null; if(!String.IsNullOrWhiteSpace(xml)) { using (StringReader sri = new StringReader(xml)) { using (XmlReader xri = XmlReader.Create(sri)) { // Utilisation des paramètres de sortie XSLT afin d'avoir une sortie en HTML using (StringWriter sw = new StringWriter()) using (XmlWriter xwo = XmlWriter.Create(sw, xsl.OutputSettings)) { xsl.Transform(xri, xwo); result = sw.ToString(); } } } }
L’idée en utilisant ce code est de rendre le nom de la feuille XSLT à exécuter dynamique. Il suffira d’utiliser la même fonction Azure pour appeler toutes nos feuilles de transformations. Seul le paramètre « name » devra changer.
En somme, cette fonction Azure aura besoin de 2 paramètres :
Le code complet de la fonction est le suivant :
using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System.Xml.Xsl; using System.Xml; namespace IntegrationAsAFunction.Functions { public static class ExecuteXSLT { [FunctionName("ExecuteXSLT")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); string name = req.Query["name"]; string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); dynamic data = JsonConvert.DeserializeObject(requestBody); name = name ?? data?.name; string xml = req.Query["xml"]; xml = xml ?? data?.xml; var xsl = new XslCompiledTransform(); var mapsFolder = Path.GetFullPath(Path.Combine(GetScriptPath(), "maps")); var xsltFullPath = Path.GetFullPath(Path.Combine(mapsFolder, $"{name}.xslt")); log.LogInformation("Creating settings..."); XmlReaderSettings settings = new XmlReaderSettings(); settings.IgnoreWhitespace = true; settings.IgnoreComments = true; log.LogInformation("Creating reader..."); XmlReader reader = XmlReader.Create(xsltFullPath, settings); log.LogInformation("Creating xsl settings"); XsltSettings sets = new XsltSettings(true, false); log.LogInformation("Creating xsl url resolver"); var resolver = new XmlUrlResolver(); log.LogInformation("Loading the XSL"); xsl.Load(reader, sets, resolver); string result = null; if(!String.IsNullOrWhiteSpace(xml)) { log.LogInformation("Found XML"); using (StringReader sri = new StringReader(xml)) // xmlInput is a string that contains xml { using (XmlReader xri = XmlReader.Create(sri)) { using (StringWriter sw = new StringWriter()) using (XmlWriter xwo = XmlWriter.Create(sw, xsl.OutputSettings)) // use OutputSettings of xsl, so it can be output as HTML { log.LogInformation("Transforming: {xml}", xml); xsl.Transform(xri, xwo); result = sw.ToString(); } log.LogInformation("Result: {result}", result); } } } return name != null ? (ActionResult)new OkObjectResult($"{result}") : new BadRequestObjectResult("Please pass a name on the query string or in the request body"); } #region GETS private static string GetScriptPath() => Path.Combine(GetEnvironmentVariable("HOME"), @"site\wwwroot"); private static string GetEnvironmentVariable(string name) => System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process); #endregion } }
Cette fonction s’attend à avoir un dossier « maps » qui contiendra toutes les fichiers XSLT disponibles à l’exécution.
La structure de mon projet est la suivante :
Il faut ensuite bien ajouter la référence vers chaque XSLT dans le fichier .csproj :
C’est ce qui va permettre lors du déploiement, le stockage des XSLT dans le dossier « maps/ » du système de fichier de l’application de fonction.
Une fois le déploiement réalisé nous pouvons maintenant tester cette fonction avec Postman par exemple. Celle-ci va nous retourner directement le résultat de la transformation sous forme de document XML :
L’exécution d’une map est rapide et peu coûteuse à mettre en place dans une Application de Fonction. De plus, cette approche permet un déploiement automatisé très simple contrairement à l’Integration Account. Comme tout autres fonctions Azure, celle-ci profite de toutes les fonctionnalités de scalabilité horizontale et de haute disponibilité.
Limitations connues :