Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Notitie
Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Waarschuwing
Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Belangrijk
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 artikelvoor de huidige release.
In dit artikel wordt het ASP.NET Core-onderdeelverwijderingsproces Razor met IDisposable en IAsyncDisposable.
Als een onderdeel IDisposable of IAsyncDisposableimplementeert, roept het framework resourceverwijdering aan wanneer het onderdeel uit de gebruikersinterface wordt verwijderd. Vertrouw niet op de exacte timing van wanneer deze methoden worden uitgevoerd. 
              IAsyncDisposable kan bijvoorbeeld worden geactiveerd voor of na een asynchrone Task die in OnInitalizedAsync of OnParametersSetAsync wordt aangeroepen of voltooid. Ook mag de objectverwijderingscode niet aannemen dat objecten die zijn gemaakt tijdens de initialisatie of andere levenscyclusmethoden, inderdaad bestaan.
Onderdelen hoeven niet tegelijkertijd IDisposable en IAsyncDisposable te implementeren. Als beide zijn geïmplementeerd, wordt in het framework alleen de asynchrone overbelasting uitgevoerd.
Ontwikkelaarscode moet ervoor zorgen dat IAsyncDisposable implementaties niet lang duren.
Zie de inleidende opmerkingen van ASP.NET Core Blazor synchronisatiecontextvoor meer informatie.
Verwijdering van JavaScript-interoperabiliteitsobjectverwijzingen
Voorbeelden in de JavaScript (JS) interop-artikelen typische objectverwijderingspatronen demonstreren:
Wanneer u JS aanroept vanuit .NET, zoals beschreven in JavaScript-functies aanroepen vanuit .NET-methoden in ASP.NET Core Blazor, verwijdert u alle gemaakte IJSObjectReference/IJSInProcessObjectReference/JSObjectReference van .NET of van JS om te voorkomen dat JS geheugen wordt gelekt.
Wanneer u .NET aanroept vanuit JS, zoals beschreven in .NET-methoden aanroepen vanuit JavaScript-functies in ASP.NET Core Blazor, verwijdert u alle gemaakte DotNetObjectReference bestanden uit .NET of van JS om te voorkomen dat .NET-geheugen wordt gelekt.
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.
Zie JSvoor hulp bij wanneer een circuit wordt verbroken. Zie voor algemene richtlijnen voor het afhandelen van interopfouten in JavaScript de sectie JavaScript interop in Fouten verwerken in ASP.NET Core Blazor apps.
Synchrone IDisposable
Gebruik IDisposable.Disposevoor synchrone verwijderingstaken.
Het volgende onderdeel:
- Implementeert IDisposable met de 
@implementsRazor richtlijn. - Verwijdert 
obj, een type dat IDisposableimplementeert. - Er wordt een null-controle uitgevoerd omdat 
objwordt gemaakt in een levenscyclusmethode (niet weergegeven). 
@implements IDisposable
...
@code {
    ...
    public void Dispose()
    {
        obj?.Dispose();
    }
}
Als één object verwijdering vereist, kan een lambda worden gebruikt om het object te verwijderen wanneer Dispose wordt aangeroepen. Het volgende voorbeeld wordt weergegeven in het ASP.NET Core Razor component rendering artikel en demonstreert het gebruik van een lambda-expressie voor de verwijdering van een Timer.
              TimerDisposal1.razor:
@page "/timer-disposal-1"
@using System.Timers
@implements IDisposable
<PageTitle>Timer Disposal 1</PageTitle>
<h1>Timer Disposal Example 1</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer timer = new(1000);
    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer.Dispose();
}
              TimerDisposal1.razor:
@page "/timer-disposal-1"
@using System.Timers
@implements IDisposable
<PageTitle>Timer Disposal 1</PageTitle>
<h1>Timer Disposal Example 1</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer timer = new(1000);
    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer.Dispose();
}
              CounterWithTimerDisposal1.razor:
@page "/counter-with-timer-disposal-1"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer timer = new(1000);
    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer.Dispose();
}
              CounterWithTimerDisposal1.razor:
@page "/counter-with-timer-disposal-1"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer timer = new(1000);
    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer.Dispose();
}
              CounterWithTimerDisposal1.razor:
@page "/counter-with-timer-disposal-1"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer timer = new(1000);
    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer.Dispose();
}
              CounterWithTimerDisposal1.razor:
