Wywoływanie metod platformy .NET z funkcji Języka JavaScript w programie ASP.NET Core Blazor

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

W tym artykule wyjaśniono, jak wywoływać metody platformy .NET z poziomu języka JavaScript (JS).

Aby uzyskać informacje na temat wywoływania JS funkcji z platformy .NET, zobacz Wywoływanie funkcji JavaScript z metod platformy .NET w programie ASP.NET Core Blazor.

Wywoływanie statycznej metody platformy .NET

Aby wywołać statyczną metodę .NET z języka JavaScript (JS), użyj JS funkcji:

  • DotNet.invokeMethodAsync (zalecane): Asynchroniczne dla składników po stronie serwera i po stronie klienta.
  • DotNet.invokeMethod: Synchroniczne tylko dla składników po stronie klienta.

Przekaż nazwę zestawu zawierającego metodę, identyfikator statycznej metody .NET i wszelkie argumenty.

W poniższym przykładzie:

  • Symbol {ASSEMBLY NAME} zastępczy to nazwa zestawu aplikacji.
  • Symbol {.NET METHOD ID} zastępczy jest identyfikatorem metody .NET.
  • Symbol {ARGUMENTS} zastępczy to opcjonalne argumenty rozdzielane przecinkami, które mają zostać przekazane do metody, z których każda musi być JSserializowana.
DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS});

DotNet.invokeMethodAsyncJS Promise zwraca wynik operacji. DotNet.invokeMethod (składniki po stronie klienta) zwraca wynik operacji.

Ważne

W przypadku składników po stronie serwera zalecamy funkcję asynchroniczną (invokeMethodAsync) w wersji synchronicznej (invokeMethod).

Metoda .NET musi być publiczna, statyczna i mieć [JSInvokable] atrybut .

W poniższym przykładzie:

  • Symbol {<T>} zastępczy wskazuje typ zwracany, który jest wymagany tylko dla metod, które zwracają wartość.
  • Symbol {.NET METHOD ID} zastępczy jest identyfikatorem metody.
@code {
    [JSInvokable]
    public static Task{<T>} {.NET METHOD ID}()
    {
        ...
    }
}

Uwaga

Wywoływanie otwartych metod ogólnych nie jest obsługiwane przy użyciu statycznych metod platformy .NET, ale jest obsługiwane za pomocą metod wystąpienia. Aby uzyskać więcej informacji, zobacz sekcję Wywoływanie metod klasy ogólnej platformy .NET.

W poniższym składniku ReturnArrayAsync metoda języka C# zwraca tablicę int . Atrybut [JSInvokable] jest stosowany do metody , co sprawia, że metoda jest wywoływana przez JS.

CallDotnet1.razor:

@page "/call-dotnet-1"

<PageTitle>Call .NET 1</PageTitle>

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

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

<p>
    See the result in the developer tools console.
</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 });
    }
}

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 });
    }
}

Atrybut <button> HTML elementu onclick to przypisanie procedury obsługi zdarzeń języka JavaScript onclick do przetwarzania click@onclick zdarzeń, a nie Blazoratrybut dyrektywy. Funkcja returnArrayAsyncJS jest przypisywana jako procedura obsługi.

Poniższa returnArrayAsyncJS funkcja wywołuje metodę ReturnArrayAsync .NET poprzedniego składnika i rejestruje wynik w konsoli narzędzi deweloperskich przeglądarki. BlazorSample to nazwa zestawu aplikacji.

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

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

Po wybraniu Trigger .NET static method przycisku dane wyjściowe konsoli narzędzi deweloperskich przeglądarki wyświetlają dane tablicy. Format danych wyjściowych różni się nieco między przeglądarkami. Następujące dane wyjściowe pokazują format używany przez przeglądarkę Microsoft Edge:

Array(3) [ 1, 2, 3 ]

Przekazywanie danych do metody .NET podczas wywoływania invokeMethodAsync funkcji przez przekazanie danych jako argumentów.

Aby zademonstrować przekazywanie danych do platformy .NET, wykonaj poprzednią returnArrayAsyncJS funkcję, aby otrzymać pozycję początkową po wywołaniu funkcji i przekazać wartość jako argument do invokeMethodAsync funkcji:

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

W składniku zmień wywołanie funkcji, aby uwzględnić pozycję początkową. W poniższym przykładzie użyto wartości 5:

<button onclick="returnArrayAsync(5)">
    ...
</button>

Wywołana ReturnArrayAsync metoda składnika odbiera pozycję początkową i konstruuje tablicę z niej. Tablica jest zwracana do rejestrowania w konsoli:

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

Po ponownym skompilowanej aplikacji i odświeżeniu przeglądarki w konsoli przeglądarki zostaną wyświetlone następujące dane wyjściowe po wybraniu przycisku:

Array(3) [ 5, 6, 7 ]

Domyślnie identyfikator metody .NET dla wywołania JS jest nazwą metody .NET, ale można określić inny identyfikator przy użyciu konstruktora atrybutu[JSInvokable]. W poniższym przykładzie DifferentMethodName jest przypisanym identyfikatorem ReturnArrayAsync metody dla metody :

[JSInvokable("DifferentMethodName")]

W wywołaniu metody DotNet.invokeMethodAsync (składniki po stronie serwera lub po stronie klienta) lub DotNet.invokeMethod (tylko składniki po stronie klienta) wywołaj metodę ReturnArrayAsyncDifferentMethodName .NET:

  • DotNet.invokeMethodAsync('BlazorSample', 'DifferentMethodName');
  • DotNet.invokeMethod('BlazorSample', 'DifferentMethodName'); (tylko składniki po stronie klienta)

Uwaga

Przykład ReturnArrayAsync metody w tej sekcji zwraca wynik Task bez użycia jawnego języka C# async i await słów kluczowych. Metody kodowania za pomocą async metod i await są typowe dla metod, które używają await słowa kluczowego do zwracania wartości operacji asynchronicznych.

ReturnArrayAsync metoda skomponowana z słowami kluczowymi async i await :

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

Aby uzyskać więcej informacji, zobacz Asynchroniczne programowanie za pomocą asynchronicznego i await w przewodniku języka C#.

Tworzenie odwołań do obiektów i danych języka JavaScript w celu przekazania do platformy .NET

Wywołaj metodę JSDotNet.createJSObjectReference(jsObject) konstruowania odwołania do obiektu, aby można było przekazać go do platformy .NET, gdzie jsObject jest JS Object używany do tworzenia JS odwołania do obiektu. Poniższy przykład przekazuje odwołanie do obiektu nies serializowalnego window na platformie .NET, który odbiera go w ReceiveWindowObject metodzie języka C# jako element IJSObjectReference:

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

W poprzednim przykładzie {ASSEMBLY NAME} symbol zastępczy to przestrzeń nazw aplikacji.

Uwaga

Powyższy przykład nie wymaga usunięcia JSObjectReferenceobiektu , ponieważ odwołanie do window obiektu nie jest przechowywane w obiekcie JS.

Utrzymywanie odwołania do elementu JSObjectReference wymaga jego zdysponowania, aby uniknąć wycieku JS pamięci na kliencie. Poniższy przykład refaktoryzuje powyższy kod, aby przechwycić odwołanie do JSObjectReferenceelementu , a następnie wywołanie metody w celu DotNet.disposeJSObjectReference() usunięcia odwołania:

var jsObjectReference = DotNet.createJSObjectReference(window);

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

DotNet.disposeJSObjectReference(jsObjectReference);

W poprzednim przykładzie {ASSEMBLY NAME} symbol zastępczy to przestrzeń nazw aplikacji.

Wywołaj metodę DotNet.createJSStreamReference(streamReference) konstruowania odwołania do strumieniaJS, aby można było przekazać ją do platformy .NET, gdzie streamReference jest tablicą typu , Bloblub dowolną ArrayBuffertablicą typową, taką jak Uint8Array lub Float32Array, użytą do utworzenia odwołania do strumieniaJS.

Wywoływanie metody wystąpienia platformy .NET

Aby wywołać metodę wystąpienia platformy .NET z poziomu języka JavaScript (JS):

  • Przekaż wystąpienie platformy .NET, odwołując się do JS niego, opakowując wystąpienie w obiekcie DotNetObjectReference i wywołując Create je.

  • Wywołaj metodę wystąpienia platformy .NET przy JS użyciu metody invokeMethodAsync (zalecane) lub invokeMethod (tylko składniki po stronie klienta) z przekazanego DotNetObjectReferenceelementu . Przekaż identyfikator metody .NET wystąpienia i wszystkie argumenty. Wystąpienie platformy .NET można również przekazać jako argument podczas wywoływania innych metod platformy .NET z programu JS.

    W poniższym przykładzie:

    • dotNetHelperjest .DotNetObjectReference
    • Symbol {.NET METHOD ID} zastępczy jest identyfikatorem metody .NET.
    • Symbol {ARGUMENTS} zastępczy to opcjonalne argumenty rozdzielane przecinkami, które mają zostać przekazane do metody, z których każda musi być JSserializowana.
    dotNetHelper.invokeMethodAsync('{.NET METHOD ID}', {ARGUMENTS});
    

    Uwaga

    invokeMethodAsync i invokeMethod nie akceptuj parametru nazwy zestawu podczas wywoływania metody wystąpienia.

    invokeMethodAsyncJS Promise zwraca wynik operacji. invokeMethod (tylko składniki po stronie klienta) zwraca wynik operacji.

    Ważne

    W przypadku składników po stronie serwera zalecamy funkcję asynchroniczną (invokeMethodAsync) w wersji synchronicznej (invokeMethod).

  • Usuwanie obiektu DotNetObjectReference.

