Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Jegyzet
Ez nem a cikk legújabb verziója. Az aktuális kiadásról a cikk .NET 10-es verziójában olvashat.
Figyelmeztetés
A ASP.NET Core ezen verziója már nem támogatott. További információ: .NET és .NET Core támogatási szabályzat. Az aktuális kiadást lásd ennek a cikknek a .NET 9-es verziójában.
Ez a cikk a ASP.NET Core-összetevők Razor ártalmatlanítási folyamatát ismerteti és IDisposableismertetiIAsyncDisposable.
Ha egy összetevő IDisposable vagy IAsyncDisposableimplementál, a keretrendszer erőforrás-elidegenítést kér, amikor az összetevőt eltávolítják a felhasználói felületről. Ne támaszkodhat a metódusok végrehajtásának pontos időzítésére. A IAsyncDisposable például azelőtt vagy azután aktiválható, hogy egy aszinkron Task várakozna a OnInitalizedAsync-ben vagy a OnParametersSetAsync-ban, illetve azok meghívásakor vagy befejezésekor. Emellett az objektumelhelyezési kód nem feltételezheti, hogy az inicializálás vagy más életciklus-metódusok során létrehozott objektumok léteznek.
Az összetevőknek nem kell egyszerre implementálniuk IDisposable és IAsyncDisposable. Ha mindkettő implementálva van, a keretrendszer csak az aszinkron túlterhelést hajtja végre.
A fejlesztői kódnak biztosítania kell, hogy IAsyncDisposable implementációk végrehajtása ne tartson sokáig.
További információ: ASP.NET Core Blazor szinkronizálási környezetének bevezető megjegyzései.
JavaScript interop objektumhivatkozások megsemmisítése
A JavaScript (JS) interop cikkek példái a tipikus objektumkezelési mintákat szemléltetik.
Ha a .NET-ből hívja meg a(z) JS-t, ahogy a -ben leírtuk A JavaScript-függvények meghívása a .NET-metódusokból ASP.NET Core Blazor-ban, semmisítse meg a létrehozott IJSObjectReference/IJSInProcessObjectReference/JSObjectReference-t akár a .NET-ből, akár a JS-ból, a JS memória kiszivárgásának elkerülése érdekében.
Ha a .NET-et JSa ASP.NET Core-ban Blazortalálható JavaScript-függvényekből származó .NET-metódusok meghívása során hívja meg, a .NET-ből vagy a DotNetObjectReference .NET-memória kiszivárgásának elkerülése érdekében semmisítse meg a létrehozott JS fájlokat.
JS interop objektumhivatkozások a hivatkozást létrehozó JS interop hívás oldalán található azonosító által kulcsolt térképként vannak implementálva. Ha az objektumelhelyezést a .NET vagy JS oldalról kezdeményezik, Blazor eltávolítja a bejegyzést a térképről, és az objektum szemétként gyűjthető, feltéve, hogy nincs más erős hivatkozás az objektumra.
Legalább a .NET oldalon létrehozott objektumokat mindig megsemmisítse, hogy elkerülje a .NET által felügyelt memória kiszivárgását.
DOM-tisztítási feladatok az összetevők ártalmatlanítása során
További információ: ASP.NET Core Blazor JavaScript-együttműködés (JS interop).
Útmutatásért a JSDisconnectedException tekintetében arra az esetre, amikor egy áramkör le van választva, lásd: ASP.NET Core Blazor JavaScript-interopérabilitás (JS együttműködés). Általános JavaScript-interop hibakezelési útmutatásért tekintse meg az JavaScript-interop szakaszt az ASP.NET Core alkalmazások hibáinak kezelése Blazor című részben.
Szinkron IDisposable
Szinkron ártalmatlanítási feladatokhoz használja a IDisposable.Disposeeszközt.
A következő összetevő:
- A IDisposable az
@implementsRazor irányelv használatával kerül megvalósításra. - Eltávolítja a
objtípust, amely megvalósítja a IDisposable-et. - A null értékű ellenőrzés azért történik, mert
objegy életciklus-metódusban jön létre (nem jelenik meg).
@implements IDisposable
...
@code {
...
public void Dispose()
{
obj?.Dispose();
}
}
Ha egyetlen objektumot kell megsemmisíteni, a lambda segítségével Dispose meghívásakor megsemmisítheti az objektumot. Az alábbi példa megjelenik a ASP.NET Core Razor összetevő renderelési cikkben, és bemutatja a lambda kifejezés használatát egy Timermegsemmisítéséhez.
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();
}
Jegyzet
Az előző példában a StateHasChanged hívását egy ComponentBase.InvokeAsync hívása csomagolja be, mert a visszahívást a rendszer Blazorszinkronizálási környezetén kívül hívja meg. További információkért lásd: ASP.NET Core Razor komponens megjelenítése.
Ha az objektum életciklus-metódusban (például OnInitialized{Async}) jön létre, a nullhívása előtt ellenőrizze a 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();
}
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();
}
További információ:
- Nem felügyelt erőforrások kezelése és tisztítása (.NET-dokumentáció)
- Nullfeltételes operátorok ?. és? []
Aszinkron IAsyncDisposable
Aszinkron ártalmatlanítási feladatokhoz használja a IAsyncDisposable.DisposeAsync.
A következő összetevő:
- A IAsyncDisposable az
@implementsRazor irányelv használatával kerül megvalósításra. - Megsemmisíti a
obj-t, amely egy nem felügyelt típus, és megvalósítja a IAsyncDisposable-et. - A null értékű ellenőrzés azért történik, mert
objegy életciklus-metódusban jön létre (nem jelenik meg).
@implements IAsyncDisposable
...
@code {
...
public async ValueTask DisposeAsync()
{
if (obj is not null)
{
await obj.DisposeAsync();
}
}
}
További információ:
- ASP.NET Core Blazor szinkronizálási környezet
- Nem felügyelt erőforrások kezelése és tisztítása (.NET-dokumentáció)
- Nullfeltételes operátorok ?. és? []
A null hozzárendelése az eldobott objektumokhoz
A nullDispose/hívása után általában nincs szükség DisposeAsync hozzárendelésére az eldobott objektumokhoz. A null hozzárendelésének ritka esetei a következők:
- Ha az objektum típusa rosszul van implementálva, és nem tolerálja a Dispose/DisposeAsyncismételt hívásait, rendeljen
null-at a megsemmisítés után, hogy zökkenőmentesen kihagyja a további hívásokat Dispose/DisposeAsync. - Ha egy hosszú életű folyamat továbbra is hivatkozik egy megsemmisített objektumra, a
nullhozzárendelése lehetővé teszi, hogy a szemétgyűjtő felszabadítsa az objektumot annak ellenére, hogy a hosszú élettartamú folyamat hivatkozik rá.
Ezek szokatlan forgatókönyvek. A helyesen implementált és normálisan viselkedő objektumok esetében nincs értelme null hozzárendelni az elvetett objektumokhoz. Azokban a ritka esetekben, amikor egy objektumot nullkell hozzárendelni, javasoljuk, hogy dokumentálja az okot, és keressen olyan megoldást, amely megakadályozza a nullhozzárendelését.
StateHasChanged
Jegyzet
A StateHasChanged hívása Dispose-ben és DisposeAsync-ben nem támogatott.
StateHasChanged a renderelő lebontásának részeként lehet meghívni, így a felhasználói felület frissítéseinek kérése ezen a ponton nem támogatott.
Eseménykezelők
Mindig iratkozzon le az eseménykezelők .NET-eseményeiről. Az alábbi Blazor űrlap példák bemutatják, hogyan lehet leiratkozni egy eseménykezelőről a Dispose metódusban.
Privát mező és lambda megközelítés:
@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;
}
}
Privát módszer megközelítése:
@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;
}
}
Az EditForm összetevővel és űrlapokkal kapcsolatos további információkért tekintse meg a ASP.NET Core Blazor-űrlapok áttekintési és az Űrlapok csomópont egyéb űrlapcikkeit.
Névtelen függvények, metódusok és kifejezések
Ha névtelen függvényeket , metódusokat vagy kifejezéseket használ, nem szükséges IDisposable és leiratkozási meghatalmazottak implementálása. A meghatalmazott leiratkozásának sikertelensége azonban probléma , ha az eseményt felfedő objektum túllépi a meghatalmazottat regisztráló összetevő élettartamát. Ha ez történik, memóriavesztés következik be, mert a regisztrált meghatalmazott életben tartja az eredeti objektumot. Ezért csak akkor használja a következő módszereket, ha tudja, hogy az eseménymegbízott gyorsan rendelkezik. Ha kétségei vannak az ártalmatlanítást igénylő objektumok élettartamával kapcsolatban, iratkozzon fel egy delegált metódusra, és a korábbi példák szerint megfelelően oldja fel a delegáltat.
Névtelen lambda metódus megközelítés (explicit ártalmatlanítás nem szükséges):
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);
}
Névtelen lambda kifejezési megközelítés (explicit ártalmatlanítás nem szükséges):
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);
}
Az előző kód teljes példája névtelen lambda kifejezésekkel jelenik meg a ASP.NET Core Blazor űrlapok érvényesítési cikkben.
További információ: Nem felügyelt erőforrások tisztítása és az azt követő témakörök a Dispose és DisposeAsync metódusok implementálásával kapcsolatban.
Ártalmatlanítás JS interop során
Csapdázza JSDisconnectedException-t olyan esetekben, amikor a BlazorSignalR áramkör elvesztése megakadályozza a JS interop hívások végrehajtását, és kezeletlen kivételt eredményez.
További információ: