Les métadonnées OpenGraph sont des données qui permettent (notamment) de créer une prévisualisation pour un lien lorsqu’on le partage sur Internet.

Plus d’infos dans notre article dédié à OpenGraph : https://code-garage.fr/blog/comment-personnaliser-le-partage-de-votre-site-sur-les-reseaux-sociaux-avec-opengraph

Si vous gérer des liens dans votre logiciel, vous avez sûrement envie de pouvoir faire une prévisualisation comme ceci :

open-graph.JPG

Etape 1 : Préparer le projet

Pour mener le projet à bien, vous allez avoir besoin de deux modules :

using System.Web; //Utilisé pour charger la page
using HtmlAgilityPack; //Utilisé pour parser la page

Pour HtmlAgilityPack vous devrez l’installer via votre gestionnaire de paquets NuGet

Ensuite on va préparer un modèle de données simple pour accueillir nos métadonnées Open Graph, comme ceci :

public record LinkPreview
{
    public int? Id { get; set; }
    public string Url { get; init; } = String.Empty;
    public string Title { get; init; } = String.Empty;
    public string Description { get; init; } = String.Empty;
    public string ImageUrl { get; init; } = String.Empty;
    public string SiteName { get; init; } = String.Empty;
    public DateTime LastUpdate { get; init; }
}

Puis on va déclarer notre classe OpenGraphLoader et sa fonction principale qui prendra une url en entrée et retournera (s’il existe), une instance de LinkPreview :

public class OpenGraphLoader 
{
	readonly HttpClient _client;

	public OpenGraphLoader ()
    {
		// Initialisation de notre client HTTP
		_client = new HttpClient();
    }

	public async Task<LinkPreview?> GetLinkPreview(string url)
	{
		return null;
	}
}

Notre classe va contenir une instance d’un client HTTP pour pouvoir faire la requête faire la page web.

Pour l’instant, la fonction principale est vide, et nous allons maintenant écrire la logique ce celle-ci !

Etape 2 : Charger la page web

Pour charger le contenu HTML de notre page web, il va falloir utiliser le client HTTP préalablement initialisé, et lui passer notre URL.

Le contenu de la réponse est simplement une suite d’octets, il va donc falloir re-transformer ces octets en String pour retrouver notre code HTML :

public async Task<LinkPreview?> GetLinkPreview(string url)
{
	// Exécute la requête vers l'url de la page web
	var response = await _client.GetAsync(url);
	// Parse le corps de la réponse (la page) en string
	var html = await response.Content.ReadAsStringAsync();

	/* 
		Ici nous allons parser 
		nos métadonnées 
	*/

	return null;
}

Il ne nous reste plus qu’à utiliser fouiller dans ce code HTML à la recherche de nos métadonnées et de leurs valeurs

Etape 3 : Parser les métadonnées

Pour cette étape nous allons utiliser le paquet HtmlAgilityPack qui va nous permettre de charger le code HTML pour le transformer en un vrai document HTML que nous allons pouvoir parcourir :

// Charge le contenu HTML dans un HtmlDocument
var doc = new HtmlDocument();
doc.LoadHtml(html);

Puis on va pouvoir sélectionner les éléments HTML qui nous intéressent (les fameuses balises OpenGraph), et récupérer leurs valeurs une à une :

// Sélectionne tous les éléments <meta> avec l'attribut property="og:*"
var metaTags = doc.DocumentNode.SelectNodes("//meta[starts-with(@property, 'og:')]");

// Créer un dictionnaire pour stocker tous les noms des éléments et leur valeur
var openGraphData = new Dictionary<string, string>();

// Extrait les données et les ajoute au dictionnaire une par une
if (metaTags != null)
{
    foreach (var tag in metaTags)
    {
        var property = tag.GetAttributeValue("property", "");
        var content = tag.GetAttributeValue("content", "");
        if (!string.IsNullOrEmpty(property) && !string.IsNullOrEmpty(content))
        {
            // Supprime le prfixe 'og:' du nom de la propriété
            property = property.Replace("og:", "");
            openGraphData[property] = content;
        }
    }
} else {
	return null;
}

Dans le cas où aucune balise og:* n’est trouvée, la fonction retournera null , mais vous pouvez décider de renvoyer un LinkPreview vide à la place !

Et enfin, il ne reste plus qu’à passer toutes ces données à notre objet LinkPreview (si des métadonnées ont été trouvées) et à le retourner à la fin de notre fonction :

return new LinkPreview()
{
    Url = url,
    Title = openGraphData["title"],
    Description = openGraphData["description"],
    ImageUrl = openGraphData["image"],
    SiteName = openGraphData["site_name"],
    LastUpdate = DateTime.Now
};

Et voilà ! Vous pouvez désormais récupérer les balises Open Graph de n’importe quelle page web (à condition qu’elles existent) !

Et vous pouvez bien évidemment adapter ce code pour récupérer d’autres informations présentes sur la page.

Le code complet

Voici l’entièreté du code de ce tutoriel, avec tous les commentaires :

using System.Web; //Utilisé pour charger la page
using HtmlAgilityPack; //Utilisé pour parser la page

namespace App;

public record LinkPreview
{
    public int? Id { get; set; }
    public string Url { get; init; } = String.Empty;
    public string Title { get; init; } = String.Empty;
    public string Description { get; init; } = String.Empty;
    public string ImageUrl { get; init; } = String.Empty;
    public string SiteName { get; init; } = String.Empty;
    public DateTime LastUpdate { get; init; }
}

public class OpenGraphLoader 
{
	readonly HttpClient _client;

	public OpenGraphLoader ()
  {
		// Initialisation de notre client HTTP
		_client = new HttpClient();
  }

	public async Task<LinkPreview?> GetLinkPreview(string url)
	{
		// Exécute la requête vers l'url de la page web
		var response = await _client.GetAsync(url);
		// Parse le corps de la réponse (la page) en string
		var html = await response.Content.ReadAsStringAsync();

		// Charge le contenu HTML dans un HtmlDocument
		var doc = new HtmlDocument();
		doc.LoadHtml(html);

		// Select all meta tags with property attribute starting with 'og:'
		var metaTags = doc.DocumentNode.SelectNodes("//meta[starts-with(@property, 'og:')]");
		
		// Create a dictionary to store OpenGraph metadata
		var openGraphData = new Dictionary<string, string>();
		
		// Extract content from meta tags and add it to the dictionary
		if (metaTags != null)
		{
		    foreach (var tag in metaTags)
		    {
		        var property = tag.GetAttributeValue("property", "");
		        var content = tag.GetAttributeValue("content", "");
		        if (!string.IsNullOrEmpty(property) && !string.IsNullOrEmpty(content))
		        {
		            // Remove 'og:' prefix from property
		            property = property.Replace("og:", "");
		            openGraphData[property] = content;
		        }
		    }
		} else {
			return null;
		}
	
		return new LinkPreview()
		{
		    Url = url,
		    Title = openGraphData["title"],
		    Description = openGraphData["description"],
		    ImageUrl = openGraphData["image"],
		    SiteName = openGraphData["site_name"],
		    LastUpdate = DateTime.Now
		};
	}
}

Vous pouvez directement copier-coller ce code, mais si vous ne comprenez pas certaines parties, pensez à relire l’entièreté du tutoriel !

Avant de terminer

Chaque url que vous allez prévisualiser pourra prendre plus ou moins de temps à se charger, cela peut donc ralentir votre logiciel.

Vous pouvez évidemment rendre ce traitement non-bloquant, mais ce n’est pas toujours possible selon votre cas d’usage !

L’idéal est de stocker le résultat de ces appels dans une base de donnée (avec comme identifiant l’url), pour créer un cache temporaire, et minimiser le nombre de requêtes (et donc le temps d’exécution) des appels à cette fonction !

Pour lire la suite de ce tutoriel, vous devez posséder un compte gratuit