Delen via


.NET-methoden aanroepen vanuit JavaScript-functies in ASP.NET Core Blazor

Note

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikel voor de huidige release.

Warning

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 9-versie van dit artikel voor de huidige release.

Important

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikel voor de huidige release.

In dit artikel wordt uitgelegd hoe u .NET-methoden aanroept vanuit JavaScript (JS).

Zie Blazorvoor meer informatie over het aanroepen van functies vanuit .NET.

Een statische .NET-methode aanroepen

Als u een statische .NET-methode wilt aanroepen vanuit JavaScript (JS), gebruikt u de JS volgende functies:

  • DotNet.invokeMethodAsync (aanbevolen): Asynchroon voor zowel server- als clientonderdelen.
  • DotNet.invokeMethod: Alleen synchroon voor onderdelen aan de clientzijde.

Geef de naam van de assembly door die de methode bevat, de id van de statische .NET-methode en eventuele argumenten.

In het volgende voorbeeld:

  • De {PACKAGE ID/ASSEMBLY NAME} placeholder is de pakket-id van het project (<PackageId> in het projectbestand) voor een library- of assemblynaam voor een app.
  • De {.NET METHOD ID} tijdelijke aanduiding is de .NET-methode-id.
  • De {ARGUMENTS} tijdelijke aanduidingen zijn optionele, door komma's gescheiden argumenten om door te geven aan de methode, die elk JSON-serializeerbaar moeten zijn.
DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});

DotNet.invokeMethodAsync retourneert een JS Promise weergave van het resultaat van de bewerking. DotNet.invokeMethod (onderdelen aan de clientzijde) retourneert het resultaat van de bewerking.

Important

Voor onderdelen aan de serverzijde raden we de asynchrone functie (invokeMethodAsync) aan via de synchrone versie (invokeMethod).

De .NET-methode moet openbaar, statisch zijn en het [JSInvokable] kenmerk hebben.

In het volgende voorbeeld:

  • De {<T>} tijdelijke aanduiding geeft het retourtype aan. Dit is alleen vereist voor methoden die een waarde retourneren.
  • De {.NET METHOD ID} tijdelijke aanduiding is de methode-id.
@code {
    [JSInvokable]
    public static Task{<T>} {.NET METHOD ID}()
    {
        ...
    }
}

Note

Het aanroepen van open algemene methoden wordt niet ondersteund met statische .NET-methoden, maar wordt ondersteund met exemplaarmethoden. Voor meer informatie, zie de sectie Aanroepen van generieke methoden van .NET-klassen.

In het volgende onderdeel retourneert de ReturnArrayAsync C#-methode een int matrix. Het [JSInvokable] kenmerk wordt toegepast op de methode, waardoor de methode kan worden aangeroepen door JS.

CallDotnet1.razor:

@page "/call-dotnet-1"
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET 1</PageTitle>

<h1>Call .NET Example 1</h1>

<p>
    <button id="btn">Trigger .NET static method</button>
</p>

<p>
    See the result in the developer tools console.
</p>

@code {
    private IJSObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./Components/Pages/CallDotnet1.razor.js");

            await module.InvokeVoidAsync("addHandlers");
        }
    }

    [JSInvokable]
    public static Task<int[]> ReturnArrayAsync() =>
        Task.FromResult(new int[] { 11, 12, 13 });

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }
    }
}

CallDotnet1.razor.js:

export function returnArrayAsync() {
  DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
    .then(data => {
      console.log(data);
    });
}

export function addHandlers() {
  const btn = document.getElementById("btn");
  btn.addEventListener("click", returnArrayAsync);
}

De addHandlersJS functie voegt een click gebeurtenis toe aan de knop. De returnArrayAsyncJS functie wordt toegewezen als handler.

De returnArrayAsyncJS functie roept de ReturnArrayAsync .NET-methode van het onderdeel aan, waarmee het resultaat wordt opgeslagen in de console voor webontwikkelaars van de browser. BlazorSample is de assemblynaam van de app.

CallDotnet1.razor:

@page "/call-dotnet-1"
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET 1</PageTitle>

<h1>Call .NET Example 1</h1>

<p>
    <button id="btn">Trigger .NET static method</button>
</p>

<p>
    See the result in the developer tools console.
</p>

@code {
    private IJSObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./Components/Pages/CallDotnet1.razor.js");

            await module.InvokeVoidAsync("addHandlers");
        }
    }

    [JSInvokable]
    public static Task<int[]> ReturnArrayAsync() =>
        Task.FromResult(new int[] { 11, 12, 13 });

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }
    }
}

CallDotnet1.razor.js:

export function returnArrayAsync() {
  DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
    .then(data => {
      console.log(data);
    });
}

export function addHandlers() {
  const btn = document.getElementById("btn");
  btn.addEventListener("click", returnArrayAsync);
}

De addHandlersJS functie voegt een click gebeurtenis toe aan de knop. De returnArrayAsyncJS functie wordt toegewezen als handler.

De returnArrayAsyncJS functie roept de ReturnArrayAsync .NET-methode van het onderdeel aan, waarmee het resultaat wordt opgeslagen in de console voor webontwikkelaars van de browser. BlazorSample is de assemblynaam van de app.

CallDotNetExample1.razor:

@page "/call-dotnet-example-1"

<h1>Call .NET Example 1</h1>

<p>
    <button onclick="returnArrayAsync()">
        Trigger .NET static method
    </button>
</p>

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

CallDotNetExample1.razor:

@page "/call-dotnet-example-1"

<h1>Call .NET Example 1</h1>

<p>
    <button onclick="returnArrayAsync()">
        Trigger .NET static method
    </button>
</p>

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

CallDotNetExample1.razor:

@page "/call-dotnet-example-1"

<h1>Call .NET Example 1</h1>

<p>
    <button onclick="returnArrayAsync()">
        Trigger .NET static method
    </button>
</p>

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

CallDotNetExample1.razor:

@page "/call-dotnet-example-1"

<h1>Call .NET Example 1</h1>

<p>
    <button onclick="returnArrayAsync()">
        Trigger .NET static method
    </button>
</p>

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

Het HTML-attribuut van het <button>-element is de JavaScript onclick gebeurtenis-handler toewijzing voor het verwerken van onclick-gebeurtenissen, niet het aanwijzingsattribuut van clickBlazor. De returnArrayAsyncJS functie wordt toegewezen als handler.

Met de volgende returnArrayAsyncJS functie wordt de ReturnArrayAsync .NET-methode van het onderdeel aangeroepen, waarmee het resultaat wordt opgeslagen in de console voor webontwikkelaars van de browser. BlazorSample is de assemblynaam van de app.

<script>
  window.returnArrayAsync = () => {
    DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync')
      .then(data => {
        console.log(data);
      });
    };
</script>

Note

Zie JSvoor algemene richtlijnen voor Blazor locatie en onze aanbevelingen voor productie-apps.

Wanneer de Trigger .NET static method knop is geselecteerd, worden de matrixgegevens weergegeven in de console voor ontwikkelaarshulpprogramma's van de browser. De indeling van de uitvoer verschilt enigszins tussen browsers. In de volgende uitvoer ziet u de indeling die wordt gebruikt door Microsoft Edge:

Array(3) [ 11, 12, 13 ]

Geef gegevens door aan een .NET-methode wanneer u de invokeMethodAsync functie aanroept door de gegevens als argumenten door te geven.

Als u wilt demonstreren dat gegevens worden doorgegeven aan .NET, geeft u een beginpositie door aan de ReturnArrayAsync methode waarin de methode wordt aangeroepen in JS:

export function returnArrayAsync() {
  DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', 14)
    .then(data => {
      console.log(data);
    });
}
<script>
  window.returnArrayAsync = () => {
    DotNet.invokeMethodAsync('BlazorSample', 'ReturnArrayAsync', 14)
      .then(data => {
        console.log(data);
      });
    };
</script>

De aanroepbare ReturnArrayAsync methode van het onderdeel ontvangt de beginpositie en bouwt de matrix ermee. De matrix wordt geretourneerd voor logboekregistratie naar de console:

[JSInvokable]
public static Task<int[]> ReturnArrayAsync(int startPosition) => 
    Task.FromResult(Enumerable.Range(startPosition, 3).ToArray());

Nadat de app opnieuw is gecompileerd en de browser is vernieuwd, wordt de volgende uitvoer weergegeven in de console van de browser wanneer de knop is geselecteerd:

Array(3) [ 14, 15, 16 ]

De .NET-methode-id voor de aanroep is de naam van de JS .NET-methode, maar u kunt een andere id opgeven met behulp van de [JSInvokable] kenmerkconstructor . In het volgende voorbeeld DifferentMethodName is de toegewezen methode-id voor de ReturnArrayAsync methode:

[JSInvokable("DifferentMethodName")]

In de aanroep naar DotNet.invokeMethodAsync (server- of clientonderdelen) of DotNet.invokeMethod (alleen clientonderdelen), roept u DifferentMethodName aan om de ReturnArrayAsync .NET-methode uit te voeren:

  • DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
  • DotNet.invokeMethod('BlazorSample', 'DifferentMethodName'); (alleen onderdelen aan clientzijde)

Note

Het ReturnArrayAsync voorbeeld van de methode in deze sectie retourneert het resultaat van een Task zonder expliciete C# async en await trefwoorden. Coderingsmethoden met async en await zijn typische methoden die het await trefwoord gebruiken om de waarde van asynchrone bewerkingen te retourneren.

ReturnArrayAsync methode samengesteld met async en await trefwoorden:

[JSInvokable]
public static async Task<int[]> ReturnArrayAsync() => 
    await Task.FromResult(new int[] { 11, 12, 13 });

Zie Asynchrone programmering met asynchroon programmeren en wachten in de C#-handleiding voor meer informatie.

JavaScript-object- en gegevensverwijzingen maken om door te geven aan .NET

Aanroep DotNet.createJSObjectReference(jsObject) om een JS objectverwijzing te maken, zodat deze kan worden doorgegeven aan .NET, waar jsObject wordt gebruikt JS Object om de JS objectverwijzing te maken. In het volgende voorbeeld wordt een verwijzing naar het niet-serialiseerbare window object doorgegeven aan .NET, dat deze in de ReceiveWindowObject C#-methode ontvangt als een IJSObjectReference.

DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject', 
  DotNet.createJSObjectReference(window));
[JSInvokable]
public static void ReceiveWindowObject(IJSObjectReference objRef)
{
    ...
}

In het voorgaande voorbeeld is de {PACKAGE ID/ASSEMBLY NAME} tijdelijke aanduiding de pakket-id van het project (<PackageId> in het projectbestand) voor een bibliotheek- of assemblynaam voor een app.

Note

Het voorgaande voorbeeld vereist geen verwijdering van de JSObjectReference, aangezien er geen verwijzing naar het window object wordt bewaard in JS.

Het onderhouden van een verwijzing naar een JSObjectReference verwijzing vereist het verwijderen ervan om te voorkomen dat geheugen op de client wordt gelekt JS . In het volgende voorbeeld wordt de voorgaande code hersteld om een verwijzing naar de JSObjectReference vast te leggen, gevolgd door het aanroepen van DotNet.disposeJSObjectReference() om de verwijzing te verwijderen.

var jsObjectReference = DotNet.createJSObjectReference(window);

DotNet.invokeMethodAsync('{PACKAGE ID/ASSEMBLY NAME}', 'ReceiveWindowObject', jsObjectReference);

DotNet.disposeJSObjectReference(jsObjectReference);

In het voorgaande voorbeeld is de {PACKAGE ID/ASSEMBLY NAME} tijdelijke aanduiding de pakket-id van het project (<PackageId> in het projectbestand) voor een bibliotheek- of assemblynaam voor een app.

Aanroep DotNet.createJSStreamReference(streamReference) om een JS stroomreferentie te maken, zodat deze kan worden doorgegeven aan .NET, waarbij streamReference een ArrayBuffer, Blobof een getypte matrix, zoals Uint8Array of Float32Array, wordt gebruikt om de JS stroomreferentie te maken.

Een .NET-instantiemethode aanroepen

Een .NET-instantiemethode aanroepen vanuit JavaScript (JS):

  • Geef het .NET-exemplaar door als referentie aan JS door het exemplaar in een DotNetObjectReference te verpakken en Create erop aan te roepen.

  • Roep een .NET-exemplaarmethode aan van JS met invokeMethodAsync (aanbevolen) of invokeMethod (alleen client-side componenten) van de doorgegeven DotNetObjectReference. Geef de id van de .NET-instantiemethode en eventuele argumenten door. Het .NET-exemplaar kan ook worden doorgegeven als argument bij het aanroepen van andere .NET-methoden vanuit JS.

    In het volgende voorbeeld:

    • dotNetHelper is een DotNetObjectReference.
    • De {.NET METHOD ID} tijdelijke aanduiding is de .NET-methode-id.
    • De {ARGUMENTS} tijdelijke aanduidingen zijn optionele, door komma's gescheiden argumenten om door te geven aan de methode, die elk JSON-serializeerbaar moeten zijn.
    dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
    

    Note

    invokeMethodAsync en invokeMethod accepteer geen assemblynaamparameter bij het aanroepen van een exemplaarmethode.

    invokeMethodAsync retourneert een JS Promise weergave van het resultaat van de bewerking. invokeMethod (alleen onderdelen aan de clientzijde) retourneert het resultaat van de bewerking.

    Important

    Voor onderdelen aan de serverzijde raden we de asynchrone functie (invokeMethodAsync) aan via de synchrone versie (invokeMethod).

  • Verwijder de DotNetObjectReference.

De volgende secties van dit artikel laten verschillende benaderingen zien voor het aanroepen van een .NET-instantiemethode:

Vermijd het inkorten van .NET-methoden die door JavaScript kunnen worden opgeroepen.

Deze sectie is van toepassing op apps aan de clientzijde waarvoor vooraf compilatie (AOT) en runtime-relinking is ingeschakeld.

Verschillende voorbeelden in de volgende secties zijn gebaseerd op een benadering van een klasse-exemplaar, waarbij de JavaScript-invokable .NET-methode die is gemarkeerd met het [JSInvokable] kenmerk lid is van een klasse die geen Razor onderdeel is. Wanneer dergelijke .NET-methoden zich in een Razor onderdeel bevinden, worden ze beschermd tegen het opnieuw koppelen/bijsnijden van runtime. Als u de .NET-methoden wilt beveiligen tegen bijsnijden buiten Razor onderdelen, implementeert u de methoden met het DynamicDependency kenmerk op de constructor van de klasse, zoals in het volgende voorbeeld wordt gedemonstreerd:

using System.Diagnostics.CodeAnalysis;
using Microsoft.JSInterop;

public class ExampleClass {

    [DynamicDependency(nameof(ExampleJSInvokableMethod))]
    public ExampleClass()
    {
    }

    [JSInvokable]
    public string ExampleJSInvokableMethod()
    {
        ...
    }
}

Zie .NET-bibliotheken voorbereiden voor bijsnijden: DynamicDependency voor meer informatie.

Geef een DotNetObjectReference door aan een afzonderlijke JavaScript-functie

In het voorbeeld in deze sectie ziet u hoe u een DotNetObjectReference afzonderlijke JavaScript-functie (JS) doorgeeft.

De volgende sayHello1JS functie ontvangt een DotNetObjectReference en roept aan invokeMethodAsync om de GetHelloMessage .NET-methode van een onderdeel aan te roepen:

<script>
  window.sayHello1 = (dotNetHelper) => {
    return dotNetHelper.invokeMethodAsync('GetHelloMessage');
  };
</script>

Note

Zie JSvoor algemene richtlijnen voor Blazor locatie en onze aanbevelingen voor productie-apps.

In het voorgaande voorbeeld is de naam dotNetHelper van de variabele willekeurig en kan deze worden gewijzigd in elke voorkeursnaam.

Voor het volgende onderdeel:

  • Het onderdeel heeft een .NET-methode genaamd JS, die GetHelloMessage-invokable is.
  • Wanneer de Trigger .NET instance method knop is geselecteerd, wordt de JS functie sayHello1 aangeroepen met de DotNetObjectReference.
  • sayHello1:
    • Roept GetHelloMessage aan en ontvangt het berichtresultaat.
    • Retourneert het berichtresultaat naar de aanroepmethode TriggerDotNetInstanceMethod .
  • Het geretourneerde bericht van sayHello1 in result wordt weergegeven aan de gebruiker.
  • Om een geheugenlek te voorkomen en garbagecollection toe te staan, wordt de door DotNetObjectReference gemaakte .NET-objectverwijzing vrijgegeven in de Dispose-methode.

CallDotnet2.razor:

@page "/call-dotnet-2"
@implements IDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET 2</PageTitle>

<h1>Call .NET Example 2</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private DotNetObjectReference<CallDotnet2>? objRef;

    protected override void OnInitialized() =>
        objRef = DotNetObjectReference.Create(this);

    public async Task TriggerDotNetInstanceMethod() =>
        result = await JS.InvokeAsync<string>("sayHello1", objRef);

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

    public void Dispose() => objRef?.Dispose();
}

CallDotnet2.razor:

@page "/call-dotnet-2"
@implements IDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET 2</PageTitle>

<h1>Call .NET Example 2</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private DotNetObjectReference<CallDotnet2>? objRef;

    protected override void OnInitialized() =>
        objRef = DotNetObjectReference.Create(this);

    public async Task TriggerDotNetInstanceMethod() =>
        result = await JS.InvokeAsync<string>("sayHello1", objRef);

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

    public void Dispose() => objRef?.Dispose();
}

CallDotNetExample2.razor:

@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 2</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private DotNetObjectReference<CallDotNetExample2>? objRef;

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }

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

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

CallDotNetExample2.razor:

@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 2</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private DotNetObjectReference<CallDotNetExample2>? objRef;

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }

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

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

CallDotNetExample2.razor:

@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 2</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private DotNetObjectReference<CallDotNetExample2> objRef;

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }

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

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

CallDotNetExample2.razor:

@page "/call-dotnet-example-2"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 2</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private DotNetObjectReference<CallDotNetExample2> objRef;

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }

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

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

In het voorgaande voorbeeld is de naam dotNetHelper van de variabele willekeurig en kan deze worden gewijzigd in elke voorkeursnaam.

Gebruik de volgende richtlijnen om argumenten door te geven aan een exemplaarmethode:

Voeg parameters toe aan de aanroep van de .NET-methode. In het volgende voorbeeld wordt een naam doorgegeven aan de methode. Voeg indien nodig extra parameters toe aan de lijst.

<script>
  window.sayHello2 = (dotNetHelper, name) => {
    return dotNetHelper.invokeMethodAsync('GetHelloMessage', name);
  };
</script>

In het voorgaande voorbeeld is de naam dotNetHelper van de variabele willekeurig en kan deze worden gewijzigd in elke voorkeursnaam.

Geef de lijst met parameters op voor de .NET-methode.

CallDotnet3.razor:

@page "/call-dotnet-3"
@implements IDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET 3</PageTitle>

<h1>Call .NET Example 3</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private DotNetObjectReference<CallDotnet3>? objRef;

    protected override void OnInitialized() => 
        objRef = DotNetObjectReference.Create(this);

    public async Task TriggerDotNetInstanceMethod() =>
        result = await JS.InvokeAsync<string>("sayHello2", objRef, name);

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

    public void Dispose() => objRef?.Dispose();
}

CallDotnet3.razor:

@page "/call-dotnet-3"
@implements IDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET 3</PageTitle>

<h1>Call .NET Example 3</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private DotNetObjectReference<CallDotnet3>? objRef;

    protected override void OnInitialized() => 
        objRef = DotNetObjectReference.Create(this);

    public async Task TriggerDotNetInstanceMethod() =>
        result = await JS.InvokeAsync<string>("sayHello2", objRef, name);

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

    public void Dispose() => objRef?.Dispose();
}

CallDotNetExample3.razor:

@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 3</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private DotNetObjectReference<CallDotNetExample3>? objRef;

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
    }

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

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

CallDotNetExample3.razor:

@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 3</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private DotNetObjectReference<CallDotNetExample3>? objRef;

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
    }

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

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

CallDotNetExample3.razor:

@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 3</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private DotNetObjectReference<CallDotNetExample3> objRef;

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
    }

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

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

CallDotNetExample3.razor:

@page "/call-dotnet-example-3"
@implements IDisposable
@inject IJSRuntime JS

<h1>Call .NET Example 3</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private DotNetObjectReference<CallDotNetExample3> objRef;

    protected override void OnInitialized()
    {
        objRef = DotNetObjectReference.Create(this);
    }

    public async Task TriggerDotNetInstanceMethod()
    {
        result = await JS.InvokeAsync<string>("sayHello2", objRef, name);
    }

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

    public void Dispose()
    {
        objRef?.Dispose();
    }
}

In het voorgaande voorbeeld is de naam dotNetHelper van de variabele willekeurig en kan deze worden gewijzigd in elke voorkeursnaam.

Een DotNetObjectReference aan een klasse doorgeven met meerdere JavaScript-functies

In het voorbeeld in deze sectie ziet u hoe u een DotNetObjectReference JavaScript-klasse (JS) met meerdere functies doorgeeft.

Maak en geef een DotNetObjectReference van de OnAfterRenderAsync levenscyclusmethode door aan een JS klasse die meerdere functies kan gebruiken. Zorg ervoor dat de .NET-code de DotNetObjectReference vrijgeeft, zoals in het volgende voorbeeld wordt getoond.

In het volgende onderdeel roepen de Trigger JS function knoppen JS functies aan door de JSonclick eigenschap in te stellen, en niet het Blazor@onclick instructiekenmerk.

CallDotNetExampleOneHelper.razor:

@page "/call-dotnet-example-one-helper"
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET Example</PageTitle>

<h1>Pass <code>DotNetObjectReference</code> to a JavaScript class</h1>

<p>
    <label>
        Message: <input @bind="name" />
    </label>
</p>

<p>
    <button id="sayHelloBtn">
        Trigger JS function <code>sayHello</code>
    </button>
</p>

<p>
    <button id="welcomeVisitorBtn">
        Trigger JS function <code>welcomeVisitor</code>
    </button>
</p>

@code {
    private IJSObjectReference? module;
    private string? name;
    private DotNetObjectReference<CallDotNetExampleOneHelper>? dotNetHelper;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./Components/Pages/CallDotNetExampleOneHelper.razor.js");

            dotNetHelper = DotNetObjectReference.Create(this);
            await module.InvokeVoidAsync("GreetingHelpers.setDotNetHelper", 
                dotNetHelper);

            await module.InvokeVoidAsync("addHandlers");
        }
    }

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

    [JSInvokable]
    public string GetWelcomeMessage() => $"Welcome, {name}!";

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }

        dotNetHelper?.Dispose();
    }
}

In het voorgaande voorbeeld:

  • JS is een geïnjecteerd IJSRuntime exemplaar. IJSRuntime wordt geregistreerd door het Blazor framework.
  • De naam dotNetHelper van de variabele is willekeurig en kan worden gewijzigd in elke voorkeursnaam.
  • Het onderdeel moet DotNetObjectReference expliciet verwijderen om de vuilnisverzameling toe te staan en een geheugenlek te voorkomen.
  • JSDisconnectedException komt vast te zitten bij het verwijderen van de module wanneer het BlazorSignalR circuit verloren gaat. Als de voorgaande code wordt gebruikt in een Blazor WebAssembly-app, is er geen SignalR verbinding verloren gegaan, zodat u het try-catch blok kunt verwijderen en de regel kunt verlaten waarmee de module (await module.DisposeAsync();) wordt verwijderd. Zie ASP.NET Core Blazor JavaScript-interoperabiliteit (JS interop)voor meer informatie.

CallDotNetExampleOneHelper.razor.js:

export class GreetingHelpers {
  static dotNetHelper;

  static setDotNetHelper(value) {
    GreetingHelpers.dotNetHelper = value;
  }

  static async sayHello() {
    const msg =
      await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
    alert(`Message from .NET: "${msg}"`);
  }

  static async welcomeVisitor() {
    const msg =
      await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
    alert(`Message from .NET: "${msg}"`);
  }
}

export function addHandlers() {
  const sayHelloBtn = document.getElementById("sayHelloBtn");
  sayHelloBtn.addEventListener("click", GreetingHelpers.sayHello);

  const welcomeVisitorBtn = document.getElementById("welcomeVisitorBtn");
  welcomeVisitorBtn.addEventListener("click", GreetingHelpers.welcomeVisitor);
}

In het voorgaande voorbeeld is de naam dotNetHelper van de variabele willekeurig en kan deze worden gewijzigd in elke voorkeursnaam.

@page "/call-dotnet-example-one-helper"
@implements IDisposable
@inject IJSRuntime JS

<h1>Pass <code>DotNetObjectReference</code> to a JavaScript class</h1>

<p>
    <label>
        Message: <input @bind="name" />
    </label>
</p>

<p>
    <button onclick="GreetingHelpers.sayHello()">
        Trigger JS function <code>sayHello</code>
    </button>
</p>

<p>
    <button onclick="GreetingHelpers.welcomeVisitor()">
        Trigger JS function <code>welcomeVisitor</code>
    </button>
</p>

@code {
    private string? name;
    private DotNetObjectReference<CallDotNetExampleOneHelper>? dotNetHelper;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            dotNetHelper = DotNetObjectReference.Create(this);
            await JS.InvokeVoidAsync("GreetingHelpers.setDotNetHelper", 
                dotNetHelper);
        }
    }

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

    [JSInvokable]
    public string GetWelcomeMessage() => $"Welcome, {name}!";

    public void Dispose()
    {
        dotNetHelper?.Dispose();
    }
}

In het voorgaande voorbeeld:

  • JS is een geïnjecteerd IJSRuntime exemplaar. IJSRuntime wordt geregistreerd door het Blazor framework.
  • De naam dotNetHelper van de variabele is willekeurig en kan worden gewijzigd in elke voorkeursnaam.
  • Het onderdeel moet DotNetObjectReference expliciet verwijderen om de vuilnisverzameling toe te staan en een geheugenlek te voorkomen.
<script>
  class GreetingHelpers {
    static dotNetHelper;

    static setDotNetHelper(value) {
      GreetingHelpers.dotNetHelper = value;
    }

    static async sayHello() {
      const msg = 
        await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetHelloMessage');
      alert(`Message from .NET: "${msg}"`);
    }

    static async welcomeVisitor() {
      const msg = 
        await GreetingHelpers.dotNetHelper.invokeMethodAsync('GetWelcomeMessage');
      alert(`Message from .NET: "${msg}"`);
    }
  }

  window.GreetingHelpers = GreetingHelpers;
</script>

In het voorgaande voorbeeld:

  • De GreetingHelpers klasse wordt toegevoegd aan het window object om de klasse globaal te definiëren, zodat Blazor de klasse kan lokaliseren voor JS-interop.
  • De naam dotNetHelper van de variabele is willekeurig en kan worden gewijzigd in elke voorkeursnaam.

Note

Zie JSvoor algemene richtlijnen voor Blazor locatie en onze aanbevelingen voor productie-apps.

Algemene .NET-klassemethoden aanroepen

JavaScript-functies (JS) kunnen .NET-algemene klassemethoden aanroepen, waarbij een JS functie een .NET-methode van een algemene klasse aanroept.

In de volgende algemene typeklasse (GenericType<TValue>):

  • De klasse heeft één typeparameter (TValue) met één algemene Value eigenschap.
  • De klasse heeft twee niet-algemene methoden die zijn gemarkeerd met het [JSInvokable] kenmerk, elk met een algemene typeparameter met de naam newValue:
    • Update werkt de waarde van Value synchroon bij vanuit newValue.
    • UpdateAsync werkt asynchroon de waarde van Value bij van newValue na het creëren van een awaitable taak met Task.Yield, die asynchroon terugkeert naar de huidige context wanneer deze wordt afgewacht.
  • Elk van de klassemethoden schrijft het type TValue en de waarde van Value naar de console. Schrijven naar de console is alleen voor demonstratiedoeleinden. Productie-apps vermijden meestal naar de console schrijven ten gunste van app-logboeken. Zie ASP.NET Core-logboekregistratie Blazor en -logboekregistratie in .NET en ASP.NET Core voor meer informatie.

Note

Open generieke types en methoden geven geen typen op voor typeplaatsaanduiders. Omgekeerd leveren gesloten generieken typen voor alle type tijdelijke aanduidingen. In de voorbeelden in deze sectie worden gesloten generics gedemonstreert, maar het aanroepen van JSinteroperabiliteitsexemplaren met open generics wordt ondersteund. Het gebruik van open generics wordt niet ondersteund voor aanroepen van statische .NET-methoden, die eerder in dit artikel zijn beschreven.