W poniższych sekcjach tego artykułu przedstawiono różne podejścia do wywoływania metody wystąpienia platformy .NET:

Unikaj przycinania metod javaScript-invokable .NET

Ta sekcja dotyczy aplikacji po stronie klienta z włączoną kompilacją przed czasem (AOT) i ponownym łączeniem środowiska uruchomieniowego.

Kilka przykładów w poniższych sekcjach jest opartych na podejściu wystąpienia klasy, w którym metoda javaScript-invokable .NET oznaczona atrybutem [JSInvokable] jest składową klasy, która nie jest składnikiemRazor. Gdy takie metody platformy .NET znajdują się w składniku Razor , są chronione przed ponownym łączeniem/przycinaniem środowiska uruchomieniowego. Aby chronić metody .NET przed przycinaniem poza składnikamiRazor, zaimplementuj metody z atrybutem DynamicDependency w konstruktorze klasy, jak pokazano w poniższym przykładzie:

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

public class ExampleClass {

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

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

Aby uzyskać więcej informacji, zobacz Przygotowywanie bibliotek .NET do przycinania: DynamicDependency.

Przekazywanie elementu DotNetObjectReference do pojedynczej funkcji Języka JavaScript

W przykładzie w tej sekcji pokazano, jak przekazać element DotNetObjectReference do pojedynczej funkcji Języka JavaScript (JS).

Następująca sayHello1JS funkcja odbiera DotNetObjectReference wywołania invokeMethodAsync metody i w celu wywołania GetHelloMessage metody .NET składnika:

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

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

W poprzednim przykładzie nazwa dotNetHelper zmiennej jest dowolna i można ją zmienić na dowolną preferowaną nazwę.

Dla następującego składnika:

  • Składnik ma metodę JS-invokable .NET o nazwie GetHelloMessage.
  • Po wybraniu Trigger .NET instance methodJS przycisku funkcja jest wywoływana za pomocą .sayHello1DotNetObjectReference
  • sayHello1:
    • Wywołuje GetHelloMessage i odbiera wynik komunikatu.
    • Zwraca wynik komunikatu do metody wywołującej TriggerDotNetInstanceMethod .
  • Zwrócony komunikat z sayHello1 in result jest wyświetlany użytkownikowi.
  • Aby uniknąć przecieku pamięci i umożliwić odzyskiwanie pamięci, odwołanie do obiektu platformy .NET utworzonego przez DotNetObjectReference program jest usuwane w metodzie 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();
    }
}

W poprzednim przykładzie nazwa dotNetHelper zmiennej jest dowolna i można ją zmienić na dowolną preferowaną nazwę.

Skorzystaj z poniższych wskazówek, aby przekazać argumenty do metody wystąpienia:

Dodaj parametry do wywołania metody .NET. W poniższym przykładzie nazwa jest przekazywana do metody . Dodaj dodatkowe parametry do listy zgodnie z potrzebami.

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

W poprzednim przykładzie nazwa dotNetHelper zmiennej jest dowolna i można ją zmienić na dowolną preferowaną nazwę.

Podaj listę parametrów do metody .NET.

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();
    }
}

W poprzednim przykładzie nazwa dotNetHelper zmiennej jest dowolna i można ją zmienić na dowolną preferowaną nazwę.

Przekazywanie klasy DotNetObjectReference do klasy z wieloma funkcjami Języka JavaScript

W przykładzie w tej sekcji pokazano, jak przekazać element DotNetObjectReference do klasy JavaScript (JS) z wieloma funkcjami.

Utwórz i przekaż element DotNetObjectReference z OnAfterRenderAsync metody cyklu życia do JS klasy dla wielu funkcji do użycia. Upewnij się, że kod platformy .NET usuwa DotNetObjectReferenceelement , jak pokazano w poniższym przykładzie.

W poniższym składniku przyciski wywołuje funkcje, Trigger JS function ustawiająconclickJSwłaściwość, a nie@onclickBlazor atrybut dyrektywy.JS

CallDotNetExampleOneHelper.razor:

@page "/call-dotnet-example-one-helper"
@implements IDisposable
@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 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();
    }
}
@page "/call-dotnet-example-one-helper"
@implements IDisposable
@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 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();
    }
}
@page "/call-dotnet-example-one-helper"
@implements IDisposable
@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 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()
    {
        if (dotNetHelper is not null)
        {
            dotNetHelper.Dispose();
        }
    }
}

W powyższym przykładzie:

  • JS jest wystąpieniem wstrzykniętym IJSRuntime . IJSRuntime program jest zarejestrowany przez platformę Blazor .
  • Nazwa dotNetHelper zmiennej jest dowolna i może zostać zmieniona na dowolną preferowaną nazwę.
  • Składnik musi jawnie usunąć element, DotNetObjectReference aby umożliwić odzyskiwanie pamięci i zapobiec wyciekowi pamięci.
<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>

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

W powyższym przykładzie:

  • Klasa GreetingHelpers jest dodawana do window obiektu w celu globalnego zdefiniowania klasy, która umożliwia Blazor zlokalizowanie klasy dla JS międzyoperacyjności.
  • Nazwa dotNetHelper zmiennej jest dowolna i może zostać zmieniona na dowolną preferowaną nazwę.

Wywoływanie metod klasy ogólnej platformy .NET

Funkcje języka JavaScript (JS) mogą wywoływać metody klasy ogólnej platformy .NET, gdzie JS funkcja wywołuje metodę .NET klasy ogólnej.

W następującej klasie typu ogólnego (GenericType<TValue>):

  • Klasa ma pojedynczy parametr typu (TValue) z jedną właściwością ogólną Value .
  • Klasa ma dwie metody inne niż ogólne oznaczone atrybutem[JSInvokable], z których każdy ma parametr typu ogólnego o nazwie newValue:
    • Update synchronicznie aktualizuje wartość Value z newValue.
    • UpdateAsync asynchronicznie aktualizuje wartość Value z newValue po utworzeniu oczekiwanego zadania, Task.Yield gdy asynchronicznie zwraca bieżący kontekst w oczekiwanym czasie.
  • Każda z metod klasy zapisuje typ TValue i wartość Value w konsoli. Zapisywanie w konsoli jest przeznaczone tylko do celów demonstracyjnych. Aplikacje produkcyjne zwykle unikają zapisywania w konsoli na rzecz rejestrowania aplikacji. Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor logging and Logging in .NET Core and ASP.NET Core (Rejestrowanie i rejestrowanie na platformie .NET Core) i ASP.NET Core.

Uwaga

Otwarte typy ogólne i metody nie określają typów dla symboli zastępczych typów. Z drugiej strony zamknięte typy dostaw typów ogólnych dla wszystkich symboli zastępczych typów. Przykłady w tej sekcji przedstawiają zamknięte typy ogólne, ale wywoływanie metod wystąpienia międzyoperacyjnego z otwartymi rodzajami ogólnymi jest obsługiwane.JS Używanie otwartych typów ogólnych nie jest obsługiwane w przypadku wywołań statycznych metod .NET, które zostały opisane wcześniej w tym artykule.

Aby uzyskać więcej informacji, zobacz następujące artykuły:

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 void UpdateAsync(TValue newValue)
    {
        await Task.Yield();
        Value = newValue;

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

W następującej invokeMethodsAsync funkcji:

  • Metody i UpdateAsync klasy Update typów ogólnych są wywoływane z argumentami reprezentującymi ciągi i liczby.
  • Składniki po stronie klienta obsługują synchronicznie wywoływanie metod platformy .NET za pomocą polecenia invokeMethod. syncInterop otrzymuje wartość logiczną wskazującą, czy międzyoperacyjna JS występuje na kliencie. Gdy syncInterop parametr to true, invokeMethod jest bezpiecznie wywoływany. Jeśli wartość syncInterop to false, wywoływana jest tylko funkcja invokeMethodAsync asynchroniczna, ponieważ JS międzyoperacyjna jest wykonywana w składniku po stronie serwera.
  • W celach DotNetObjectReference demonstracyjnych wywołanie funkcji (invokeMethod lub invokeMethodAsync), metoda .NET o nazwie (Update lub UpdateAsync) i argument są zapisywane w konsoli. Argumenty używają liczby losowej, aby zezwolić na dopasowanie JS wywołania metody .NET do wywołania metody .NET (również zapisanej w konsoli po stronie platformy .NET). Kod produkcyjny zwykle nie jest zapisywany w konsoli programu na kliencie lub serwerze. Aplikacje produkcyjne zwykle polegają na rejestrowaniu aplikacji. Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor logging and Logging in .NET Core and ASP.NET Core (Rejestrowanie i rejestrowanie na platformie .NET Core) i ASP.NET Core.
<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>

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

W poniższym składniku GenericsExample:

  • invokeMethodsAsync Funkcja jest wywoływana JS po wybraniu Invoke Interop przycisku.
  • Para DotNetObjectReference typów jest tworzona i przekazywana do JS funkcji dla wystąpień GenericType klasy jako i stringint.

GenericsExample.razor:

@page "/generics-example"
@using System.Runtime.InteropServices
@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 =
            RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));

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

    public void Dispose()
    {
        objRef1?.Dispose();
        objRef2?.Dispose();
    }
}
@page "/generics-example"
@using System.Runtime.InteropServices
@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 =
            RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));

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

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

W poprzednim przykładzie JS jest wstrzyknięte IJSRuntime wystąpienie. IJSRuntime program jest zarejestrowany przez platformę Blazor .

Poniżej przedstawiono typowe dane wyjściowe z poprzedniego przykładu, gdy Invoke Interop przycisk jest wybrany w składniku po stronie klienta:

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

Jeśli powyższy przykład jest implementowany w składniku po stronie serwera, unika się wywołań synchronicznych.invokeMethod W przypadku składników po stronie serwera zalecamy funkcję asynchroniczną (invokeMethodAsync) w wersji synchronicznej (invokeMethod).

Typowe dane wyjściowe składnika po stronie serwera:

JS: invokeMethodAsync:Update('string 34809')
.NET: Update: GenericType<System.String>: ciąg 34809
JS: invokeMethodAsync:UpdateAsync('string 93059')
JS: invokeMethodAsync:Update(41997)
.NET: Aktualizacja: GenericType<System.Int32>: 41997
JS: invokeMethodAsync:UpdateAsync(24652)
.NET: UpdateAsync: GenericType<System.String>: ciąg 93059
.NET: UpdateAsync: GenericType<System.Int32>: 24652

Powyższe przykłady danych wyjściowych pokazują, że metody asynchroniczne są wykonywane i wykonywane w dowolnej kolejności w zależności od kilku czynników, w tym planowania wątków i szybkości wykonywania metody. Nie można niezawodnie przewidzieć kolejności ukończenia wywołań metody asynchronicznej.

Przykłady wystąpień klas

Następująca sayHello1JS funkcja:

  • Wywołuje metodę GetHelloMessage .NET w przekazanym DotNetObjectReferencepliku .
  • Zwraca komunikat z GetHelloMessage do obiektu wywołującego sayHello1 .
<script>
  window.sayHello1 = (dotNetHelper) => {
    return dotNetHelper.invokeMethodAsync('GetHelloMessage');
  };
</script>

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

W poprzednim przykładzie nazwa dotNetHelper zmiennej jest dowolna i można ją zmienić na dowolną preferowaną nazwę.

Poniższa HelloHelper klasa ma metodę JS-invokable .NET o nazwie GetHelloMessage. Po HelloHelper utworzeniu Name nazwa właściwości jest używana do zwracania komunikatu z .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;

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}!";
}

Metoda CallHelloHelperGetHelloMessage w poniższej JsInteropClasses3 klasie wywołuje JS funkcję sayHello1 z nowym wystąpieniem HelloHelperklasy .

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;

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);
    }
}

Aby uniknąć przecieku pamięci i umożliwić odzyskiwanie pamięci, odwołanie do obiektu platformy .NET utworzone przez DotNetObjectReference program jest usuwane, gdy odwołanie do obiektu wykracza poza zakres ze składniąusing var.

Trigger .NET instance method Gdy przycisk jest zaznaczony w następującym składniku, JsInteropClasses3.CallHelloHelperGetHelloMessage jest wywoływany z wartością 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);
    }
}

Na poniższej ilustracji przedstawiono renderowany składnik o nazwie Amy Pond w Name polu. Po wybraniu Hello, Amy Pond! przycisku zostanie wyświetlony w interfejsie użytkownika:

Przykład składnika

Powyższy wzorzec pokazany w JsInteropClasses3 klasie można również zaimplementować całkowicie w składniku.

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);
    }
}

Aby uniknąć przecieku pamięci i umożliwić odzyskiwanie pamięci, odwołanie do obiektu platformy .NET utworzone przez DotNetObjectReference program jest usuwane, gdy odwołanie do obiektu wykracza poza zakres ze składniąusing var.

Dane wyjściowe wyświetlane przez składnik są Hello, Amy Pond! wtedy, gdy nazwa Amy Pond jest podana name w polu.

W poprzednim składniku odwołanie do obiektu platformy .NET jest usuwane. Jeśli klasa lub składnik nie usuwa elementu , należy go usunąć DotNetObjectReferencez klienta przez wywołanie dispose przekazanego DotNetObjectReferenceelementu :

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

W powyższym przykładzie:

  • Symbol {JS FUNCTION NAME} zastępczy to JS nazwa funkcji.
  • Nazwa dotNetHelper zmiennej jest dowolna i może zostać zmieniona na dowolną preferowaną nazwę.
  • Symbol {.NET METHOD ID} zastępczy jest identyfikatorem metody .NET.

Klasa pomocnika metody wystąpienia składnika platformy .NET

Klasa pomocnika może wywołać metodę wystąpienia platformy .NET jako .Action Klasy pomocnika są przydatne w następujących scenariuszach:

  • Gdy na tej samej stronie jest renderowanych kilka składników tego samego typu.
  • W aplikacjach po stronie serwera z wieloma użytkownikami jednocześnie używających tego samego składnika.

W poniższym przykładzie:

  • Składnik zawiera kilka ListItem1 składników, które są składnikiem udostępnionym w folderze aplikacji Shared .
  • Każdy ListItem1 składnik składa się z komunikatu i przycisku.
  • Po wybraniu ListItem1ListItem1przycisku składnika metoda zmienia UpdateMessage tekst elementu listy i ukrywa przycisk.

Poniższa MessageUpdateInvokeHelper klasa obsługuje metodę JS.NET z możliwością wywołania metody -invokable .NET, UpdateMessageCalleraby wywołać Action określoną klasę po utworzeniu wystąpienia klasy.

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;

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();
    }
}

Poniższa updateMessageCallerJS funkcja wywołuje metodę UpdateMessageCaller .NET.

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

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

W poprzednim przykładzie nazwa dotNetHelper zmiennej jest dowolna i można ją zmienić na dowolną preferowaną nazwę.

Poniższy ListItem1 składnik jest składnikiem udostępnionym, który może być używany dowolną liczbę razy w składniku nadrzędnym i tworzy elementy listy () dla listy HTML (<li>...</li><ul>...</ul> lub <ol>...</ol>). Każde ListItem1 wystąpienie składnika ustanawia wystąpienie MessageUpdateInvokeHelper elementu z zestawem Action na jego UpdateMessage metodę.

Po wybraniu ListItem1InteropCallupdateMessageCaller przycisku składnika jest wywoływany z utworzonym DotNetObjectReference wystąpieniem.MessageUpdateInvokeHelper Dzięki temu platforma może wywołać UpdateMessageCaller wystąpienie tego ListItem1MessageUpdateInvokeHelper wystąpienia. Przekazany DotNetObjectReference element jest usuwany w JS pliku (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()
    {
        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 element jest wywoływany w celu zaktualizowania interfejsu użytkownika, gdy message jest ustawiony w elem UpdateMessage. Jeśli StateHasChanged nie jest wywoływana, nie ma możliwości, aby wiedzieć, Blazor że interfejs użytkownika powinien zostać zaktualizowany po wywołaniu Action .

Poniższy składnik nadrzędny zawiera cztery elementy listy, z których każde jest wystąpieniem ListItem1 składnika.

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>

Na poniższej ilustracji przedstawiono renderowany składnik nadrzędny po wybraniu drugiego InteropCall przycisku:

  • ListItem1 Drugi składnik wyświetlił UpdateMessage Called! komunikat.
  • Przycisk InteropCall drugiego ListItem1 składnika nie jest widoczny, ponieważ właściwość CSS display przycisku jest ustawiona na nonewartość .

Przykład składnika

Metoda .NET wystąpienia składnika wywoływana z DotNetObjectReference przypisanej do właściwości elementu

Przypisanie DotNetObjectReference elementu do właściwości elementu HTML umożliwia wywoływanie metod .NET w wystąpieniu składnika:

Podobnie jak w przypadku podejścia opisanego w sekcji klasa pomocnika metody platformy .NET wystąpienia składnika, takie podejście jest przydatne w następujących scenariuszach:

  • Gdy na tej samej stronie jest renderowanych kilka składników tego samego typu.
  • W aplikacjach po stronie serwera z wieloma użytkownikami jednocześnie używających tego samego składnika.
  • Metoda .NET jest wywoływana ze JS zdarzenia (na przykład onclick), a nie ze Blazor zdarzenia (na przykład @onclick).

W poniższym przykładzie:

  • Składnik zawiera kilka ListItem2 składników, które są składnikiem udostępnionym w folderze aplikacji Shared .
  • Każdy ListItem2 składnik składa się z komunikatu <span> o elemencie listy, a drugi <span> z właściwością CSS ustawioną display na inline-block wartość na potrzeby wyświetlania.
  • Po wybraniu ListItem2ListItem2UpdateMessage elementu listy składników metoda zmienia tekst elementu listy w pierwszym <span> i ukrywa drugi<span>, ustawiając jego display właściwość na .none

Następująca assignDotNetHelperJS funkcja przypisuje element DotNetObjectReference do elementu we właściwości o nazwie dotNetHelper:

<script>
  window.assignDotNetHelper = (element, dotNetHelper) => {
    element.dotNetHelper = dotNetHelper;
  }
</script>

Następująca interopCallJS funkcja używa DotNetObjectReference elementu dla przekazanego elementu w celu wywołania metody .NET o nazwie UpdateMessage:

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

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

W poprzednim przykładzie nazwa dotNetHelper zmiennej jest dowolna i można ją zmienić na dowolną preferowaną nazwę.

Poniższy ListItem2 składnik jest składnikiem udostępnionym, który może być używany dowolną liczbę razy w składniku nadrzędnym i tworzy elementy listy () dla listy HTML (<li>...</li><ul>...</ul> lub <ol>...</ol>).

Każde ListItem2 wystąpienie składnika wywołuje assignDotNetHelperJS funkcję w OnAfterRenderAsync elemencie z odwołaniem do elementu (pierwszym <span> elementem elementu listy) i wystąpieniem składnika jako DotNetObjectReference.

ListItem2 Po wybraniu komunikatu <span> składnika jest wywoływany <span> przekazywanie interopCall elementu jako parametru (this), który wywołuje UpdateMessage metodę .NET. W UpdateMessagepliku StateHasChanged jest wywoływany w celu zaktualizowania interfejsu użytkownika, gdy message jest ustawiony, a display właściwość drugiego <span> jest aktualizowana. Jeśli StateHasChanged nie jest wywoływana, nie ma możliwości, aby wiedzieć, Blazor że interfejs użytkownika powinien zostać zaktualizowany po wywołaniu metody.

Element DotNetObjectReference jest usuwany, gdy składnik jest usuwany.

ListItem2.razor:

@inject IJSRuntime JS

<li>
    <span style="font-weight:bold;color:@color" @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.";
    private string color = "initial";

    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";
        color = "MediumSeaGreen";
        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();
}
@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();
}

Poniższy składnik nadrzędny zawiera cztery elementy listy, z których każde jest wystąpieniem ListItem2 składnika.

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>

Synchroniczne międzyoperajności JS w składnikach po stronie klienta

Ta sekcja dotyczy tylko składników po stronie klienta.

Wywołania współdziałania języka JS są domyślnie asynchroniczne niezależnie od tego, czy wywoływany kod jest synchroniczny, czy asynchroniczny. Wywołania są domyślnie asynchroniczne, aby upewnić się, że składniki są zgodne z trybami renderowania po stronie serwera i po stronie klienta. Na serwerze wszystkie JS wywołania międzyoperacyjne muszą być asynchroniczne, ponieważ są wysyłane za pośrednictwem połączenia sieciowego.

Jeśli wiesz, że składnik działa tylko w zestawie WebAssembly, możesz wykonać synchroniczne wywołania międzyoperacyjne JS . Ma to nieco mniejsze obciążenie niż wykonywanie wywołań asynchronicznych i może spowodować zmniejszenie liczby cykli renderowania, ponieważ nie ma stanu pośredniego podczas oczekiwania na wyniki.

Aby wykonać wywołanie synchroniczne z języka JavaScript do platformy .NET w składniku po stronie klienta, użyj polecenia DotNet.invokeMethod zamiast DotNet.invokeMethodAsync.

Wywołania synchroniczne działają, jeśli:

  • Składnik jest renderowany tylko do wykonania w zestawie WebAssembly.
  • Wywołana funkcja zwraca wartość synchronicznie. Funkcja nie async jest metodą i nie zwraca platformy .NET Task ani języka JavaScript Promise.

Lokalizacja języka JavaScript

Załaduj kod JavaScript (JS) przy użyciu dowolnego podejścia opisanego w artykule dotyczącym lokalizacji języka JavaScript:

Ładowanie JS modułów JS zostało opisane w tym artykule w sekcji Izolacja języka JavaScript w modułach Języka JavaScript.

Ostrzeżenie

Umieść <script> tag tylko w pliku składnika (.razor), jeśli składnik ma gwarancję wdrożenia statycznego renderowania po stronie serwera (statyczny SSR), ponieważ <script> tag nie może być aktualizowany dynamicznie.

Ostrzeżenie

Nie umieszczaj tagu <script> w pliku składnika (.razor), ponieważ <script> tag nie może być aktualizowany dynamicznie.

Izolacja języka JavaScript w modułach języka JavaScript

Platforma Blazor włącza izolację języka JavaScript (JS) w standardowych modułach języka JavaScript (Specyfikacja ECMAScript). Ładowanie modułu JavaScript działa tak samo jak w Blazor przypadku innych typów aplikacji internetowych i możesz dostosować sposób definiowania modułów w aplikacji. Aby zapoznać się z przewodnikiem dotyczącym używania modułów Języka JavaScript, zobacz Artykuł MdN Web Docs: JavaScript modules (Dokumentacja internetowa mdN: moduły Języka JavaScript).

Izolacja języka JS zapewnia następujące korzyści:

  • Zaimportowany kod JS nie zanieczyszcza już globalnej przestrzeni nazw.
  • Użytkownicy biblioteki i składników nie są zobowiązani do zaimportowania powiązanego kodu JS.

Aby uzyskać więcej informacji, zobacz Wywoływanie funkcji języka JavaScript z metod platformy .NET na platformie ASP.NET Core Blazor.

Importowanie dynamiczne za pomocą import() operatora jest obsługiwane w przypadku platformy ASP.NET Core i Blazor:

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

W poprzednim przykładzie symbol zastępczy reprezentuje sprawdzanie warunkowe, aby określić, {CONDITION} czy moduł powinien zostać załadowany.

Aby uzyskać informacje o zgodności przeglądarki, zobacz Czy mogę używać: moduły JavaScript: import dynamiczny.

Unikaj odwołań do obiektów okrągłych

Obiekty zawierające odwołania cykliczne nie mogą być serializowane na kliencie dla jednego z następujących obiektów:

  • Wywołania metody .NET.
  • Wywołania metody Języka JavaScript z języka C#, gdy zwracany typ zawiera odwołania cykliczne.

Obsługa tablic bajtów

Blazor obsługuje zoptymalizowaną międzyoperacyjną tablicę bajtów JavaScript (JS), która pozwala uniknąć kodowania/dekodowania tablic bajtowych do base64. W poniższym przykładzie użyto JS międzyoperajności, aby przekazać tablicę bajtów do platformy .NET.

sendByteArrayJS Podaj funkcję. Funkcja jest wywoływana statycznie, która zawiera parametr nazwy zestawu w wywołaniu invokeMethodAsync przez przycisk w składniku i nie zwraca wartości:

<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>

Uwaga

Aby uzyskać ogólne wskazówki dotyczące JS lokalizacji i naszych zaleceń dotyczących aplikacji produkcyjnych, zobacz Lokalizacja języka JavaScript w aplikacjach ASP.NET CoreBlazor.

CallDotnet8.razor:

@page "/call-dotnet-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

<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

<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));
    }
}

Aby uzyskać informacje na temat używania tablicy bajtów podczas wywoływania języka JavaScript z platformy .NET, zobacz Wywoływanie funkcji Języka JavaScript z metod platformy .NET w programie ASP.NET Core Blazor.

Przesyłanie strumieniowe z języka JavaScript do platformy .NET

Blazor obsługuje przesyłanie strumieniowe danych bezpośrednio z języka JavaScript do platformy .NET. Strumienie są wymagane przy użyciu interfejsuMicrosoft.JSInterop.IJSStreamReference.

Microsoft.JSInterop.IJSStreamReference.OpenReadStreamAsync Zwraca element Stream i używa następujących parametrów:

  • maxAllowedSize: Maksymalna liczba bajtów dozwolona dla operacji odczytu z języka JavaScript, która domyślnie wynosi 512 000 bajtów, jeśli nie zostanie określona.
  • cancellationToken: A CancellationToken do anulowania odczytu.

W języku JavaScript:

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

W kodzie języka C#:

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);

W powyższym przykładzie:

  • JS jest wystąpieniem wstrzykniętym IJSRuntime . IJSRuntime program jest zarejestrowany przez platformę Blazor .
  • Element dataReferenceStream jest zapisywany na dysku (file.txt) w ścieżce folderu tymczasowego bieżącego użytkownika (GetTempPath).

Wywoływanie funkcji Języka JavaScript z metod platformy .NET w programie ASP.NET Core Blazor obejmuje operację odwrotną, przesyłaną strumieniowo z platformy .NET do języka JavaScript przy użyciu elementu DotNetStreamReference.

ASP.NET Core Blazor przekazywania plików obejmuje sposób przekazywania pliku w programie Blazor. Przykład formularzy, który przesyła strumieniowo dane w składniku po stronie serwera, zobacz Rozwiązywanie problemów z formularzami <textarea>ASP.NET CoreBlazor.

Interopcja języka JavaScript [JSImport]/[JSExport]

Ta sekcja dotyczy składników po stronie klienta.

Alternatywą dla interakcji z językiem JavaScript (JS) w składnikach po stronie klienta przy użyciu JSBlazormechanizmu międzyoperacyjnego opartego na interfejsie IJSRuntime jest/JS[JSImport][JSExport] dostępny interfejs API międzyoperacyjny dla aplikacji przeznaczonych dla platformy .NET 7 lub nowszej.

Aby uzyskać więcej informacji, zobacz JavaScript Import/Export interop with ASP.NET Core (Importowanie/JSeksportowanie międzyoperacji języka JavaScript JSza pomocą programu ASP.NET CoreBlazor).

Usuwanie odwołań do obiektów międzyoperacyjnych języka JavaScript

Przykłady w artykułach międzyoperacyjnych języka JavaScript (JS) przedstawiają typowe wzorce usuwania obiektów:

JS Odwołania do obiektów międzyoperacyjności są implementowane jako mapowane przez identyfikator po stronie wywołania międzyoperacyjnego JS , które tworzy odwołanie. Gdy usuwanie obiektu jest inicjowane z platformy .NET lub JS po stronie, Blazor usuwa wpis z mapy, a obiekt może zostać odśmiecany, o ile nie ma innego silnego odwołania do obiektu.

Co najmniej zawsze usuwaj obiekty utworzone po stronie platformy .NET, aby uniknąć wycieku pamięci zarządzanej platformy .NET.

Zadania oczyszczania modelu DOM podczas usuwania składników

Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor JavaScript interoperability (JS interop).

Wywołania międzyoperacyjne języka JavaScript bez obwodu

Aby uzyskać więcej informacji, zobacz ASP.NET Core Blazor JavaScript interoperability (JS interop).

Dodatkowe zasoby