Skip to content

Commit b467a79

Browse files
authored
Update Blazor JS Interop for disposal (dotnet#16828)
1 parent 888b3c5 commit b467a79

1 file changed

Lines changed: 65 additions & 1 deletion

File tree

aspnetcore/blazor/javascript-interop.md

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,9 @@ returnArrayAsyncJs: function () {
504504

505505
You can also call .NET instance methods from JavaScript. To invoke a .NET instance method from JavaScript:
506506

507-
* Pass the .NET instance to JavaScript by wrapping it in a `DotNetObjectReference` instance. The .NET instance is passed by reference to JavaScript.
507+
* Pass the .NET instance by reference to JavaScript:
508+
* Make a static call to `DotNetObjectReference.Create`.
509+
* Wrap the instance in a `DotNetObjectReference` instance and call `Create` on the `DotNetObjectReference` instance. Dispose of `DotNetObjectReference` objects (an example appears later in this section).
508510
* Invoke .NET instance methods on the instance using the `invokeMethod` or `invokeMethodAsync` functions. The .NET instance can also be passed as an argument when invoking other .NET methods from JavaScript.
509511

510512
> [!NOTE]
@@ -550,6 +552,68 @@ Console output in the browser's web developer tools:
550552
Hello, Blazor!
551553
```
552554

555+
To avoid a memory leak and allow garbage collection on a component that creates a `DotNetObjectReference`, dispose of the object in the class that created the `DotNetObjectReference` instance:
556+
557+
```csharp
558+
public class ExampleJsInterop : IDisposable
559+
{
560+
private readonly IJSRuntime _jsRuntime;
561+
private DotNetObjectReference<HelloHelper> _objRef;
562+
563+
public ExampleJsInterop(IJSRuntime jsRuntime)
564+
{
565+
_jsRuntime = jsRuntime;
566+
}
567+
568+
public ValueTask<string> CallHelloHelperSayHello(string name)
569+
{
570+
_objRef = DotNetObjectReference.Create(new HelloHelper(name));
571+
572+
return _jsRuntime.InvokeAsync<string>(
573+
"exampleJsFunctions.sayHello",
574+
_objRef);
575+
}
576+
577+
public void Dispose()
578+
{
579+
_objRef?.Dispose();
580+
}
581+
}
582+
```
583+
584+
The preceding pattern shown in the `ExampleJsInterop` class can also be implemented in a component:
585+
586+
```razor
587+
@page "/JSInteropComponent"
588+
@using BlazorSample.JsInteropClasses
589+
@implements IDisposable
590+
@inject IJSRuntime JSRuntime
591+
592+
<h1>JavaScript Interop</h1>
593+
594+
<button type="button" class="btn btn-primary" @onclick="TriggerNetInstanceMethod">
595+
Trigger .NET instance method HelloHelper.SayHello
596+
</button>
597+
598+
@code {
599+
private DotNetObjectReference<HelloHelper> _objRef;
600+
601+
public async Task TriggerNetInstanceMethod()
602+
{
603+
_objRef = DotNetObjectReference.Create(new HelloHelper("Blazor"));
604+
605+
await JSRuntime.InvokeAsync<string>(
606+
"exampleJsFunctions.sayHello",
607+
_objRef);
608+
}
609+
610+
public void Dispose()
611+
{
612+
_objRef?.Dispose();
613+
}
614+
}
615+
```
616+
553617
## Share interop code in a class library
554618

555619
JS interop code can be included in a class library, which allows you to share the code in a NuGet package.

0 commit comments

Comments
 (0)