Zie de volgende artikelen voor meer informatie:

GenericType.cs:

using Microsoft.JSInterop;

public class GenericType<TValue>
{
    public TValue? Value { get; set; }

    [JSInvokable]
    public void Update(TValue newValue)
    {
        Value = newValue;

        Console.WriteLine($"Update: GenericType<{typeof(TValue)}>: {Value}");
    }

    [JSInvokable]
    public async Task UpdateAsync(TValue newValue)
    {
        await Task.Yield();
        Value = newValue;

        Console.WriteLine($"UpdateAsync: GenericType<{typeof(TValue)}>: {Value}");
    }
}

In de volgende invokeMethodsAsync functie:

  • De algemene typeklasse Update en UpdateAsync methoden worden aangeroepen met argumenten die tekenreeksen en getallen vertegenwoordigen.
  • Onderdelen aan de clientzijde ondersteunen het aanroepen van .NET-methoden synchroon met invokeMethod. syncInterop ontvangt een Booleaanse waarde die aangeeft of de JS interoperabiliteit plaatsvindt op de client. Wanneer syncInteroptrue is, kan invokeMethod veilig worden aangeroepen. Als de waarde van syncInteropfalse is, wordt alleen de asynchrone functie invokeMethodAsync aangeroepen omdat de interoperabiliteit wordt uitgevoerd in een server-side component JS.
  • Voor demonstratiedoeleinden wordt de DotNetObjectReference functie-aanroep (invokeMethod of invokeMethodAsync), de .NET-methode aangeroepen (Update of UpdateAsync) en het argument naar de console geschreven. De argumenten gebruiken een willekeurig getal om het koppelen van de JS functieaanroep aan de aanroep van de .NET-methode toe te staan (ook naar de console aan de .NET-zijde geschreven). Productiecode schrijft meestal niet naar de console, op de client of op de server. Productie-apps zijn meestal afhankelijk van app-logboekregistratie. Zie ASP.NET Core-logboekregistratie Blazor en -logboekregistratie in .NET en ASP.NET Core voor meer informatie.
<script>
  const randomInt = () => Math.floor(Math.random() * 99999);

  window.invokeMethodsAsync = async (syncInterop, dotNetHelper1, dotNetHelper2) => {
    var n = randomInt();
    console.log(`JS: invokeMethodAsync:Update('string ${n}')`);
    await dotNetHelper1.invokeMethodAsync('Update', `string ${n}`);

    n = randomInt();
    console.log(`JS: invokeMethodAsync:UpdateAsync('string ${n}')`);
    await dotNetHelper1.invokeMethodAsync('UpdateAsync', `string ${n}`);

    if (syncInterop) {
      n = randomInt();
      console.log(`JS: invokeMethod:Update('string ${n}')`);
      dotNetHelper1.invokeMethod('Update', `string ${n}`);
    }

    n = randomInt();
    console.log(`JS: invokeMethodAsync:Update(${n})`);
    await dotNetHelper2.invokeMethodAsync('Update', n);

    n = randomInt();
    console.log(`JS: invokeMethodAsync:UpdateAsync(${n})`);
    await dotNetHelper2.invokeMethodAsync('UpdateAsync', n);

    if (syncInterop) {
      n = randomInt();
      console.log(`JS: invokeMethod:Update(${n})`);
      dotNetHelper2.invokeMethod('Update', n);
    }
  };
</script>

Note

Zie JSvoor algemene richtlijnen voor Blazor locatie en onze aanbevelingen voor productie-apps.

In de volgende GenericsExample component:

  • De JS functie invokeMethodsAsync wordt aangeroepen wanneer de Invoke Interop knop is geselecteerd.
  • Er worden twee DotNetObjectReference typen gemaakt en doorgegeven aan de JS functie voor instanties van de GenericType als een string en een int.

GenericsExample.razor:

@page "/generics-example"
@implements IDisposable
@inject IJSRuntime JS

<p>
    <button @onclick="InvokeInterop">Invoke Interop</button>
</p>

<ul>
    <li>genericType1: @genericType1?.Value</li>
    <li>genericType2: @genericType2?.Value</li>
</ul>

@code {
    private GenericType<string> genericType1 = new() { Value = "string 0" };
    private GenericType<int> genericType2 = new() { Value = 0 };
    private DotNetObjectReference<GenericType<string>>? objRef1;
    private DotNetObjectReference<GenericType<int>>? objRef2;

    protected override void OnInitialized()
    {
        objRef1 = DotNetObjectReference.Create(genericType1);
        objRef2 = DotNetObjectReference.Create(genericType2);
    }

    public async Task InvokeInterop()
    {
        var syncInterop = OperatingSystem.IsBrowser();

        await JS.InvokeVoidAsync(
            "invokeMethodsAsync", syncInterop, objRef1, objRef2);
    }

    public void Dispose()
    {
        objRef1?.Dispose();
        objRef2?.Dispose();
    }
}
@page "/generics-example"
@implements IDisposable
@inject IJSRuntime JS

<p>
    <button @onclick="InvokeInterop">Invoke Interop</button>
</p>

<ul>
    <li>genericType1: @genericType1?.Value</li>
    <li>genericType2: @genericType2?.Value</li>
</ul>

@code {
    private GenericType<string> genericType1 = new() { Value = "string 0" };
    private GenericType<int> genericType2 = new() { Value = 0 };
    private DotNetObjectReference<GenericType<string>>? objRef1;
    private DotNetObjectReference<GenericType<int>>? objRef2;

    protected override void OnInitialized()
    {
        objRef1 = DotNetObjectReference.Create(genericType1);
        objRef2 = DotNetObjectReference.Create(genericType2);
    }

    public async Task InvokeInterop()
    {
        var syncInterop = OperatingSystem.IsBrowser();

        await JS.InvokeVoidAsync(
            "invokeMethodsAsync", syncInterop, objRef1, objRef2);
    }

    public void Dispose()
    {
        objRef1?.Dispose();
        objRef2?.Dispose();
    }
}

In het voorgaande voorbeeld JS is een geïnjecteerd IJSRuntime exemplaar. IJSRuntime wordt geregistreerd door het Blazor framework.

Hieronder ziet u de typische uitvoer van het voorgaande voorbeeld wanneer de Invoke Interop knop is geselecteerd in een onderdeel aan de clientzijde:

JS: invokeMethodAsync:Update('string 37802')
.NET: Update: GenericType<System.String>: tekenreeks 37802
JS: invokeMethodAsync:UpdateAsync('string 53051')
JS: invokeMethod:Update('string 26784')
.NET: Update: GenericType<System.String>: tekenreeks 26784
JS: invokeMethodAsync:Update(14107)
.NET: Bijwerken: GenericType<System.Int32>: 14107
JS: invokeMethodAsync:UpdateAsync(48995)
JS: invokeMethod:Update(12872)
.NET: Update: GenericType<System.Int32>: 12872
.NET: UpdateAsync: GenericType<System.String>: tekenreeks 53051
.NET: UpdateAsync: GenericType<System.Int32>: 48995

Als het voorgaande voorbeeld wordt geïmplementeerd in een server-side onderdeel, worden de synchrone aanroepen met invokeMethod vermeden. Voor onderdelen aan de serverzijde raden we de asynchrone functie (invokeMethodAsync) aan via de synchrone versie (invokeMethod).

Typische uitvoer van een onderdeel aan de serverzijde:

JS: invokeMethodAsync:Update('string 34809')
.NET: Update: GenericType<System.String>: tekenreeks 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Bijwerken: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: tekenreeks 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652

In de voorgaande uitvoervoorbeelden ziet u dat asynchrone methoden in een willekeurige volgorde worden uitgevoerd en voltooid, afhankelijk van verschillende factoren, waaronder threadplanning en de snelheid van de uitvoering van de methode. Het is niet mogelijk om de volgorde van voltooiing voor asynchrone methodeaanroepen betrouwbaar te voorspellen.

Voorbeelden van klasse-instanties

De volgende sayHello1JS functie:

  • Roept de GetHelloMessage .NET-methode aan op de doorgegeven DotNetObjectReference.
  • Retourneert het bericht van GetHelloMessage naar de sayHello1 aanroeper.
<script>
  window.sayHello1 = (dotNetHelper) => {
    return dotNetHelper.invokeMethodAsync('GetHelloMessage');
  };
</script>

Note

Zie JSvoor algemene richtlijnen voor Blazor locatie en onze aanbevelingen voor productie-apps.

In het voorgaande voorbeeld is de naam dotNetHelper van de variabele willekeurig en kan deze worden gewijzigd in elke voorkeursnaam.

De volgende HelloHelper klasse heeft een aanroepbare .NET-methode met de naam JS. Wanneer HelloHelper wordt gemaakt, wordt de naam in de Name eigenschap gebruikt om een bericht terug te geven van GetHelloMessage.

HelloHelper.cs:

using Microsoft.JSInterop;

namespace BlazorSample;

public class HelloHelper(string? name)
{
    public string? Name { get; set; } = name ?? "No Name";

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;

namespace BlazorSample;

public class HelloHelper(string? name)
{
    public string? Name { get; set; } = name ?? "No Name";

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;

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

    public string? Name { get; set; }

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;

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

    public string? Name { get; set; }

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;

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

    public string Name { get; set; }

    [JSInvokable]
    public string GetHelloMessage() => $"Hello, {Name}!";
}
using Microsoft.JSInterop;

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