@page "/counter-with-timer-disposal-1"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer timer = new Timer(1000);
    protected override void OnInitialized()
    {
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer.Dispose();
}
Notitie
In het voorgaande voorbeeld wordt de aanroep naar StateHasChanged verpakt door een aanroep naar ComponentBase.InvokeAsync omdat de callback buiten de synchronisatiecontext van Blazorwordt aangeroepen. Zie ASP.NET Core Razor component renderingvoor meer informatie.
Als het object is gemaakt in een levenscyclusmethode, zoals OnInitialized{Async}, controleert u op null voordat u Disposeaanroept.
              TimerDisposal2.razor:
@page "/timer-disposal-2"
@using System.Timers
@implements IDisposable
<PageTitle>Timer Disposal 2</PageTitle>
<h1>Timer Disposal Example 2</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer? timer;
    protected override void OnInitialized()
    {
        timer = new Timer(1000);
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer?.Dispose();
}
              TimerDisposal2.razor:
@page "/timer-disposal-2"
@using System.Timers
@implements IDisposable
<PageTitle>Timer Disposal 2</PageTitle>
<h1>Timer Disposal Example 2</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer? timer;
    protected override void OnInitialized()
    {
        timer = new Timer(1000);
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer?.Dispose();
}
              CounterWithTimerDisposal2.razor:
@page "/counter-with-timer-disposal-2"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer? timer;
    protected override void OnInitialized()
    {
        timer = new Timer(1000);
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer?.Dispose();
}
              CounterWithTimerDisposal2.razor:
@page "/counter-with-timer-disposal-2"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer? timer;
    protected override void OnInitialized()
    {
        timer = new Timer(1000);
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer?.Dispose();
}
              CounterWithTimerDisposal2.razor:
@page "/counter-with-timer-disposal-2"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer timer;
    protected override void OnInitialized()
    {
        timer = new Timer(1000);
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer?.Dispose();
}
              CounterWithTimerDisposal2.razor:
@page "/counter-with-timer-disposal-2"
@using System.Timers
@implements IDisposable
<h1>Counter with <code>Timer</code> disposal</h1>
<p>Current count: @currentCount</p>
@code {
    private int currentCount = 0;
    private Timer timer;
    protected override void OnInitialized()
    {
        timer = new Timer(1000);
        timer.Elapsed += (sender, eventArgs) => OnTimerCallback();
        timer.Start();
    }
    private void OnTimerCallback()
    {
        _ = InvokeAsync(() =>
        {
            currentCount++;
            StateHasChanged();
        });
    }
    public void Dispose() => timer?.Dispose();
}
Zie voor meer informatie:
Asynchrone IAsyncDisposable
Gebruik IAsyncDisposable.DisposeAsyncvoor asynchrone verwijderingstaken.
Het volgende onderdeel:
- Implementeert IAsyncDisposable met de 
@implementsRazor richtlijn. - Verwijdert 
obj, een onbeheerd type dat IAsyncDisposableimplementeert. - Er wordt een null-controle uitgevoerd omdat 
objwordt gemaakt in een levenscyclusmethode (niet weergegeven). 
@implements IAsyncDisposable
...
@code {
    ...
    public async ValueTask DisposeAsync()
    {
        if (obj is not null)
        {
            await obj.DisposeAsync();
        }
    }
}
Zie voor meer informatie:
- ASP.NET Core Blazor synchronisatiecontext
 - onbeheerde resources (.NET-documentatie) opschonen
 - Null-voorwaardelijke operatoren ?." en ? []
 
Toewijzing van null aan verwijderde objecten
Meestal hoeft u null niet toe te wijzen aan verwijderde objecten nadat u Dispose/DisposeAsynchebt aangeroepen. Zeldzame gevallen voor het toewijzen van null omvatten het volgende:
- Als het type van het object slecht is geïmplementeerd en herhalende aanroepen naar Dispose/DisposeAsyncniet tolereert, wijst u na verwijdering 
nulltoe om verdere aanroepen naar Dispose/DisposeAsyncprobleemloos over te slaan. - Als een proces met een lange levensduur een verwijzing naar een verwijderd object blijft bevatten, staat het toewijzen van 
nullde garbagecollector toe om het object vrij te maken ondanks het langdurige proces dat een verwijzing naar het object bevat. 
Dit zijn ongebruikelijke scenario's. Voor objecten die correct zijn geïmplementeerd en normaal werken, is er geen reden om null toe te wijzen aan afgedankte objecten. In zeldzame gevallen waarin een object moet worden toegewezen null, raden we u aan de reden te documenteren en een oplossing te zoeken die voorkomt dat nullmoet worden toegewezen.
StateHasChanged
Notitie
Bellen StateHasChanged in Dispose en DisposeAsync wordt niet ondersteund. 
              StateHasChanged kan worden aangeroepen als onderdeel van het afbreken van de renderer, zodat het aanvragen van UI-updates op dat moment niet wordt ondersteund.
