Blazor : ma première application (javascript et service)

Update v0.2

Série d'article sur Blazor :

Avant d'aller plus avant dans les différents concepts de Blazor, un point important est : comment développer sereinement ?

Je dis ca car pour l'instant, impossible de mettre le moindre point d'arrêt dans votre code .NET de votre appli Blazor. Vous allez me dire : fais des logs, des traces, c'est mieux.

Ok, puisque vous le prenez comme cela.

Donc personnellement, pour "deboguer" une appli javascript/typescript, j'utilise à fond la console du navigateur. Cela permet de ne pas interrompre le déroulement de l'application et de voir ce qu'il se passe dans le panel des outils du développeur du navigateur (F12).

Il faut donc pouvoir appeler les méthodes de l'objet javascript console, donc généralement savoir appeler une méthode javascript depuis son code C#.

Interop Javascript

Pour cela, Blazor vous permet d'enregistrer un script, une fonction :

<script type="text/javascript">
    Blazor.registerFunction('mafonction', () => {
        console.log('coucou');
        return true;
    });
</script>

On enregistre ici la fonction javascript 'mafonction' qui sera appelable (invokable ;-)) depuis le code C# ainsi :

void AppelJs()
{
    Microsoft.AspNetCore.Blazor.Browser.Interop.RegisteredFunction.Invoke<bool>("mafonction");
}

NB : En interne, la méthode Invoke appele une méthode du runtime de Mono qui se charge réellement de l'interop.

Service

C'est bien beau mais c'est un peu "craspouille" comme code. On va donc essayer de le "professionaliser". Pour cela, je vais dans un premier temps créer un service dans mon application que je nommerais ConsoleService :

using Microsoft.AspNetCore.Blazor.Browser.Interop;
 
namespace MaPremiereAppliBlazor.Services
{
    public class ConsoleService
    {
        // retourne MaPremiereAppliBlazor.Services.ConsoleService
        private string Prefix => GetType().FullName;
 
        /// <summary>
        /// Permet d'ajouter un log dans la console du navigateur
        /// </summary>
        /// <param name="message">Le message</param>
        public void Log(string message)
        {
            if (string.IsNullOrEmpty(message)) return;
 
            RegisteredFunction.Invoke<bool>(Prefix + ".log", message);
        }
 
        /// <summary>
        /// Permet d'ajouter un log dans la console du navigateur
        /// </summary>
        /// <param name="sender">L'objet appelant par convention</param>
        /// <param name="message">Le message</param>
        /// <remarks>Log dans la console: [NomDuTypeAppelant] message</remarks>
        public void Log(object sender, string message)
        {
            if (message == nullreturn;
            if (sender == null) Log(message);
            Log($"[{sender.GetType().Name}{message}");
        }
 
        /// <summary>
        /// Vide la console
        /// </summary>
        public void Clear()
        {
            RegisteredFunction.Invoke<bool>(Prefix + ".clear");
        }
    }
}

Remarquez que ce service invoque des méthodes javascript dont les noms sont :

  • MaPremiereAppliBlazor.Services.ConsoleService.log(message)
  • MaPremiereAppliBlazor.Services.ConsoleService.clear()

Je vais ensuite enregistrer ces méthodes dans la liste des méthodes invocables en les ajoutant dans la page MainLayout.cshtml :

@implements ILayoutComponent
 
<div class='container-fluid'>
    <div class='row'>
        <div class='col-sm-3'>
            <NavMenu />
        </div>
        <div class='col-sm-9'>
            @Body
        </div>
    </div>
</div>
 
<script type="text/javascript">
    var prefix = "SimpleCrudBlazor.Client.Services.ConsoleService";
    Blazor.registerFunction(prefix + '.log', message => {
        console.log(message);
        return true;
    });
    Blazor.registerFunction(prefix + '.clear', () => {
        console.clear();
        return true;
    });
</script>
 
@functions {
public RenderFragment Body { getset; }
}

Injection de dépendance

Reste maintenant à enregistrer notre service dans le moteur d'injection de dépendance dans le Main de notre Program :

using Microsoft.AspNetCore.Blazor.Browser.Rendering;
using Microsoft.AspNetCore.Blazor.Browser.Services;
using MaPremiereAppliBlazor.Services;
using Microsoft.Extensions.DependencyInjection;
 
namespace MaPremiereAppliBlazor
{
    class Program
    {
        static void Main(string[] args)
        {
            var serviceProvider = new BrowserServiceProvider(configure =>
            {
                configure.Add(ServiceDescriptor.Singleton<ConsoleServiceConsoleService>());
            });
 
            new BrowserRenderer(serviceProvider).AddComponent<App>("app");
        }
    }
}

Voila, tout est prêt. Il suffit dans n'importe quel composant de notre application d'utiliser le moteur d'injection pour utiliser notre service. Dans une page, un Component quelconque, le framework Blazor nous permet d'utiliser la directive @inject :

@using System.Globalization
@using MaPremiereAppliBlazor.Services
@page "/counter"
@inject ConsoleService ConsoleService
<h1>Counter</h1>
 
<p>Current count: @currentCount</p>
<p>Increment value: <input bind="@IncrementValue" type="number" /></p>
 
<button onclick="@(() => IncrementCount())">Click me</button>
 
@functions {
    int currentCount = 0;
    private int _incrementValue = 1;
 
    public string IncrementValue
    {
        get { return _incrementValue.ToString(CultureInfo.InvariantCulture); }
        set { int.TryParse(valueout _incrementValue); }
    }
 
    void IncrementCount()
    {
        ConsoleService.Log($"Ancienne valeur de currentCount: {currentCount}");
        currentCount+= _incrementValue;
        ConsoleService.Log($"Nouvelle valeur de currentCount: {currentCount}");
    }
}

Grâce à mes 2 signatures de la méthode log, je peux même faire plus explicite en tapant :

void IncrementCount()
{
    ConsoleService.Log(this$"Ancienne valeur de currentCount: {currentCount}");
    currentCount+= _incrementValue;
    ConsoleService.Log(this$"Nouvelle valeur de currentCount: {currentCount}");
}

Ce qui donne dans le navigateur :

C'est plus cool non ?

blog comments powered by Disqus