    public string Name { get; set; }

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

De CallHelloHelperGetHelloMessage methode in de volgende JsInteropClasses3 klasse roept de JS functie sayHello1 aan met een nieuw exemplaar van HelloHelper.

JsInteropClasses3.cs:

using Microsoft.JSInterop;

namespace BlazorSample;

public class JsInteropClasses3(IJSRuntime js)
{
    private readonly IJSRuntime js = js;

    public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        return await js.InvokeAsync<string>("sayHello1", objRef);
    }
}
using Microsoft.JSInterop;

namespace BlazorSample;

public class JsInteropClasses3(IJSRuntime js)
{
    private readonly IJSRuntime js = js;

    public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        return await js.InvokeAsync<string>("sayHello1", objRef);
    }
}
using Microsoft.JSInterop;

public class JsInteropClasses3
{
    private readonly IJSRuntime js;

    public JsInteropClasses3(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        return await js.InvokeAsync<string>("sayHello1", objRef);
    }
}
using Microsoft.JSInterop;

public class JsInteropClasses3
{
    private readonly IJSRuntime js;

    public JsInteropClasses3(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask<string> CallHelloHelperGetHelloMessage(string? name)
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        return await js.InvokeAsync<string>("sayHello1", objRef);
    }
}
using System.Threading.Tasks;
using Microsoft.JSInterop;

public class JsInteropClasses3
{
    private readonly IJSRuntime js;

    public JsInteropClasses3(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask<string> CallHelloHelperGetHelloMessage(string name)
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        return await js.InvokeAsync<string>("sayHello1", objRef);
    }
}
using System.Threading.Tasks;
using Microsoft.JSInterop;

public class JsInteropClasses3
{
    private readonly IJSRuntime js;

    public JsInteropClasses3(IJSRuntime js)
    {
        this.js = js;
    }

    public async ValueTask<string> CallHelloHelperGetHelloMessage(string name)
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        return await js.InvokeAsync<string>("sayHello1", objRef);
    }
}

Om een geheugenlek te voorkomen en garbagecollection toe te staan, wordt de .NET-objectverwijzing die is gemaakt door DotNetObjectReference verwijderd wanneer de objectverwijzing uit scope raakt via de using var-syntaxis.

Wanneer de Trigger .NET instance method knop is geselecteerd in het volgende onderdeel, JsInteropClasses3.CallHelloHelperGetHelloMessage wordt aangeroepen met de waarde van name.

CallDotnet4.razor:

@page "/call-dotnet-4"
@inject IJSRuntime JS

<PageTitle>Call .NET 4</PageTitle>

<h1>Call .NET Example 4</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private JsInteropClasses3? jsInteropClasses;

    protected override void OnInitialized() => 
        jsInteropClasses = new JsInteropClasses3(JS);

    private async Task TriggerDotNetInstanceMethod()
    {
        if (jsInteropClasses is not null)
        {
            result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
        }
    }
}

CallDotnet4.razor:

@page "/call-dotnet-4"
@inject IJSRuntime JS

<PageTitle>Call .NET 4</PageTitle>

<h1>Call .NET Example 4</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private JsInteropClasses3? jsInteropClasses;

    protected override void OnInitialized() => 
        jsInteropClasses = new JsInteropClasses3(JS);

    private async Task TriggerDotNetInstanceMethod()
    {
        if (jsInteropClasses is not null)
        {
            result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
        }
    }
}

CallDotNetExample4.razor:

@page "/call-dotnet-example-4"
@inject IJSRuntime JS

<h1>Call .NET Example 4</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private JsInteropClasses3? jsInteropClasses;

    protected override void OnInitialized()
    {
        jsInteropClasses = new JsInteropClasses3(JS);
    }

    private async Task TriggerDotNetInstanceMethod()
    {
        if (jsInteropClasses is not null)
        {
            result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
        }
    }
}

CallDotNetExample4.razor:

@page "/call-dotnet-example-4"
@inject IJSRuntime JS

<h1>Call .NET Example 4</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;
    private JsInteropClasses3? jsInteropClasses;

    protected override void OnInitialized()
    {
        jsInteropClasses = new JsInteropClasses3(JS);
    }

    private async Task TriggerDotNetInstanceMethod()
    {
        if (jsInteropClasses is not null)
        {
            result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
        }
    }
}

CallDotNetExample4.razor:

@page "/call-dotnet-example-4"
@inject IJSRuntime JS

<h1>Call .NET Example 4</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private JsInteropClasses3 jsInteropClasses;

    protected override void OnInitialized()
    {
        jsInteropClasses = new JsInteropClasses3(JS);
    }

    private async Task TriggerDotNetInstanceMethod()
    {
        result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
    }
}

CallDotNetExample4.razor:

@page "/call-dotnet-example-4"
@inject IJSRuntime JS

<h1>Call .NET Example 4</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;
    private JsInteropClasses3 jsInteropClasses;

    protected override void OnInitialized()
    {
        jsInteropClasses = new JsInteropClasses3(JS);
    }

    private async Task TriggerDotNetInstanceMethod()
    {
        result = await jsInteropClasses.CallHelloHelperGetHelloMessage(name);
    }
}

In de volgende afbeelding ziet u het weergegeven onderdeel met de naam Amy Pond in het Name veld. Nadat de knop is geselecteerd, Hello, Amy Pond! wordt deze weergegeven in de gebruikersinterface:

Voorbeeld van het onderdeel CallDotNetExample4 weergegeven

Het voorgaande patroon dat in de JsInteropClasses3 klasse wordt weergegeven, kan ook volledig in een onderdeel worden geïmplementeerd.

CallDotnet5.razor:

@page "/call-dotnet-5"
@inject IJSRuntime JS

<PageTitle>Call .NET 5</PageTitle>

<h1>Call .NET Example 5</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;

    public async Task TriggerDotNetInstanceMethod()
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }
}

CallDotnet5.razor:

@page "/call-dotnet-5"
@inject IJSRuntime JS

<PageTitle>Call .NET 5</PageTitle>

<h1>Call .NET Example 5</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;

    public async Task TriggerDotNetInstanceMethod()
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }
}

CallDotNetExample5.razor:

@page "/call-dotnet-example-5"
@inject IJSRuntime JS

<h1>Call .NET Example 5</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;

    public async Task TriggerDotNetInstanceMethod()
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }
}

CallDotNetExample5.razor:

@page "/call-dotnet-example-5"
@inject IJSRuntime JS

<h1>Call .NET Example 5</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string? name;
    private string? result;

    public async Task TriggerDotNetInstanceMethod()
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }
}

CallDotNetExample5.razor:

@page "/call-dotnet-example-5"
@inject IJSRuntime JS

<h1>Call .NET Example 5</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;

    public async Task TriggerDotNetInstanceMethod()
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }
}

CallDotNetExample5.razor:

@page "/call-dotnet-example-5"
@inject IJSRuntime JS

<h1>Call .NET Example 5</h1>

<p>
    <label>
        Name: <input @bind="name" />
    </label>
</p>

<p>
    <button @onclick="TriggerDotNetInstanceMethod">
        Trigger .NET instance method
    </button>
</p>

<p>
    @result
</p>

@code {
    private string name;
    private string result;

    public async Task TriggerDotNetInstanceMethod()
    {
        using var objRef = DotNetObjectReference.Create(new HelloHelper(name));
        result = await JS.InvokeAsync<string>("sayHello1", objRef);
    }
}

Om een geheugenlek te voorkomen en garbagecollection toe te staan, wordt de .NET-objectverwijzing die is gemaakt door DotNetObjectReference verwijderd wanneer de objectverwijzing uit scope raakt via de using var-syntaxis.

De uitvoer die door het onderdeel wordt weergegeven, is Hello, Amy Pond! wanneer de naam Amy Pond wordt opgegeven in het name veld.

In het voorgaande onderdeel wordt de .NET-objectverwijzing verwijderd. Als een klasse of component de DotNetObjectReference niet verwijdert, verwijder het dan van de client door de methode dispose aan te roepen op het doorgegeven DotNetObjectReference:

window.{JS FUNCTION NAME} = (dotNetHelper) => {
  dotNetHelper.invokeMethodAsync('{.NET METHOD ID}');
  dotNetHelper.dispose();
}

In het voorgaande voorbeeld:

  • De {JS FUNCTION NAME} tijdelijke aanduiding is de naam van de JS functie.
  • De naam dotNetHelper van de variabele is willekeurig en kan worden gewijzigd in elke voorkeursnaam.
  • De {.NET METHOD ID} tijdelijke aanduiding is de .NET-methode-id.

Helperklasse voor .NET-methoden voor componentinstanties

Een helperklasse kan een .NET-exemplaarmethode aanroepen als een Action. Helperklassen zijn handig in scenario's waarin het gebruik van statische .NET-methoden niet van toepassing is:

  • Wanneer verschillende onderdelen van hetzelfde type worden weergegeven op dezelfde pagina.
  • In serverside applicaties waarin meerdere gebruikers gelijktijdig hetzelfde onderdeel gebruiken.

In het volgende voorbeeld:

  • Het onderdeel bevat verschillende ListItem1 onderdelen.
  • Elk ListItem1 onderdeel bestaat uit een bericht en een knop.
  • Wanneer een ListItem1 componentknop is geselecteerd, wijzigt de ListItem1-methode van de UpdateMessage de tekst van het lijstitem en wordt de knop verborgen.

De volgende MessageUpdateInvokeHelper klasse onderhoudt een JS.NET-methode UpdateMessageCallerdie kan worden aangeroepen om de Action opgegeven methode aan te roepen wanneer de klasse wordt geïnstantieerd.

MessageUpdateInvokeHelper.cs:

using Microsoft.JSInterop;

namespace BlazorSample;

public class MessageUpdateInvokeHelper(Action action)
{
    private readonly Action action = action;

    [JSInvokable]
    public void UpdateMessageCaller() => action.Invoke();
}
using Microsoft.JSInterop;

namespace BlazorSample;

public class MessageUpdateInvokeHelper(Action action)
{
    private readonly Action action = action;

    [JSInvokable]
    public void UpdateMessageCaller() => action.Invoke();
}
using Microsoft.JSInterop;

public class MessageUpdateInvokeHelper
{
    private Action action;

    public MessageUpdateInvokeHelper(Action action)
    {
        this.action = action;
    }

    [JSInvokable]
    public void UpdateMessageCaller()
    {
        action.Invoke();
    }
}
using Microsoft.JSInterop;

public class MessageUpdateInvokeHelper
{
    private Action action;

    public MessageUpdateInvokeHelper(Action action)
    {
        this.action = action;
    }

    [JSInvokable]
    public void UpdateMessageCaller()
    {
        action.Invoke();
    }
}
using System;
using Microsoft.JSInterop;

public class MessageUpdateInvokeHelper
{
    private Action action;

    public MessageUpdateInvokeHelper(Action action)
    {
        this.action = action;
    }

    [JSInvokable]
    public void UpdateMessageCaller()
    {
        action.Invoke();
    }
}
using System;
using Microsoft.JSInterop;

public class MessageUpdateInvokeHelper
{
    private Action action;

    public MessageUpdateInvokeHelper(Action action)
    {
        this.action = action;
    }

    [JSInvokable]
    public void UpdateMessageCaller()
    {
        action.Invoke();
    }
}

Met de volgende updateMessageCallerJS functie wordt de UpdateMessageCaller .NET-methode aangeroepen.

<script>
  window.updateMessageCaller = (dotNetHelper) => {
    dotNetHelper.invokeMethodAsync('UpdateMessageCaller');
    dotNetHelper.dispose();
  }
</script>

Note

Zie JSvoor algemene richtlijnen voor Blazor locatie en onze aanbevelingen voor productie-apps.

In het voorgaande voorbeeld is de naam dotNetHelper van de variabele willekeurig en kan deze worden gewijzigd in elke voorkeursnaam.

Het volgende ListItem1-onderdeel is een gedeeld onderdeel dat elk gewenst aantal keren in een oudercomponent kan worden gebruikt en lijstitems (<li>...</li>) voor een HTML-lijst (<ul>...</ul> of <ol>...</ol>) kan maken. Met elke ListItem1 componentinstantie maakt een exemplaar van MessageUpdateInvokeHelper, waarbij Action is ingesteld op de UpdateMessage methode.

Wanneer de knop van een ListItem1 onderdeel is geselecteerd, InteropCall wordt aangeroepen met een gemaakt updateMessageCaller voor het DotNetObjectReferenceMessageUpdateInvokeHelper exemplaar. Hierdoor kan het framework UpdateMessageCaller aanroepen op de ListItem1-instantie van die MessageUpdateInvokeHelper. Het doorgegeven DotNetObjectReference wordt afgehandeld in JS (dotNetHelper.dispose()).

ListItem1.razor:

@inject IJSRuntime JS

<li>
    @message
    <button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>

@code {
    private string message = "Select one of these list item buttons.";
    private string display = "inline-block";
    private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;

    protected override void OnInitialized()
    {
        messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
    }

    protected async Task InteropCall()
    {
        if (messageUpdateInvokeHelper is not null)
        {
            await JS.InvokeVoidAsync("updateMessageCaller",
                DotNetObjectReference.Create(messageUpdateInvokeHelper));
        }
    }

    private void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }
}
@inject IJSRuntime JS

<li>
    @message
    <button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>

@code {
    private string message = "Select one of these list item buttons.";
    private string display = "inline-block";
    private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;

    protected override void OnInitialized()
    {
        messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
    }

    protected async Task InteropCall()
    {
        if (messageUpdateInvokeHelper is not null)
        {
            await JS.InvokeVoidAsync("updateMessageCaller",
                DotNetObjectReference.Create(messageUpdateInvokeHelper));
        }
    }

    private void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }
}
@inject IJSRuntime JS

<li>
    @message
    <button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>

@code {
    private string message = "Select one of these list item buttons.";
    private string display = "inline-block";
    private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;

    protected override void OnInitialized()
    {
        messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
    }

    protected async Task InteropCall()
    {
        if (messageUpdateInvokeHelper is not null)
        {
            await JS.InvokeVoidAsync("updateMessageCaller",
                DotNetObjectReference.Create(messageUpdateInvokeHelper));
        }
    }

    private void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }
}
@inject IJSRuntime JS

<li>
    @message
    <button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>

@code {
    private string message = "Select one of these list item buttons.";
    private string display = "inline-block";
    private MessageUpdateInvokeHelper? messageUpdateInvokeHelper;

    protected override void OnInitialized()
    {
        messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
    }

    protected async Task InteropCall()
    {
        if (messageUpdateInvokeHelper is not null)
        {
            await JS.InvokeVoidAsync("updateMessageCaller",
                DotNetObjectReference.Create(messageUpdateInvokeHelper));
        }
    }

    private void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }
}
@inject IJSRuntime JS

<li>
    @message
    <button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>

@code {
    private string message = "Select one of these list item buttons.";
    private string display = "inline-block";
    private MessageUpdateInvokeHelper messageUpdateInvokeHelper;

    protected override void OnInitialized()
    {
        messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
    }

    protected async Task InteropCall()
    {
        await JS.InvokeVoidAsync("updateMessageCaller",
            DotNetObjectReference.Create(messageUpdateInvokeHelper));
    }

    private void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }
}
@inject IJSRuntime JS

<li>
    @message
    <button @onclick="InteropCall" style="display:@display">InteropCall</button>
</li>

@code {
    private string message = "Select one of these list item buttons.";
    private string display = "inline-block";
    private MessageUpdateInvokeHelper messageUpdateInvokeHelper;

    protected override void OnInitialized()
    {
        messageUpdateInvokeHelper = new MessageUpdateInvokeHelper(UpdateMessage);
    }

    protected async Task InteropCall()
    {
        await JS.InvokeVoidAsync("updateMessageCaller",
            DotNetObjectReference.Create(messageUpdateInvokeHelper));
    }

    private void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }
}

StateHasChanged wordt aangeroepen om de gebruikersinterface bij te werken wanneer message is ingesteld in UpdateMessage. Als StateHasChanged niet wordt aangeroepen, heeft Blazor geen manier om te weten dat de gebruikersinterface moet worden bijgewerkt wanneer de Action wordt aangeroepen.

Het volgende bovenliggende onderdeel bevat vier lijstitems, elk een exemplaar van het ListItem1 onderdeel.

CallDotnet6.razor:

@page "/call-dotnet-6"

<PageTitle>Call .NET 6</PageTitle>

<h1>Call .NET Example 6</h1>

<ul>
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
</ul>

CallDotnet6.razor:

@page "/call-dotnet-6"

<PageTitle>Call .NET 6</PageTitle>

<h1>Call .NET Example 6</h1>

<ul>
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
</ul>

CallDotNetExample6.razor:

@page "/call-dotnet-example-6"

<h1>Call .NET Example 6</h1>

<ul>
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
</ul>

CallDotNetExample6.razor:

@page "/call-dotnet-example-6"

<h1>Call .NET Example 6</h1>

<ul>
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
</ul>

CallDotNetExample6.razor:

@page "/call-dotnet-example-6"

<h1>Call .NET Example 6</h1>

<ul>
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
</ul>

CallDotNetExample6.razor:

@page "/call-dotnet-example-6"

<h1>Call .NET Example 6</h1>

<ul>
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
    <ListItem1 />
</ul>

In de volgende afbeelding ziet u het weergegeven oudercomponent nadat de tweede InteropCall knop is geselecteerd.

  • Het tweede ListItem1 onderdeel heeft het UpdateMessage Called! bericht weergegeven.
  • De InteropCall knop voor het tweede ListItem1 onderdeel is niet zichtbaar omdat de CSS-eigenschap display van de knop is ingesteld op none.

Voorbeeld van het onderdeel CallDotNetExample6 weergegeven

.NET-methode van componentinstantie aangeroepen vanuit DotNetObjectReference en toegewezen aan een elementeigenschap

De toewijzing van een DotNetObjectReference aan een eigenschap van een HTML-element maakt het mogelijk om .NET-methoden op een onderdeelexemplaar aan te roepen.

Deze benadering is vergelijkbaar met de benadering beschreven in het gedeelte Component Instance .NET-methode helperklasse. Deze benadering is nuttig in scenario's waarin het gebruik van statische .NET-methoden niet toepasbaar is:

  • Wanneer verschillende onderdelen van hetzelfde type worden weergegeven op dezelfde pagina.
  • In serverside applicaties waarin meerdere gebruikers gelijktijdig hetzelfde onderdeel gebruiken.
  • De .NET-methode wordt aangeroepen vanuit een JS gebeurtenis (bijvoorbeeld onclick), niet van een Blazor gebeurtenis (bijvoorbeeld @onclick).

In het volgende voorbeeld:

  • Het onderdeel bevat verschillende ListItem2 onderdelen, een gedeeld onderdeel.
  • Elk ListItem2 component bestaat uit een lijstitembericht <span> en een tweede <span> waarop een display CSS-eigenschap is ingesteld inline-block voor weergave.
  • Wanneer een ListItem2 lijstitem is geselecteerd, verandert de ListItem2-methode van UpdateMessage de tekst van het lijstitem in de eerste <span> en verbergt de tweede <span> door de eigenschap van de tweede <span> in te stellen op none.

De volgende assignDotNetHelperJS functie wijst de DotNetObjectReference toe aan een element in een eigenschap genaamd dotNetHelper. De volgende interopCallJS functie gebruikt het DotNetObjectReference voor het doorgegeven element om een .NET-methode aan te roepen met de naam UpdateMessage.

ListItem2.razor.js:

export function assignDotNetHelper(element, dotNetHelper) {
  element.dotNetHelper = dotNetHelper;
}

export async function interopCall(element) {
  await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}

ListItem2.razor.js:

export function assignDotNetHelper(element, dotNetHelper) {
  element.dotNetHelper = dotNetHelper;
}

export async function interopCall(element) {
  await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
}
<script>
  window.assignDotNetHelper = (element, dotNetHelper) => {
    element.dotNetHelper = dotNetHelper;
  }

  window.interopCall = async (element) => {
    await element.dotNetHelper.invokeMethodAsync('UpdateMessage');
  }
</script>

Note

Zie JSvoor algemene richtlijnen voor Blazor locatie en onze aanbevelingen voor productie-apps.

In het voorgaande voorbeeld is de naam dotNetHelper van de variabele willekeurig en kan deze worden gewijzigd in elke voorkeursnaam.

Het volgende ListItem2-onderdeel is een gedeeld onderdeel dat elk gewenst aantal keren in een oudercomponent kan worden gebruikt en lijstitems (<li>...</li>) voor een HTML-lijst (<ul>...</ul> of <ol>...</ol>) kan maken.

Elke ListItem2 onderdeelexemplaar roept de assignDotNetHelperJS functie aan in OnAfterRenderAsync met een referentie naar een element (het eerste <span> element van het lijstitem) en het onderdeelexemplaar als een DotNetObjectReference.

Wanneer een bericht van een ListItem2 component is geselecteerd, wordt <span> aangeroepen met het interopCall element als parameter (<span>), waarmee de this .NET-methode wordt aangeroepen.UpdateMessage In UpdateMessagewordt StateHasChanged aangeroepen om de gebruikersinterface bij te werken wanneer message deze is ingesteld en de display eigenschap van de tweede <span> wordt bijgewerkt. Als StateHasChanged niet wordt aangeroepen, heeft Blazor geen manier om te weten dat de gebruikersinterface moet worden bijgewerkt wanneer de methode wordt aangeroepen.

Het DotNetObjectReference wordt weggegooid wanneer het onderdeel wordt verwijderd.

ListItem2.razor:

@inject IJSRuntime JS
@implements IAsyncDisposable

<li>
    <span style="font-weight:bold;color:@color" @ref="elementRef"
        @onclick="CallJSToInvokeDotnet">
        @message
    </span>
    <span style="display:@display">
        Not Updated Yet!
    </span>
</li>

@code {
    private IJSObjectReference? module;
    private DotNetObjectReference<ListItem2>? objRef;
    private ElementReference elementRef;
    private string display = "inline-block";
    private string message = "Select one of these list items.";
    private string color = "initial";

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./Components/ListItem2.razor.js");

            objRef = DotNetObjectReference.Create(this);
            await module.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
        }
    }

    public async Task CallJSToInvokeDotnet()
    {
        if (module is not null)
        {
            await module.InvokeVoidAsync("interopCall", elementRef);
        }
    }

    [JSInvokable]
    public void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        color = "MediumSeaGreen";
        StateHasChanged();
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }

        objRef?.Dispose();
    }
}
@inject IJSRuntime JS
@implements IAsyncDisposable

<li>
    <span style="font-weight:bold;color:@color" @ref="elementRef"
        @onclick="CallJSToInvokeDotnet">
        @message
    </span>
    <span style="display:@display">
        Not Updated Yet!
    </span>
</li>

@code {
    private IJSObjectReference? module;
    private DotNetObjectReference<ListItem2>? objRef;
    private ElementReference elementRef;
    private string display = "inline-block";
    private string message = "Select one of these list items.";
    private string color = "initial";

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import",
                "./Components/ListItem2.razor.js");

            objRef = DotNetObjectReference.Create(this);
            await module.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
        }
    }

    public async Task CallJSToInvokeDotnet()
    {
        if (module is not null)
        {
            await module.InvokeVoidAsync("interopCall", elementRef);
        }
    }

    [JSInvokable]
    public void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        color = "MediumSeaGreen";
        StateHasChanged();
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }

        objRef?.Dispose();
    }
}
@inject IJSRuntime JS

<li>
    <span @ref="elementRef" onclick="interopCall(this)">@message</span>
    <span style="display:@display">Not Updated Yet!</span>
</li>

@code {
    private DotNetObjectReference<ListItem2>? objRef;
    private ElementReference elementRef;
    private string display = "inline-block";
    private string message = "Select one of these list items.";

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            objRef = DotNetObjectReference.Create(this);
            await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
        }
    }

    [JSInvokable]
    public void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }

    public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS

<li>
    <span @ref="elementRef" onclick="interopCall(this)">@message</span>
    <span style="display:@display">Not Updated Yet!</span>
</li>

@code {
    private DotNetObjectReference<ListItem2>? objRef;
    private ElementReference elementRef;
    private string display = "inline-block";
    private string message = "Select one of these list items.";

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            objRef = DotNetObjectReference.Create(this);
            await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
        }
    }

    [JSInvokable]
    public void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }

    public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS

<li>
    <span @ref="elementRef" onclick="interopCall(this)">@message</span>
    <span style="display:@display">Not Updated Yet!</span>
</li>

@code {
    private DotNetObjectReference<ListItem2> objRef;
    private ElementReference elementRef;
    private string display = "inline-block";
    private string message = "Select one of these list items.";

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            objRef = DotNetObjectReference.Create(this);
            await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
        }
    }

    [JSInvokable]
    public void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }

    public void Dispose() => objRef?.Dispose();
}
@inject IJSRuntime JS

<li>
    <span @ref="elementRef" onclick="interopCall(this)">@message</span>
    <span style="display:@display">Not Updated Yet!</span>
</li>

@code {
    private DotNetObjectReference<ListItem2> objRef;
    private ElementReference elementRef;
    private string display = "inline-block";
    private string message = "Select one of these list items.";

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            objRef = DotNetObjectReference.Create(this);
            await JS.InvokeVoidAsync("assignDotNetHelper", elementRef, objRef);
        }
    }

    [JSInvokable]
    public void UpdateMessage()
    {
        message = "UpdateMessage Called!";
        display = "none";
        StateHasChanged();
    }

    public void Dispose() => objRef?.Dispose();
}

Het volgende bovenliggende onderdeel bevat vier lijstitems, elk een exemplaar van het ListItem2 onderdeel.

CallDotnet7.razor:

@page "/call-dotnet-7"

<PageTitle>Call .NET 7</PageTitle>

<h1>Call .NET Example 7</h1>

<ul>
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
</ul>

CallDotnet7.razor:

@page "/call-dotnet-7"

<PageTitle>Call .NET 7</PageTitle>

<h1>Call .NET Example 7</h1>

<ul>
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
</ul>

CallDotNetExample7.razor:

@page "/call-dotnet-example-7"

<h1>Call .NET Example 7</h1>

<ul>
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
</ul>

CallDotNetExample7.razor:

@page "/call-dotnet-example-7"

<h1>Call .NET Example 7</h1>

<ul>
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
</ul>

CallDotNetExample7.razor:

@page "/call-dotnet-example-7"

<h1>Call .NET Example 7</h1>

<ul>
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
</ul>

CallDotNetExample7.razor:

@page "/call-dotnet-example-7"

<h1>Call .NET Example 7</h1>

<ul>
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
    <ListItem2 />
</ul>

Synchrone JS interoperabiliteit in clientonderdelen

Deze sectie is alleen van toepassing op onderdelen aan de clientzijde.

JS interop-aanroepen zijn altijd asynchroon, ongeacht of de aangeroepen code synchroon of asynchroon is. Aanroepen zijn asynchroon om ervoor te zorgen dat onderdelen compatibel zijn met de rendermodi aan de serverzijde en clientzijde. Op de server moeten alle JS interop-aanroepen asynchroon zijn omdat ze via een netwerkverbinding worden verzonden.

Als u zeker weet dat uw onderdeel alleen wordt uitgevoerd op WebAssembly, kunt u ervoor kiezen om synchrone JS interop-aanroepen uit te voeren. Dit heeft iets minder overhead dan het maken van asynchrone aanroepen en kan leiden tot minder rendercycli, omdat er geen tussenliggende status is tijdens het wachten op resultaten.

Gebruik DotNet.invokeMethod in plaats van DotNet.invokeMethodAsyncom een synchrone aanroep van JavaScript naar .NET te maken in een onderdeel aan de clientzijde.

Synchrone aanroepen werken als:

  • Het onderdeel wordt alleen weergegeven voor uitvoering op WebAssembly.
  • De aangeroepen functie retourneert een waarde synchroon. De functie is geen async methode en retourneert geen .NET-Task of JavaScript-Promise.

JavaScript location

JavaScript-code (JS) laden met behulp van een van de methoden die worden beschreven in het artikel over javaScript-locatie:

Het gebruik van JS-modules om JS te laden, wordt beschreven in dit artikel in de paragraaf JavaScript-isolatie in JavaScript-modules.

Warning

Plaats alleen een <script> tag in een onderdeelbestand (.razor) als het onderdeel gegarandeerd statische rendering aan serverszijde (static SSR) adopteert, omdat de tag niet dynamisch kan worden bijgewerkt.

Warning

Plaats geen <script> tag in een onderdeelbestand (.razor) omdat de tag <script> niet dynamisch kan worden bijgewerkt.

JavaScript-isolatie in JavaScript-modules

Blazor maakt isolatie van JavaScript (JS) mogelijk in standaard JavaScript-modules (ECMAScript-specificatie). Laden van JavaScript-modules werkt op dezelfde manier in Blazor als voor andere typen web-apps en u kunt aanpassen hoe modules in uw app worden gedefinieerd. Zie MDN-webdocumenten: JavaScript-modulesvoor een handleiding over het gebruik van JavaScript-modules.

JS isolatie biedt de volgende voordelen:

  • Geïmporteerde JS vervuilt de globale naamruimte niet meer.
  • Gebruikers van een bibliotheek en componenten hoeven de gerelateerde JSniet te importeren.

Zie JavaScript-functies aanroepen vanuit .NET-methoden in ASP.NET Core Blazorvoor meer informatie.

Dynamisch importeren met de import()-operator wordt ondersteund met ASP.NET Core en Blazor:

if ({CONDITION}) import("/additionalModule.js");

In het voorgaande voorbeeld vertegenwoordigt de tijdelijke aanduiding {CONDITION} een voorwaardelijke controle om te bepalen of de module moet worden geladen.

Zie Kan ik gebruiken: JavaScript-modules: dynamische importvoor browsercompatibiliteit.

Vermijd kringverwijzingen naar objecten

Objecten die kringverwijzingen bevatten, kunnen niet op de client worden geserialiseerd voor:

  • Aanroepen van .NET-methoden.
  • Aanroepen van JavaScript-methoden vanuit C# wanneer het retourtype circulaire referenties bevat.

Ondersteuning voor bytematrix

Blazor ondersteunt geoptimaliseerde byte-array JavaScript-interoperabiliteit (JS) die het encoderen/decoderen van byte-arrays naar Base64 vermijdt. In het volgende voorbeeld wordt interop gebruikt JS om een bytematrix door te geven aan .NET.

Geef een sendByteArrayJS-functie op. De functie wordt statisch aangeroepen door een knop in de component, waarbij de parameter assemblynaam in de invokeMethodAsync aanroep is opgenomen, en retourneert geen waarde.

CallDotnet8.razor.js:

export function sendByteArray() {
  const data = new Uint8Array([0x45, 0x76, 0x65, 0x72, 0x79, 0x74, 0x68, 0x69,
    0x6e, 0x67, 0x27, 0x73, 0x20, 0x73, 0x68, 0x69, 0x6e, 0x79, 0x2c,
    0x20, 0x43, 0x61, 0x70, 0x74, 0x61, 0x69, 0x6e, 0x2e, 0x20, 0x4e,
    0x6f, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x72, 0x65, 0x74, 0x2e]);
  DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
    .then(str => {
      alert(str);
    });
}

export function addHandlers() {
  const btn = document.getElementById("btn");
  btn.addEventListener("click", sendByteArray);
}
<script>
  window.sendByteArray = () => {
    const data = new Uint8Array([0x45,0x76,0x65,0x72,0x79,0x74,0x68,0x69,
      0x6e,0x67,0x27,0x73,0x20,0x73,0x68,0x69,0x6e,0x79,0x2c,
      0x20,0x43,0x61,0x70,0x74,0x61,0x69,0x6e,0x2e,0x20,0x4e,
      0x6f,0x74,0x20,0x74,0x6f,0x20,0x66,0x72,0x65,0x74,0x2e]);
    DotNet.invokeMethodAsync('BlazorSample', 'ReceiveByteArray', data)
      .then(str => {
        alert(str);
      });
  };
</script>

Note

Zie JSvoor algemene richtlijnen voor Blazor locatie en onze aanbevelingen voor productie-apps.

CallDotnet8.razor:

@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET 8</PageTitle>

<h1>Call .NET Example 8</h1>

<p>
    <button id="btn">Send Bytes</button>
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>

@code {
    private IJSObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import", 
                "./Components/Pages/CallDotnet8.razor.js");

            await module.InvokeVoidAsync("addHandlers");
        }
    }

    [JSInvokable]
    public static Task<string> ReceiveByteArray(byte[] receivedBytes) => 
        Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0, 
            receivedBytes.Length));

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }
    }
}

CallDotnet8.razor:

@page "/call-dotnet-8"
@using System.Text
@implements IAsyncDisposable
@inject IJSRuntime JS

<PageTitle>Call .NET 8</PageTitle>

<h1>Call .NET Example 8</h1>

<p>
    <button id="btn">Send Bytes</button>
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>

@code {
    private IJSObjectReference? module;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import", 
                "./Components/Pages/CallDotnet8.razor.js");

            await module.InvokeVoidAsync("addHandlers");
        }
    }

    [JSInvokable]
    public static Task<string> ReceiveByteArray(byte[] receivedBytes) => 
        Task.FromResult(Encoding.UTF8.GetString(receivedBytes, 0, 
            receivedBytes.Length));

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            try
            {
                await module.DisposeAsync();
            }
            catch (JSDisconnectedException)
            {
            }
        }
    }
}

CallDotNetExample8.razor:

@page "/call-dotnet-example-8"
@using System.Text

<PageTitle>Call .NET 8</PageTitle>

<h1>Call .NET Example 8</h1>

<p>
    <button onclick="sendByteArray()">Send Bytes</button>
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>

@code {
    [JSInvokable]
    public static Task<string> ReceiveByteArray(byte[] receivedBytes)
    {
        return Task.FromResult(
            Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
    }
}

CallDotNetExample8.razor:

@page "/call-dotnet-example-8"
@using System.Text

<h1>Call .NET Example 8</h1>

<p>
    <button onclick="sendByteArray()">Send Bytes</button>
</p>

<p>
    Quote ©2005 <a href="https://www.uphe.com">Universal Pictures</a>:
    <a href="https://www.uphe.com/movies/serenity-2005">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0821612/">Jewel Staite on IMDB</a>
</p>

@code {
    [JSInvokable]
    public static Task<string> ReceiveByteArray(byte[] receivedBytes)
    {
        return Task.FromResult(
            Encoding.UTF8.GetString(receivedBytes, 0, receivedBytes.Length));
    }
}

Zie JavaScript-functies aanroepen vanuit .NET-methoden in ASP.NET Core Blazorvoor meer informatie over het gebruik van een bytematrix bij het aanroepen van JavaScript vanuit .NET.

Streamen van JavaScript naar .NET

Blazor ondersteunt het rechtstreeks streamen van gegevens van JavaScript naar .NET. Streams worden aangevraagd met behulp van de Microsoft.JSInterop.IJSStreamReference interface.

Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync retourneert een Stream en gebruikt de volgende parameters:

  • maxAllowedSize: Maximum aantal bytes dat is toegestaan voor de leesbewerking van JavaScript, wat standaard 512.000 bytes is als deze niet is opgegeven.
  • cancellationToken: A CancellationToken voor het annuleren van de leesbewerking.

In JavaScript:

function streamToDotNet() {
  return new Uint8Array(10000000);
}

In C#-code:

var dataReference = 
    await JS.InvokeAsync<IJSStreamReference>("streamToDotNet");
using var dataReferenceStream = 
    await dataReference.OpenReadStreamAsync(maxAllowedSize: 10_000_000);

var outputPath = Path.Combine(Path.GetTempPath(), "file.txt");
using var outputFileStream = File.OpenWrite(outputPath);
await dataReferenceStream.CopyToAsync(outputFileStream);

In het voorgaande voorbeeld:

  • JS is een geïnjecteerd IJSRuntime exemplaar. IJSRuntime wordt geregistreerd door het Blazor framework.
  • De dataReferenceStream wordt naar schijf (file.txt) geschreven op het tijdelijke mappad van de huidige gebruiker (GetTempPath).

JavaScript-functies aanroepen vanuit .NET-methoden in ASP.NET Core Blazor behandelt de omgekeerde bewerking, streaming van .NET naar JavaScript met behulp van een DotNetStreamReference.

ASP.NET Core Blazor bestandsuploads behandelt hoe u een bestand uploadt in Blazor. Zie voor een voorbeeld van formulieren dat <textarea> gegevens in een server-side component streamt, Problemen met ASP.NET Core Blazor formulieren oplossen.

JavaScript-interoperabiliteit [JSImport]/[JSExport]

Deze sectie is van toepassing op onderdelen aan de clientzijde.

Als alternatief voor interactie met JavaScript (JS) in clientonderdelen met behulp van BlazorJS interop-mechanisme op basis van de IJSRuntime interface, is een JS[JSImport]/[JSExport] interop-API beschikbaar voor apps die gericht zijn op .NET 7 of hoger.

Zie JavaScript JSImport/JSExport-interop met ASP.NET Core Blazorvoor meer informatie.

Verwijdering van JavaScript-interoperabiliteitsobjectverwijzingen

Voorbeelden in de Interop-artikelen van JavaScript (JS) laten typische patronen voor objectverwijdering zien:

JS interop-objectverwijzingen worden geïmplementeerd als een kaart die is gekoppeld aan een id aan de zijkant van de JS interop-aanroep waarmee de verwijzing wordt gemaakt. Wanneer de verwijdering van een object wordt geïnitieerd vanuit de .NET- of JS-kant, verwijdert Blazor de vermelding uit de kaart en kan het object worden afval verzameld, zolang er geen andere sterke verwijzing naar het object aanwezig is.

Verwijder minimaal objecten die aan de .NET-zijde zijn gemaakt om te voorkomen dat .NET beheerd geheugen wordt gelekt.

DOM-opschoontaken tijdens het verwijderen van onderdelen

Zie ASP.NET Core Blazor JavaScript-interoperabiliteit (JS interop)voor meer informatie.

JavaScript-interopaanroepen zonder circuit

Zie ASP.NET Core Blazor JavaScript-interoperabiliteit (JS interop)voor meer informatie.

Additional resources