ASP.NET Core l’interopérabilité avec le JavaScript éblouissantASP.NET Core Blazor JavaScript interop

Par Javier Calvarro Nelson, Daniel Rothet Luke LathamBy Javier Calvarro Nelson, Daniel Roth, and Luke Latham

Une application éblouissant peut appeler des fonctions JavaScript à partir de méthodes .NET et .NET à partir de code JavaScript.A Blazor app can invoke JavaScript functions from .NET and .NET methods from JavaScript code.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)View or download sample code (how to download)

Appeler des fonctions JavaScript à partir de méthodes .NETInvoke JavaScript functions from .NET methods

Il arrive parfois que le code .NET soit requis pour appeler une fonction JavaScript.There are times when .NET code is required to call a JavaScript function. Par exemple, un appel JavaScript peut exposer des fonctionnalités de navigateur ou des fonctionnalités d’une bibliothèque JavaScript à l’application.For example, a JavaScript call can expose browser capabilities or functionality from a JavaScript library to the app.

Pour appeler JavaScript à partir de .net, utilisez IJSRuntime l’abstraction.To call into JavaScript from .NET, use the IJSRuntime abstraction. La InvokeAsync<T> méthode prend un identificateur pour la fonction JavaScript que vous souhaitez appeler, ainsi que n’importe quel nombre d’arguments sérialisables JSON.The InvokeAsync<T> method takes an identifier for the JavaScript function that you wish to invoke along with any number of JSON-serializable arguments. L’identificateur de fonction est relatif à la portée globale (window).The function identifier is relative to the global scope (window). Si vous souhaitez appeler window.someScope.someFunction, l’identificateur est. someScope.someFunctionIf you wish to call window.someScope.someFunction, the identifier is someScope.someFunction. Il n’est pas nécessaire d’inscrire la fonction avant qu’elle ne soit appelée.There's no need to register the function before it's called. Le type T de retour doit également être sérialisable JSON.The return type T must also be JSON serializable.

Pour les applications serveur éblouissantes :For Blazor Server apps:

  • Plusieurs demandes utilisateur sont traitées par l’application serveur éblouissante.Multiple user requests are processed by the Blazor Server app. N’appelez JSRuntime.Current pas dans un composant pour appeler des fonctions JavaScript.Don't call JSRuntime.Current in a component to invoke JavaScript functions.
  • Injectez IJSRuntime l’abstraction et utilisez l’objet injecté pour émettre des appels Interop JavaScript.Inject the IJSRuntime abstraction and use the injected object to issue JavaScript interop calls.
  • Lorsqu’une application éblouissant est prérendue, l’appel à JavaScript n’est pas possible, car une connexion avec le navigateur n’a pas été établie.While a Blazor app is prerendering, calling into JavaScript isn't possible because a connection with the browser hasn't been established. Pour plus d’informations, consultez la section détecter quand une application éblouissant est un prérendu .For more information, see the Detect when a Blazor app is prerendering section.

L’exemple suivant est basé sur TextDecoder, un décodeur basé sur JavaScript expérimental.The following example is based on TextDecoder, an experimental JavaScript-based decoder. L’exemple montre comment appeler une fonction JavaScript à partir d' C# une méthode.The example demonstrates how to invoke a JavaScript function from a C# method. La fonction JavaScript accepte un tableau d’octets d' C# une méthode, décode le tableau et retourne le texte au composant pour l’affichage.The JavaScript function accepts a byte array from a C# method, decodes the array, and returns the text to the component for display.

À l' <head> intérieur de l’élément de wwwroot/index.html (éblouissant webassembly) ou pages/_Host. cshtml (serveur éblouissant), fournissez une TextDecoder fonction qui utilise pour décoder un tableau passé :Inside the <head> element of wwwroot/index.html (Blazor WebAssembly) or Pages/_Host.cshtml (Blazor Server), provide a function that uses TextDecoder to decode a passed array:

<script>
  window.ConvertArray = (win1251Array) => {
    var win1251decoder = new TextDecoder('windows-1251');
    var bytes = new Uint8Array(win1251Array);
    var decodedArray = win1251decoder.decode(bytes);
    console.log(decodedArray);
    return decodedArray;
  };
</script>

Du code JavaScript, tel que le code illustré dans l’exemple précédent, peut également être chargé à partir d’un fichier JavaScript ( . js) avec une référence au fichier de script :JavaScript code, such as the code shown in the preceding example, can also be loaded from a JavaScript file (.js) with a reference to the script file:

<script src="exampleJsInterop.js"></script>

Le composant suivant :The following component:

  • Appelle la ConvertArray fonction JavaScript à l' JsRuntime aide de lorsqu’un bouton de composant (convertir un tableau) est sélectionné.Invokes the ConvertArray JavaScript function using JsRuntime when a component button (Convert Array) is selected.
  • Une fois la fonction JavaScript appelée, le tableau passé est converti en chaîne.After the JavaScript function is called, the passed array is converted into a string. La chaîne est retournée au composant pour l’affichage.The string is returned to the component for display.
@page "/call-js-example"
@inject IJSRuntime JsRuntime;

<h1>Call JavaScript Function Example</h1>

<button type="button" class="btn btn-primary" @onclick="ConvertArray">
    Convert Array
</button>

<p class="mt-2" style="font-size:1.6em">
    <span class="badge badge-success">
        @ConvertedText
    </span>
</p>

@code {
    // Quote (c)2005 Universal Pictures: Serenity
    // https://www.uphe.com/movies/serenity
    // David Krumholtz on IMDB: https://www.imdb.com/name/nm0472710/

    private MarkupString ConvertedText =
        new MarkupString("Select the <b>Convert Array</b> button.");

    private uint[] QuoteArray = new uint[]
        {
            60, 101, 109, 62, 67, 97, 110, 39, 116, 32, 115, 116, 111, 112, 32,
            116, 104, 101, 32, 115, 105, 103, 110, 97, 108, 44, 32, 77, 97,
            108, 46, 60, 47, 101, 109, 62, 32, 45, 32, 77, 114, 46, 32, 85, 110,
            105, 118, 101, 114, 115, 101, 10, 10,
        };

    private async void ConvertArray()
    {
        var text =
            await JsRuntime.InvokeAsync<string>("ConvertArray", QuoteArray);

        ConvertedText = new MarkupString(text);

        StateHasChanged();
    }
}

Pour utiliser l' IJSRuntime abstraction, adoptez l’une des approches suivantes :To use the IJSRuntime abstraction, adopt any of the following approaches:

  • Injecter IJSRuntime l’abstraction dans le composant Razor ( . Razor) :Inject the IJSRuntime abstraction into the Razor component (.razor):

    @inject IJSRuntime JSRuntime
    
    @code {
        public override void OnInitialized()
        {
            StocksService.OnStockTickerUpdated += stockUpdate =>
            {
                JSRuntime.InvokeAsync<object>(
                    "handleTickerChanged",
                    stockUpdate.symbol,
                    stockUpdate.price);
            };
        }
    }
    
  • Injecter IJSRuntime l’abstraction dans une classe ( . cs) :Inject the IJSRuntime abstraction into a class (.cs):

    public class JsInteropClasses
    {
        private readonly IJSRuntime _jsRuntime;
    
        public JsInteropClasses(IJSRuntime jsRuntime)
        {
            _jsRuntime = jsRuntime;
        }
    
        public Task<string> TickerChanged(string data)
        {
            // The handleTickerChanged JavaScript method is implemented
            // in a JavaScript file, such as 'wwwroot/tickerJsInterop.js'.
            return _jsRuntime.InvokeAsync<object>(
                "handleTickerChanged",
                stockUpdate.symbol,
                stockUpdate.price);
        }
    }
    
  • Pour la génération de contenu dynamique avec BuildRenderTree, [Inject] utilisez l’attribut :For dynamic content generation with BuildRenderTree, use the [Inject] attribute:

    [Inject]
    IJSRuntime JSRuntime { get; set; }
    

Dans l’exemple d’application côté client qui accompagne cette rubrique, deux fonctions JavaScript sont disponibles pour l’application qui interagit avec le DOM pour recevoir l’entrée d’utilisateur et afficher un message d’accueil :In the client-side sample app that accompanies this topic, two JavaScript functions are available to the app that interact with the DOM to receive user input and display a welcome message:

  • showPrompt– Génère une invite pour accepter l’entrée d’utilisateur (nom de l’utilisateur) et retourne le nom à l’appelant.showPrompt – Produces a prompt to accept user input (the user's name) and returns the name to the caller.
  • displayWelcomeAssigne un message de bienvenue de l’appelant à un objet DOM avec id un welcomede. –displayWelcome – Assigns a welcome message from the caller to a DOM object with an id of welcome.

wwwroot/exampleJsInterop. js:wwwroot/exampleJsInterop.js:

window.exampleJsFunctions = {
  showPrompt: function (text) {
    return prompt(text, 'Type your name here');
  },
  displayWelcome: function (welcomeMessage) {
    document.getElementById('welcome').innerText = welcomeMessage;
  },
  returnArrayAsyncJs: function () {
    DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
      .then(data => {
        data.push(4);
          console.log(data);
    });
  },
  sayHello: function (dotnetHelper) {
    return dotnetHelper.invokeMethodAsync('SayHello')
      .then(r => console.log(r));
  }
};

Placez la <script> balise qui fait référence au fichier JavaScript dans le fichier wwwroot/index.html (l’assembly éblouissant) ou le fichier pages/_Host. cshtml (serveur éblouissant).Place the <script> tag that references the JavaScript file in the wwwroot/index.html file (Blazor WebAssembly) or Pages/_Host.cshtml file (Blazor Server).

wwwroot/index.html (Webassembly éblouissant) :wwwroot/index.html (Blazor WebAssembly):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Blazor Sample</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/site.css" rel="stylesheet" />
</head>
<body>
    <app>Loading...</app>

    <script src="_framework/blazor.webassembly.js"></script>
    <script src="exampleJsInterop.js"></script>
</body>
</html>

Pages/_Host. cshtml (Serveur éblouissant) :Pages/_Host.cshtml (Blazor Server):

@page "/"
@namespace blazorsample.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Blazor Server Sample</title>
    <base href="~/" />
    <environment include="Development">
        <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" 
            href="{CDN PATH TO bootstrap.min.css}"
            asp-fallback-href="css/bootstrap/bootstrap.min.css"
            asp-fallback-test-class="sr-only" asp-fallback-test-property="position"
            asp-fallback-test-value="absolute" crossorigin="anonymous"
            integrity="{SHA384 HASH}"/>
    </environment>
    <link href="css/site.css" rel="stylesheet" />
</head>
<body>
    <app>@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))</app>

    <script src="_framework/blazor.server.js"></script>
    <script src="exampleJsInterop.js"></script>
</body>
</html>

Ne placez <script> pas de balise dans un fichier de <script> composant parce que la balise ne peut pas être mise à jour dynamiquement.Don't place a <script> tag in a component file because the <script> tag can't be updated dynamically.

Les méthodes .NET interagissent avec les fonctions JavaScript dans le fichier exampleJsInterop. js en appelant IJSRuntime.InvokeAsync<T>..NET methods interop with the JavaScript functions in the exampleJsInterop.js file by calling IJSRuntime.InvokeAsync<T>.

L' IJSRuntime abstraction est asynchrone pour permettre les scénarios de serveur éblouissants.The IJSRuntime abstraction is asynchronous to allow for Blazor Server scenarios. Si l’application est une application de webassembly éblouissante et que vous souhaitez appeler une fonction JavaScript de manière synchrone IJSInProcessRuntime , vous Invoke<T> devez effectuer un casting vers et appeler à la place.If the app is a Blazor WebAssembly app and you want to invoke a JavaScript function synchronously, downcast to IJSInProcessRuntime and call Invoke<T> instead. Nous recommandons que la plupart des bibliothèques d’interopérabilité JavaScript utilisent les API Async pour s’assurer que les bibliothèques sont disponibles dans tous les scénarios.We recommend that most JavaScript interop libraries use the async APIs to ensure that the libraries are available in all scenarios.

L’exemple d’application comprend un composant pour illustrer l’interopérabilité JavaScript.The sample app includes a component to demonstrate JavaScript interop. Le composant :The component:

  • Reçoit une entrée d’utilisateur via une invite JavaScript.Receives user input via a JavaScript prompt.
  • Retourne le texte du composant pour traitement.Returns the text to the component for processing.
  • Appelle une deuxième fonction JavaScript qui interagit avec le DOM pour afficher un message d’accueil.Calls a second JavaScript function that interacts with the DOM to display a welcome message.

Pages/JSInterop. Razor:Pages/JSInterop.razor:

@page "/JSInterop"
@using BlazorSample.JsInteropClasses
@inject IJSRuntime JSRuntime

<h1>JavaScript Interop</h1>

<h2>Invoke JavaScript functions from .NET methods</h2>

<button type="button" class="btn btn-primary" @onclick="TriggerJsPrompt">
    Trigger JavaScript Prompt
</button>

<h3 id="welcome" style="color:green;font-style:italic"></h3>

@code {
    public async void TriggerJsPrompt()
    {
        // showPrompt is implemented in wwwroot/exampleJsInterop.js
        var name = await JSRuntime.InvokeAsync<string>(
                "exampleJsFunctions.showPrompt",
                "What's your name?");
        // displayWelcome is implemented in wwwroot/exampleJsInterop.js
        await JSRuntime.InvokeAsync<string>(
                "exampleJsFunctions.displayWelcome",
                $"Hello {name}! Welcome to Blazor!");
    }
}
  1. Lorsque TriggerJsPrompt est exécuté en sélectionnant le bouton d' invite de commandes JavaScript du composant showPrompt , la fonction JavaScript fournie dans le fichier wwwroot/exampleJsInterop. js est appelée.When TriggerJsPrompt is executed by selecting the component's Trigger JavaScript Prompt button, the JavaScript showPrompt function provided in the wwwroot/exampleJsInterop.js file is called.
  2. La showPrompt fonction accepte l’entrée d’utilisateur (nom de l’utilisateur), qui est codée au format HTML et renvoyée au composant.The showPrompt function accepts user input (the user's name), which is HTML-encoded and returned to the component. Le composant stocke le nom de l’utilisateur dans une variable namelocale,.The component stores the user's name in a local variable, name.
  3. La chaîne stockée name dans est incorporée dans un message de bienvenue, qui est transmis à une displayWelcomefonction JavaScript,, qui affiche le message de bienvenue dans une balise de titre.The string stored in name is incorporated into a welcome message, which is passed to a JavaScript function, displayWelcome, which renders the welcome message into a heading tag.

Appeler une fonction JavaScript voidCall a void JavaScript function

Les fonctions JavaScript qui retournent void (0)/void 0 ou non défini sont IJSRuntime.InvokeAsync<object>appelées avec null, qui retourne.JavaScript functions that return void(0)/void 0 or undefined are called with IJSRuntime.InvokeAsync<object>, which returns null.

Détecter quand une application éblouissant est prérenduDetect when a Blazor app is prerendering

Bien qu’une application de serveur éblouissante soit prérendue, certaines actions, telles que l’appel en JavaScript, ne sont pas possibles, car une connexion avec le navigateur n’a pas été établie.While a Blazor Server app is prerendering, certain actions, such as calling into JavaScript, aren't possible because a connection with the browser hasn't been established. Les composants peuvent avoir besoin d’être restitués différemment lorsqu’ils sont prérendus.Components may need to render differently when prerendered.

Pour différer les appels Interop JavaScript jusqu’à ce que la connexion avec le navigateur soit établie, OnAfterRenderAsync vous pouvez utiliser l’événement du cycle de vie du composant.To delay JavaScript interop calls until after the connection with the browser is established, you can use the OnAfterRenderAsync component lifecycle event. Cet événement est appelé uniquement une fois que l’application est entièrement rendue et que la connexion cliente est établie.This event is only called after the app is fully rendered and the client connection is established.

@using Microsoft.JSInterop
@inject IJSRuntime JSRuntime

<input @ref="myInput" value="Value set during render" />

@code {
    private ElementReference myInput;

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            JSRuntime.InvokeAsync<object>(
                "setElementValue", myInput, "Value set after render");
        }
    }
}

Le composant suivant montre comment utiliser l’interopérabilité JavaScript dans le cadre de la logique d’initialisation d’un composant d’une manière compatible avec le prérendu.The following component demonstrates how to use JavaScript interop as part of a component's initialization logic in a way that's compatible with prerendering. Le composant montre qu’il est possible de déclencher une mise à jour de OnAfterRenderAsyncrendu depuis l’intérieur.The component shows that it's possible to trigger a rendering update from inside OnAfterRenderAsync. Le développeur doit éviter de créer une boucle infinie dans ce scénario.The developer must avoid creating an infinite loop in this scenario.

JSRuntime.InvokeAsync est appelé, ElementRef est utilisé uniquement dans OnAfterRenderAsync et non dans une méthode de cycle de vie antérieure, car il n’y a pas d’élément JavaScript tant que le composant n’est pas rendu.Where JSRuntime.InvokeAsync is called, ElementRef is only used in OnAfterRenderAsync and not in any earlier lifecycle method because there's no JavaScript element until after the component is rendered.

StateHasChangedest appelé pour restituer à nouveau le composant avec le nouvel état obtenu à partir de l’appel JavaScript Interop.StateHasChanged is called to rerender the component with the new state obtained from the JavaScript interop call. Le code ne crée pas de boucle infinie, car StateHasChanged est nullappelé uniquement lorsque infoFromJs est.The code doesn't create an infinite loop because StateHasChanged is only called when infoFromJs is null.

@page "/prerendered-interop"
@using Microsoft.AspNetCore.Components
@using Microsoft.JSInterop
@inject IComponentContext ComponentContext
@inject IJSRuntime JSRuntime

<p>
    Get value via JS interop call:
    <strong id="val-get-by-interop">@(infoFromJs ?? "No value yet")</strong>
</p>

<p>
    Set value via JS interop call:
    <input id="val-set-by-interop" @ref="myElem" />
</p>

@code {
    private string infoFromJs;
    private ElementReference myElem;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && infoFromJs == null)
        {
            infoFromJs = await JSRuntime.InvokeAsync<string>(
                "setElementValue", myElem, "Hello from interop call");

            StateHasChanged();
        }
    }
}

Pour restituer de façon conditionnelle un contenu différent selon que l’application est actuellement prérendu du contenu, IsConnected utilisez la propriété IComponentContext sur le service.To conditionally render different content based on whether the app is currently prerendering content, use the IsConnected property on the IComponentContext service. Pour les applications serveur éblouissantes IsConnected , retourne true uniquement s’il existe une connexion active au client.For Blazor Server apps, IsConnected only returns true if there's an active connection to the client. Elle retourne true toujours dans les applications webassembly éblouissantes.It always returns true in Blazor WebAssembly apps.

@page "/isconnected-example"
@using Microsoft.AspNetCore.Components.Services
@inject IComponentContext ComponentContext

<h1>IsConnected Example</h1>

<p>
    Current state:
    <strong id="connected-state">
        @(ComponentContext.IsConnected ? "connected" : "not connected")
    </strong>
</p>

<p>
    Clicks:
    <strong id="count">@count</strong>
    <button id="increment-count" @onclick="@(() => count++)">Click me</button>
</p>

@code {
    private int count;
}

Capturer des références à des élémentsCapture references to elements

Certains scénarios d' interopérabilité JavaScript requièrent des références aux éléments HTML.Some JavaScript interop scenarios require references to HTML elements. Par exemple, une bibliothèque d’interface utilisateur peut nécessiter une référence d’élément pour l’initialisation, ou vous devrez peut-être appeler des API de type commande focus sur playun élément, tel que ou.For example, a UI library may require an element reference for initialization, or you might need to call command-like APIs on an element, such as focus or play.

Capturer des références aux éléments HTML dans un composant à l’aide de l’approche suivante :Capture references to HTML elements in a component using the following approach:

  • Ajoutez un @ref attribut à l’élément HTML.Add an @ref attribute to the HTML element.
  • Définissez un champ de type ElementReference dont le nom correspond à la valeur @ref de l’attribut.Define a field of type ElementReference whose name matches the value of the @ref attribute.

L’exemple suivant illustre la capture d’une référence username à l' <input> élément :The following example shows capturing a reference to the username <input> element:

<input @ref="username" ... />

@code {
    ElementReference username;
}

Notes

N’utilisez pas de références d’élément capturées comme méthode de remplissage ou de manipulation du DOM quand éblouissant interagit avec les éléments référencés.Do not use captured element references as a way of populating or manipulating the DOM when Blazor interacts with the elements referenced. Cela peut interférer avec le modèle de rendu déclaratif.Doing so may interfere with the declarative rendering model.

En ce qui concerne le code .net, un ElementReference est un handle opaque.As far as .NET code is concerned, an ElementReference is an opaque handle. La seule chose que vous pouvez faire ElementReference avec est de la passer au code JavaScript via l’interopérabilité JavaScript.The only thing you can do with ElementReference is pass it through to JavaScript code via JavaScript interop. Dans ce cas, le code JavaScript reçoit une HTMLElement instance, qu’il peut utiliser avec les API DOM normales.When you do so, the JavaScript-side code receives an HTMLElement instance, which it can use with normal DOM APIs.

Par exemple, le code suivant définit une méthode d’extension .NET qui permet de définir le focus sur un élément :For example, the following code defines a .NET extension method that enables setting the focus on an element:

exampleJsInterop. js:exampleJsInterop.js:

window.exampleJsFunctions = {
  focusElement : function (element) {
    element.focus();
  }
}

Utilisez IJSRuntime.InvokeAsync<T> et appelez exampleJsFunctions.focusElement avec un ElementReference pour concentrer un élément :Use IJSRuntime.InvokeAsync<T> and call exampleJsFunctions.focusElement with an ElementReference to focus an element:

@inject IJSRuntime JSRuntime

<input @ref="username" />
<button @onclick="SetFocus">Set focus on username</button>

@code {
    private ElementReference username;

    public async void SetFocus()
    {
        await JSRuntime.InvokeAsync<object>(
                "exampleJsFunctions.focusElement", username);
    }
}

Pour utiliser une méthode d’extension pour le focus d’un élément, créez une méthode d’extension IJSRuntime statique qui reçoit l’instance :To use an extension method to focus an element, create a static extension method that receives the IJSRuntime instance:

public static Task Focus(this ElementReference elementRef, IJSRuntime jsRuntime)
{
    return jsRuntime.InvokeAsync<object>(
        "exampleJsFunctions.focusElement", elementRef);
}

La méthode est appelée directement sur l’objet.The method is called directly on the object. L’exemple suivant suppose que la méthode statique Focus est disponible à partir de JsInteropClasses l’espace de noms :The following example assumes that the static Focus method is available from the JsInteropClasses namespace:

@inject IJSRuntime JSRuntime
@using JsInteropClasses

<input @ref="username" />
<button @onclick="SetFocus">Set focus on username</button>

@code {
    private ElementReference username;

    public async Task SetFocus()
    {
        await username.Focus(JSRuntime);
    }
}

Important

La username variable est remplie uniquement après le rendu du composant.The username variable is only populated after the component is rendered. Si un non rempli ElementReference est passé à du code JavaScript, le code JavaScript reçoit la nullvaleur.If an unpopulated ElementReference is passed to JavaScript code, the JavaScript code receives a value of null. Pour manipuler des références d’élément une fois que le composant a terminé le rendu (pour définir le focus initial sur OnAfterRenderAsync un OnAfterRender élément), utilisez les méthodes de cycle de vie des composantsou.To manipulate element references after the component has finished rendering (to set the initial focus on an element) use the OnAfterRenderAsync or OnAfterRender component lifecycle methods.

Appeler des méthodes .NET à partir de fonctions JavaScriptInvoke .NET methods from JavaScript functions

Appel de méthode .NET statiqueStatic .NET method call

Pour appeler une méthode .net statique à partir de JavaScript, DotNet.invokeMethod utilisez DotNet.invokeMethodAsync les fonctions ou.To invoke a static .NET method from JavaScript, use the DotNet.invokeMethod or DotNet.invokeMethodAsync functions. Transmettez l’identificateur de la méthode statique que vous souhaitez appeler, le nom de l’assembly contenant la fonction et les arguments éventuels.Pass in the identifier of the static method you wish to call, the name of the assembly containing the function, and any arguments. La version asynchrone est préférable à la prise en charge des scénarios de serveur éblouissants.The asynchronous version is preferred to support Blazor Server scenarios. Pour appeler une méthode .net à partir de JavaScript, la méthode .net doit être publique, statique et avoir [JSInvokable] l’attribut.To invoke a .NET method from JavaScript, the .NET method must be public, static, and have the [JSInvokable] attribute. Par défaut, l’identificateur de méthode est le nom de la méthode, mais vous pouvez spécifier un identificateur différent à JSInvokableAttribute l’aide du constructeur.By default, the method identifier is the method name, but you can specify a different identifier using the JSInvokableAttribute constructor. L’appel de méthodes génériques ouvertes n’est pas pris en charge actuellement.Calling open generic methods isn't currently supported.

L’exemple d’application comprend C# une méthode pour retourner un tableau intde.The sample app includes a C# method to return an array of ints. L' JSInvokable attribut est appliqué à la méthode.The JSInvokable attribute is applied to the method.

Pages/JsInterop. Razor:Pages/JsInterop.razor:

<button type="button" class="btn btn-primary"
        onclick="exampleJsFunctions.returnArrayAsyncJs()">
    Trigger .NET static method ReturnArrayAsync
</button>

@code {
    [JSInvokable]
    public static Task<int[]> ReturnArrayAsync()
    {
        return Task.FromResult(new int[] { 1, 2, 3 });
    }
}

JavaScript traité au client appelle la C# méthode .net.JavaScript served to the client invokes the C# .NET method.

wwwroot/exampleJsInterop. js:wwwroot/exampleJsInterop.js:

window.exampleJsFunctions = {
  showPrompt: function (text) {
    return prompt(text, 'Type your name here');
  },
  displayWelcome: function (welcomeMessage) {
    document.getElementById('welcome').innerText = welcomeMessage;
  },
  returnArrayAsyncJs: function () {
    DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
      .then(data => {
        data.push(4);
          console.log(data);
    });
  },
  sayHello: function (dotnetHelper) {
    return dotnetHelper.invokeMethodAsync('SayHello')
      .then(r => console.log(r));
  }
};

Quand le bouton déclencher l’ReturnArrayAsync de la méthode statique .net est sélectionné, examinez la sortie de la console dans les outils de développement Web du navigateur.When the Trigger .NET static method ReturnArrayAsync button is selected, examine the console output in the browser's web developer tools.

La sortie de la console est la suivante :The console output is:

Array(4) [ 1, 2, 3, 4 ]

La quatrième valeur de tableau fait l’objet d’undata.push(4);push dans le ReturnArrayAsynctableau () retourné par.The fourth array value is pushed to the array (data.push(4);) returned by ReturnArrayAsync.

Appel de méthode d’instanceInstance method call

Vous pouvez également appeler des méthodes d’instance .NET à partir de JavaScript.You can also call .NET instance methods from JavaScript. Pour appeler une méthode d’instance .NET à partir de JavaScript :To invoke a .NET instance method from JavaScript:

  • Transmettez l’instance .net à JavaScript en l’encapsulant DotNetObjectReference dans une instance.Pass the .NET instance to JavaScript by wrapping it in a DotNetObjectReference instance. L’instance .NET est passée par référence à JavaScript.The .NET instance is passed by reference to JavaScript.
  • Appeler des méthodes d’instance .net sur l’instance invokeMethod à invokeMethodAsync l’aide des fonctions ou.Invoke .NET instance methods on the instance using the invokeMethod or invokeMethodAsync functions. L’instance .NET peut également être passée comme argument lors de l’appel d’autres méthodes .NET à partir de JavaScript.The .NET instance can also be passed as an argument when invoking other .NET methods from JavaScript.

Notes

L’exemple d’application enregistre les messages dans la console côté client.The sample app logs messages to the client-side console. Pour les exemples suivants présentés dans l’exemple d’application, examinez la sortie de console du navigateur dans les outils de développement du navigateur.For the following examples demonstrated by the sample app, examine the browser's console output in the browser's developer tools.

Lorsque le bouton de méthode d’instance .net de déclenchement HelloHelper. SayHello est sélectionné, ExampleJsInterop.CallHelloHelperSayHello est appelé et passe un nom, Blazor, à la méthode.When the Trigger .NET instance method HelloHelper.SayHello button is selected, ExampleJsInterop.CallHelloHelperSayHello is called and passes a name, Blazor, to the method.

Pages/JsInterop. Razor:Pages/JsInterop.razor:

<button type="button" class="btn btn-primary" @onclick="TriggerNetInstanceMethod">
    Trigger .NET instance method HelloHelper.SayHello
</button>

@code {
    public async void TriggerNetInstanceMethod()
    {
        var exampleJsInterop = new ExampleJsInterop(JSRuntime);
        await exampleJsInterop.CallHelloHelperSayHello("Blazor");
    }
}

CallHelloHelperSayHelloappelle la fonction sayHello JavaScript avec une nouvelle instance de HelloHelper.CallHelloHelperSayHello invokes the JavaScript function sayHello with a new instance of HelloHelper.

JsInteropClasses/ExampleJsInterop. cs:JsInteropClasses/ExampleJsInterop.cs:

public class ExampleJsInterop
{
    private readonly IJSRuntime _jsRuntime;

    public ExampleJsInterop(IJSRuntime jsRuntime)
    {
        _jsRuntime = jsRuntime;
    }

    public ValueTask<object> CallHelloHelperSayHello(string name)
    {
        // sayHello is implemented in wwwroot/exampleJsInterop.js
        return _jsRuntime.InvokeAsync<object>(
            "exampleJsFunctions.sayHello",
            DotNetObjectReference.Create(new HelloHelper(name)));
    }
}

wwwroot/exampleJsInterop. js:wwwroot/exampleJsInterop.js:

window.exampleJsFunctions = {
  showPrompt: function (text) {
    return prompt(text, 'Type your name here');
  },
  displayWelcome: function (welcomeMessage) {
    document.getElementById('welcome').innerText = welcomeMessage;
  },
  returnArrayAsyncJs: function () {
    DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
      .then(data => {
        data.push(4);
          console.log(data);
    });
  },
  sayHello: function (dotnetHelper) {
    return dotnetHelper.invokeMethodAsync('SayHello')
      .then(r => console.log(r));
  }
};

Le nom est passé au HelloHelperconstructeur de, qui définit la HelloHelper.Name propriété.The name is passed to HelloHelper's constructor, which sets the HelloHelper.Name property. Lorsque la fonction sayHello JavaScript est exécutée HelloHelper.SayHello , retourne Hello, {Name}! le message, qui est écrit dans la console par la fonction JavaScript.When the JavaScript function sayHello is executed, HelloHelper.SayHello returns the Hello, {Name}! message, which is written to the console by the JavaScript function.

JsInteropClasses/HelloHelper.cs:JsInteropClasses/HelloHelper.cs:

public class HelloHelper
{
    public HelloHelper(string name)
    {
        Name = name;
    }

    public string Name { get; set; }

    [JSInvokable]
    public string SayHello() => $"Hello, {Name}!";
}

Sortie de la console dans les outils de développement Web du navigateur :Console output in the browser's web developer tools:

Hello, Blazor!

Partager du code d’interopérabilité dans une bibliothèque de classesShare interop code in a class library

Le code JavaScript Interop peut être inclus dans une bibliothèque de classes, ce qui vous permet de partager le code dans un package NuGet.JavaScript interop code can be included in a class library, which allows you to share the code in a NuGet package.

La bibliothèque de classes gère l’incorporation des ressources JavaScript dans l’assembly généré.The class library handles embedding JavaScript resources in the built assembly. Les fichiers JavaScript sont placés dans le dossier wwwroot .The JavaScript files are placed in the wwwroot folder. Les outils s’occupent de l’incorporation des ressources lors de la génération de la bibliothèque.The tooling takes care of embedding the resources when the library is built.

Le package NuGet créé est référencé dans le fichier projet de l’application de la même façon que n’importe quel package NuGet.The built NuGet package is referenced in the app's project file the same way that any NuGet package is referenced. Une fois le package restauré, le code d’application peut appeler JavaScript comme s’il C#avait été.After the package is restored, app code can call into JavaScript as if it were C#.

Pour plus d'informations, consultez Bibliothèques de classes des composants Razor ASP.NET Core.For more information, see Bibliothèques de classes des composants Razor ASP.NET Core.

Sécuriser les appels d’interopérabilité JSHarden JS interop calls

L’interopérabilité de JS peut échouer en raison d’erreurs réseau et doit être considérée comme non fiable.JS interop may fail due to networking errors and should be treated as unreliable. Par défaut, une application de serveur éblouissante expire des appels d’interopérabilité JS sur le serveur après une minute.By default, a Blazor Server app times out JS interop calls on the server after one minute. Si une application peut tolérer un délai d’expiration plus agressif, par exemple 10 secondes, définissez le délai d’expiration à l’aide de l’une des approches suivantes :If an app can tolerate a more aggressive timeout, such as 10 seconds, set the timeout using one of the following approaches:

  • Globalement dans Startup.ConfigureServices, spécifiez le délai d’expiration :Globally in Startup.ConfigureServices, specify the timeout:

    services.AddServerSideBlazor(
        options => options.JSInteropDefaultCallTimeout = TimeSpan.FromSeconds({SECONDS}));
    
  • Par appel dans le code du composant, un appel unique peut spécifier le délai d’attente :Per-invocation in component code, a single call can specify the timeout:

    var result = await JSRuntime.InvokeAsync<string>("MyJSOperation", 
        TimeSpan.FromSeconds({SECONDS}), new[] { "Arg1" });
    

Pour plus d’informations sur l’épuisement des Sécuriser les applications de serveur ASP.NET Core éblouissantesressources, consultez.For more information on resource exhaustion, see Sécuriser les applications de serveur ASP.NET Core éblouissantes.