Gebeurtenishandlers
Schrijf u altijd uit voor gebeurtenishandlers van .NET-gebeurtenissen. In de volgende Blazor formulier voorbeelden ziet u hoe u een gebeurtenis-handler kunt afmelden in de methode Dispose.
Private veld en lambda-benadering:
@implements IDisposable
<EditForm ... EditContext="editContext" ...>
    ...
    <button type="submit" disabled="@formInvalid">Submit</button>
</EditForm>
@code {
    ...
    private EventHandler<FieldChangedEventArgs>? fieldChanged;
    protected override void OnInitialized()
    {
        editContext = new(model);
        fieldChanged = (_, __) =>
        {
            ...
        };
        editContext.OnFieldChanged += fieldChanged;
    }
    public void Dispose()
    {
        editContext.OnFieldChanged -= fieldChanged;
    }
}
Benadering van privémethode:
@implements IDisposable
<EditForm ... EditContext="editContext" ...>
    ...
    <button type="submit" disabled="@formInvalid">Submit</button>
</EditForm>
@code {
    ...
    protected override void OnInitialized()
    {
        editContext = new(model);
        editContext.OnFieldChanged += HandleFieldChanged;
    }
    private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
    {
        ...
    }
    public void Dispose()
    {
        editContext.OnFieldChanged -= HandleFieldChanged;
    }
}
Zie Blazor en de andere formulierenartikelen in de Forms-knoop voor meer informatie over het -onderdeel en formulieren.
Anonieme functies, methoden en expressies
Wanneer anonieme functies, methoden of expressies worden gebruikt, is het niet nodig om IDisposable te implementeren en gedelegeerden af te melden. Het niet afmelden van een gemachtigde is echter een probleem wanneer het object dat het evenement blootlegt, langer meegaat dan de levensduur van het onderdeel dat de gedelegeerde registreert. Wanneer dit gebeurt, resulteert een geheugenlek omdat de geregistreerde gemachtigde het oorspronkelijke object actief houdt. Gebruik daarom alleen de volgende benaderingen wanneer u weet dat de gemachtigde van de gebeurtenis snel wordt verwijderd. Wanneer u twijfelt over de levensduur van objecten waarvoor verwijdering is vereist, abonneert u een gedelegeerdemethode en moet u de gemachtigde correct verwijderen zoals in de eerdere voorbeelden wordt weergegeven.
Anonieme lambdamethodebenadering (expliciete verwijdering is niet vereist):
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
    formInvalid = !editContext.Validate();
    StateHasChanged();
}
protected override void OnInitialized()
{
    editContext = new(starship);
    editContext.OnFieldChanged += (s, e) => HandleFieldChanged((editContext)s, e);
}
Anonieme lambda-expressiebenadering (expliciete verwijdering is niet vereist):
private ValidationMessageStore? messageStore;
[CascadingParameter]
private EditContext? CurrentEditContext { get; set; }
protected override void OnInitialized()
{
    ...
    messageStore = new(CurrentEditContext);
    CurrentEditContext.OnValidationRequested += (s, e) => messageStore.Clear();
    CurrentEditContext.OnFieldChanged += (s, e) => 
        messageStore.Clear(e.FieldIdentifier);
}
Het volledige voorbeeld van de voorgaande code met anonieme lambda-expressies wordt weergegeven in het ASP.NET Core Blazor formuliervalidatie artikel.
Zie Onbeheerde resources opschonen en de onderwerpen die volgen bij het implementeren van de Dispose en DisposeAsync methoden voor meer informatie.
Verwijdering tijdens de JS-interoperabiliteit
Trap JSDisconnectedException in mogelijke gevallen waarbij verlies van het BlazorSignalR-circuit voorkomt dat JS interop-aanroepen plaatsvinden en leidt tot een niet-afgehandelde uitzondering.
Zie de volgende bronnen voor meer informatie: