Fermer

avril 25, 2018

Une expérience avec Markdown et Blazor


Blazor + Markdown = BlazeDown

BlazeDown est un preuve de concept pour un éditeur en ligne Markdown construit sur Blazor . C'est juste une expérience; Je voulais botter les pneus de Blazor. Il n'est nullement destiné à être un produit ou un exemple de meilleures pratiques. Je voulais démontrer que c'est possible et c'est tout.

 http://www.telerik.com/

Une démo en direct de BlazeDown est disponible ici: http: // edcharbeneau .com / BlazeDown / . Le dépôt de cette démo est disponible sur GitHub: BlazeDown .

Client-Side C #

BlazeDown a été construit en utilisant Blazor, un framework expérimental côté client applications utilisant .NET et C #. C'est vrai, cette application a été créée avec .NET et fonctionne nativement dans le navigateur en utilisant WebAssembly .

Grâce à Blazor, l'application ne nécessite aucun plugin. En effet, le code est compilé dans WebAssembly, ce que votre navigateur comprend. Presque tout ce que vous voyez ici a été écrit en .NET en utilisant C # avec quelques exceptions. Puisque Blazor est dans la phase expérimentale (je ne peux pas le souligner assez) quelques petites solutions de contournement sont requises pour certains traits.

Building BlazeDown

Cette expérience devait tester Blazor et voir comment facile (ou difficile) c'était d'utiliser une bibliothèque .NET Standard sur le client. La beauté de BlazeDown est que l'écriture d'un analyseur Markdown était complètement inutile car il existait déjà pour .NET.

Le Markdown Processor

BlazeDown tire parti de l'écosystème .NET. Il utilise le MarkDig comme un processeur Markdown extensible pour .NET. Depuis MarkDig est compatible avec .NET Standard 1.1+, il a fonctionné parfaitement avec Blazor. La liberté de réutiliser les bibliothèques .NET existantes sur le client est à mon avis ce qui fait de Blazor une option intéressante pour les développeurs.

L'utilisation de MarkDig dans Blazor suivait la procédure standard de saisie du paquet depuis NuGet . Une fois le paquet installé, MarkDig est initialisé comme dans n'importe quelle autre application .NET

Il suffit d'appeler la méthode ToHtml de MarkDig pour convertir une chaîne en HTML:

 @using Markdig;

chaîne privée RenderHtmlContent (valeur de chaîne) => Markdig.Markdown.ToHtml (
  démarque: valeur,
  pipeline: nouveau MarkdownPipelineBuilder (). UseAdvancedExtensions (). Build ()
Pour compléter l'expérience, Blazor a été utilisé pour charger les fichiers Markdown  .md  en externe. Une fois de plus, .NET a été utilisé pour ajouter la fonctionnalité sans sauter directement en JavaScript en utilisant  System.Net.Http  et  Http.GetAsync . 

Le code pour utiliser Http.GetAsync est assez similaire à comment il serait utilisé dans une application .NET typique. Un HttpResponseMessage est créé pour effectuer l'appel à la ressource en utilisant GetAsync . Une fois la réponse renvoyée, nous vérifions si la réponse a réussi en utilisant httpResponse.IsSuccessStatusCode . Enfin, le fichier de démarque qui en résulte est retourné, ou un message d'erreur est transmis le long wait httpResponse.Content.ReadAsStringAsync (): httpResponse.ReasonPhrase .

Bien que ces routines sont tous familiers, il est à noter que certaines abstractions peuvent être présentes dans Blazor pour invoquer JavaScript sous le capot afin de rendre la requête HTTP réelle

 protected override async Task OnInitAsync ()
{
  if (Contenu == null)
    Content = String.IsNullOrEmpty (FromUrl)?
      "La propriété Content ou FromUrl n'est pas définie ou n'est pas valide": await InitContentFromUrl ();
}

tâche asynchrone privée  InitContentFromUrl ()
{
  HttpResponseMessage httpResponse = wait Http.GetAsync (FromUrl);
  Renvoie httpResponse.IsSuccessStatusCode?
    wait httpResponse.Content.ReadAsStringAsync (): httpResponse.ReasonPhrase;
} 

Le composant

Pour expérimenter pleinement ce que Blazor a à offrir dans son état actuel, le modèle de composant Blazor a été utilisé pour créer un composant . Le composant est capable de recevoir une chaîne simple ou d'extraire des données d'une ressource externe.

La propriété Content est utilisée pour définir une chaîne simple comme le Markdown à rendre en HTML:

Ceci génère le balisage suivant:

Hello World

La propriété FromUrl définit une URL pour le composant à extraire des données à partir de:

 < Markdown   Contenu  =  ] " /helloworld.md "  > 

Cela génère le même balisage sauf à partir d'un emplacement différent:

 < h1 >  Bonjour World  </  h1 > 

Le modèle de composant de Blazor suit des principes similaires aux frameworks JavaScript modernes comme Angular. Chaque composant a un modèle HTML - dans le cas de Blazor, nous utilisons le format .cshtml de Razor. En plus du modèle, le code du composant est encapsulé comme C #.

La structure du composant Markdown est assez simple. Les propriétés et les méthodes du composant sont liées et rendues à l'aide de Razor. En créant des propriétés publiques Content et FromUrl ces valeurs sont reconnues comme propriétés de composant lorsque nous écrivons .

Lorsque le composant est créé, il doit extraire une ressource un est défini dans la propriété FromUrl . Raconter Blazor pour initialiser une extraction lorsque le composant se charge est aussi simple que de surcharger le comportement OnInitAsync de la classe de base du composant:

 // Markdown.cshtml
@if (Content == null)
{
   Chargement en cours ... 
}
autre
{
  
@RenderHtml ()   
} chaîne publique Contenu {get; ensemble; } chaîne publique FromUrl {get; ensemble; } override protégé async Tâche OnInitAsync () {   if (String.IsNullOrEmpty (Contenu))     Content = String.IsNullOrEmpty (FromUrl)?       "La propriété Content ou FromUrl n'est pas définie ou n'est pas valide": await InitContentFromUrl (); } tâche asynchrone privée InitContentFromUrl () {   HttpResponseMessage httpResponse = wait Http.GetAsync (FromUrl);   Renvoie httpResponse.IsSuccessStatusCode?     wait httpResponse.Content.ReadAsStringAsync (): httpResponse.ReasonPhrase; } chaîne privée RenderHtmlContent () => Markdig.Markdown.ToHtml (   markdown: Contenu,   pipeline: nouveau MarkdownPipelineBuilder (). UseAdvancedExtensions (). Build ()

Le code ci-dessus représente le code idéal pour le composant

The Bad Parts

Le code idéal mentionné ci-dessus a nécessité quelques hacks, rappelez-vous qu'il s'agit d'un 0.2.0 release et Blazor est très tôt dans le développement. Parcourir le code source sur GitHub révélera que beaucoup plus se passe dans les coulisses

Rendu HTML brut

Le premier problème majeur est que le HTML brut ne peut pas être rendu avec Blazor. Cela signifie que lorsque MarkDig appelle ToHtml le code HTML littéral est rendu à l'écran sous forme de chaîne, ex:

Même les balises H1 sont visibles

. Afin de rendre le rendu HTML brut correctement, deux méthodes sont utilisées

Tout d'abord, un hack vilain est nécessaire pour afficher le code HTML lorsque le composant est initialisé. Étant donné que le DOM n'a pas encore rendu, nous ne pouvons même pas utiliser correctement JavaScript pour lutter contre ce problème. Le code réel s'attache à l'événement onerror d'une image pour forcer le rendu HTML via JavaScript:

  
  

Deuxièmement, lorsque la propriété Content est définie, JavaScript est appelé via interop pour trouver le conteneur de notre composant afin de rendre le code HTML directement au DOM:

 public string
{
  obtenir {return content; }
  ensemble
  {
    content = valeur;
    if (isComponentInitialized)
      // Une fois ce problème résolu, https://github.com/aspnet/Blazor/issues/167
      // alors l'interop ne sera plus nécessaire. Cela prendra également soin
      // de ce boiteux <img hack dans le balisage ci-dessus. Une fois la sortie HTML brute est
      // disponible, le composant utilisera simplement la fonction RenderHtmlContent
      // directement à partir de Razor.
      HtmlRendererInterop.RenderMarkdownAsHtml (RenderHtmlContent (valeur));
  }
} 
 Blazor.registerFunction ('MarkdownComponent.HtmlRendererInterop.RenderMarkdown', fonction (message) {
  laissez el = document.getElementById ("markdown-component");
  if (el) {el.innerHTML = message; }
  autre {
    console.log ("HTML non rendu");
  }
}); 

En dépit d'être à la fois laide et plutôt cool en même temps, c'est nécessaire. Blazor a encore beaucoup de travail pour éliminer le besoin d'interop et de hacks excentriques comme ceux-ci.

Liaison de données dans Blazor

En plus des hacks de rendu, la liaison de données est encore relativement nouvelle et changeante en 0.2.0. La liaison de données fonctionne dans Blazor par des conventions simples, faciles à comprendre et à mettre en œuvre. Voici l'exemple montré dans l'article MSDN célébrant la version 0.2.0 :

 @ * dans Counter.cshtml * @
... html omis pour la brièveté ...
@les fonctions {   public int Value {get; ensemble; } = 1;   action publique ValueChanged {get; ensemble; } } @ * dans un autre fichier * @ @les fonctions {   public int CurrentValue {get; ensemble; } }

BlazeDown utilise la liaison de données pour mettre à jour l'aperçu HTML lorsqu'un utilisateur saisit du contenu dans un