Olvasás angol nyelven

Megosztás a következőn keresztül:


ASP.NET Core Razor-összetevők életciklusa

Megjegyzés

Ez nem a cikk legújabb verziója. Az aktuális kiadást lásd a cikk .NET 9-es verziójában.

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 a cikk .NET 9-es verziójában.

Fontos

Ezek az információk egy olyan előzetes termékre vonatkoznak, amelyet a kereskedelmi forgalomba kerülés előtt jelentősen módosíthatnak. A Microsoft nem vállal kifejezett vagy hallgatólagos szavatosságot az itt megadott információkra vonatkozóan.

Az aktuális kiadást lásd a cikk .NET 9-es verziójában.

Ez a cikk az ASP.NET Core Razor összetevő életciklusát és az életciklus-események használatát ismerteti.

Életciklus-események

A Razor összetevő szinkron és aszinkron életciklus-metódusok halmazában dolgozza fel Razor összetevők életciklus-eseményeit. Az életciklus-metódusokat felül lehet bírálni az összetevők további műveleteinek végrehajtásához az összetevők inicializálása és renderelése során.

Ez a cikk leegyszerűsíti az összetevők életciklusának eseményfeldolgozását az összetett keretrendszerlogika tisztázása érdekében, és nem fedi le az évek során végrehajtott összes módosítást. Előfordulhat, hogy hozzá kell férnie a ComponentBase referenciaforráshoz, hogy integrálja az egyéni eseményfeldolgozást Blazoréletciklus-eseményfeldolgozással. A referenciaforrás kód megjegyzései további megjegyzéseket tartalmaznak az életciklus-eseményfeldolgozással kapcsolatban, amelyek nem jelennek meg ebben a cikkben vagy a API dokumentációjában.

Megjegyzés

A .NET referenciaforrásra mutató dokumentációs hivatkozások általában betöltik az adattár alapértelmezett ágát, amely a .NET következő kiadásának aktuális fejlesztését jelöli. Egy adott kiadás címkéjének kiválasztásához válassza az Ágak vagy címkék közötti váltás legördülő listát. További információ: A ASP.NET Core-forráskód (dotnet/AspNetCore.Docs #26205) verziócímkéjének kiválasztása.

Az alábbi egyszerűsített diagramok Razor összetevők életciklusának eseményfeldolgozását szemléltetik. Az életciklus-eseményekhez társított C#-metódusok a cikk következő szakaszaiban található példákkal vannak definiálva.

Összetevő életciklus-eseményei:

  1. Ha az összetevő először jelenik meg egy kérelemben:
    • Hozzon létre az összetevő példányát.
    • Hajtsd végre a tulajdonságok befecskendezését.
    • Hívja OnInitialized{Async}. Ha egy hiányos Task van visszaadva, a Task-et várják, majd az összetevőt újrarenderelik. A szinkron metódust az aszinkron metódus előtt hívjuk meg.
  2. Hívja OnParametersSet{Async}. Ha egy hiányos Task van visszaadva, a Task-et várják, majd az összetevőt újrarenderelik. A szinkron metódust az aszinkron metódus előtt hívjuk meg.
  3. Rendereljen az összes szinkron munkához, és fejezze be a Tasks.

Megjegyzés

Az életciklus-eseményekben végrehajtott aszinkron műveletek késleltethetik az összetevők renderelését vagy az adatok megjelenítését. További információért lásd a Hiányos aszinkron műveletek kezelése a renderelés szakaszában című fejezetet a jelen cikk későbbi részében.

A szülőösszetevők a gyermekösszetevők előtt jelennek meg, mert a renderelés határozza meg, hogy mely gyermekek vannak jelen. Ha szinkron szülő komponens inicializálását használja, a szülő komponens inicializálása garantáltan elsőként fejeződik be. Ha aszinkron szülőösszetevő-inicializálást használ, a szülő- és gyermekösszetevő-inicializálás befejezési sorrendje nem határozható meg, mert az a futó inicializálási kódtól függ.

A Razor összetevő életciklus-eseményei a Blazor

DOM-eseményfeldolgozás:

  1. Az eseménykezelő fut.
  2. Ha egy hiányos Task van visszaadva, a Task-et várják, majd az összetevőt újrarenderelik.
  3. Rendereljen az összes szinkron munkához, és fejezze be a Tasks.

DOM eseményfeldolgozás

A Render életciklusa:

  1. Kerülje a további renderelési műveleteket az összetevőn, ha az alábbi feltételek teljesülnek:
    • Nem ez az első renderelés.
    • ShouldRender visszaadja false.
  2. Hozza létre a renderelési fa diffjét (különbség) és renderelje az összetevőt.
  3. Várjon a DOM frissítésére.
  4. Hívja OnAfterRender{Async}. A szinkron metódust az aszinkron metódus előtt hívjuk meg.

renderelési életciklus

Az StateHasChanged hívások újrarenderelést eredményeznek. További információkért lásd: ASP.NET Core Razor összetevő renderelése.

Quiescence az előrenderelés során

A kiszolgálóoldali Blazor alkalmazásokban az előrenderelés megvárja nyugalmi állapotot, ami azt jelenti, hogy egy összetevő csak akkor jelenik meg, ha a renderelési fa összes összetevője befejezte a renderelést. A kiesés észrevehető késést okozhat a renderelésben, ha egy összetevő hosszú ideig futó feladatokat hajt végre az inicializálás és más életciklus-módszerek során, ami rossz felhasználói élményt eredményez. További információért lásd a Hiányos aszinkron műveletek kezelése a renderelés szakaszában című fejezetet a jelen cikk későbbi részében.

Paraméterek beállításakor (SetParametersAsync)

SetParametersAsync beállítja az összetevő szülője által a renderfában vagy az útvonalparaméterekben megadott paramétereket.

A metódus ParameterView paramétere az összetevő összetevőparaméterének értékeit tartalmazza minden alkalommal, amikor SetParametersAsync meghívják. A SetParametersAsync metódus felülírásával a fejlesztői kód közvetlenül kezelheti ParameterViewparamétereit.

A SetParametersAsync alapértelmezett implementációja az egyes tulajdonságok értékét az [Parameter] vagy [CascadingParameter] attribútummal állítja be,, amelynek megfelelő értéke van a ParameterView. A ParameterView-ban megfelelő értékkel nem rendelkező paraméterek változatlanok maradnak.

A kódnak általában az alaposztály metódusát (await base.SetParametersAsync(parameters);) kell meghívnia SetParametersAsyncfelülírásakor. Speciális helyzetekben a fejlesztői kód bármilyen módon képes értelmezni a bejövő paraméterek értékeit, ha nem invokálja az alaposztály metódusát. Nincs például szükség arra, hogy a bejövő paramétereket az osztály tulajdonságaihoz rendelje. A kód alaposztály-metódus meghívása nélkül történő strukturálásakor azonban a ComponentBase referenciaforrásra kell hivatkoznia, mert más életciklus-metódusokat hív meg, és összetett módon jeleníti meg az eseményindítókat.

Megjegyzés

A .NET referenciaforrásra mutató dokumentációs hivatkozások általában betöltik az adattár alapértelmezett ágát, amely a .NET következő kiadásának aktuális fejlesztését jelöli. Egy adott kiadás címkéjének kiválasztásához válassza az Ágak vagy címkék közötti váltás legördülő listát. További információ: A ASP.NET Core-forráskód (dotnet/AspNetCore.Docs #26205) verziócímkéjének kiválasztása.

Ha az ComponentBase.SetParametersAsync inicializálási és renderelési logikájára szeretne támaszkodni, de nem szeretné feldolgozni a bejövő paramétereket, lehetősége van üres ParameterView átadni az alaposztály metódusának:

await base.SetParametersAsync(ParameterView.Empty);

Ha az eseménykezelők a fejlesztői kódban vannak megadva, szüntesse meg őket a felszámoláskor. További információért lásd: ASP.NET Core Razor összetevők eltávolítása.

Az alábbi példában ParameterView.TryGetValue hozzárendeli a Param paraméter értékét value, ha a Param útvonalparaméterének elemzése sikeres. Ha value nem null, az összetevő megjeleníti az értéket.

Bár az útvonalparaméter-egyeztetés nem érzékeny a kis- és nagybetűkre, TryGetValue csak a kis- és nagybetűket megkülönböztető paraméterneveknek felel meg az útvonalsablonban. Az alábbi példában /{Param?} kell használni az útvonalsablonban annak érdekében, hogy az érték TryGetValuelegyen, és ne /{param?}. Ha /{param?} van használva ebben a forgatókönyvben, TryGetValuefalse-t ad vissza, és message nincs beállítva egyik message sztringre sem.

SetParamsAsync.razor:

@page "/set-params-async/{Param?}"

<PageTitle>Set Parameters Async</PageTitle>

<h1>Set Parameters Async Example</h1>

<p>@message</p>

@code {
    private string message = "Not set";

    [Parameter]
    public string? Param { get; set; }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        if (parameters.TryGetValue<string>(nameof(Param), out var value))
        {
            if (value is null)
            {
                message = "The value of 'Param' is null.";
            }
            else
            {
                message = $"The value of 'Param' is {value}.";
            }
        }

        await base.SetParametersAsync(parameters);
    }
}
@page "/set-params-async/{Param?}"

<PageTitle>Set Parameters Async</PageTitle>

<h1>Set Parameters Async Example</h1>

<p>@message</p>

@code {
    private string message = "Not set";

    [Parameter]
    public string? Param { get; set; }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        if (parameters.TryGetValue<string>(nameof(Param), out var value))
        {
            if (value is null)
            {
                message = "The value of 'Param' is null.";
            }
            else
            {
                message = $"The value of 'Param' is {value}.";
            }
        }

        await base.SetParametersAsync(parameters);
    }
}
@page "/set-params-async/{Param?}"

<p>@message</p>

@code {
    private string message = "Not set";

    [Parameter]
    public string? Param { get; set; }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        if (parameters.TryGetValue<string>(nameof(Param), out var value))
        {
            if (value is null)
            {
                message = "The value of 'Param' is null.";
            }
            else
            {
                message = $"The value of 'Param' is {value}.";
            }
        }

        await base.SetParametersAsync(parameters);
    }
}
@page "/set-params-async/{Param?}"

<p>@message</p>

@code {
    private string message = "Not set";

    [Parameter]
    public string? Param { get; set; }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        if (parameters.TryGetValue<string>(nameof(Param), out var value))
        {
            if (value is null)
            {
                message = "The value of 'Param' is null.";
            }
            else
            {
                message = $"The value of 'Param' is {value}.";
            }
        }

        await base.SetParametersAsync(parameters);
    }
}
@page "/set-params-async/{Param?}"

<p>@message</p>

@code {
    private string message = "Not set";

    [Parameter]
    public string Param { get; set; }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        if (parameters.TryGetValue<string>(nameof(Param), out var value))
        {
            if (value is null)
            {
                message = "The value of 'Param' is null.";
            }
            else
            {
                message = $"The value of 'Param' is {value}.";
            }
        }

        await base.SetParametersAsync(parameters);
    }
}
@page "/set-params-async"
@page "/set-params-async/{Param}"

<p>@message</p>

@code {
    private string message = "Not set";

    [Parameter]
    public string Param { get; set; }

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        if (parameters.TryGetValue<string>(nameof(Param), out var value))
        {
            if (value is null)
            {
                message = "The value of 'Param' is null.";
            }
            else
            {
                message = $"The value of 'Param' is {value}.";
            }
        }

        await base.SetParametersAsync(parameters);
    }
}

Összetevő inicializálása (OnInitialized{Async})

OnInitialized és OnInitializedAsync kizárólag az összetevőpéldány teljes élettartama alatt inicializálnak egy összetevőt. A paraméterértékek és a paraméterértékek módosítása nem befolyásolhatja az ezekben a metódusokban végrehajtott inicializálást. A statikus beállítások betöltése például egy olyan legördülő listába, amely nem változik az összetevő élettartama során, és amely nem függ a paraméterértékektől, az egyik életciklus-metódusban történik. Ha a paraméterértékek vagy a paraméterértékek változásai hatással vannak az összetevő állapotára, használja inkább a OnParametersSet{Async}.

Ezek a metódusok akkor lesznek meghívva, ha az összetevő inicializálva van, miután megkapta a kezdeti paramétereket SetParametersAsync. A szinkron metódust az aszinkron metódus előtt hívjuk meg.

Ha szinkron szülőösszetevő-inicializálást használ, a szülő inicializálása garantáltan befejeződik a gyermekösszetevő inicializálása előtt. Ha aszinkron szülőösszetevő-inicializálást használ, a szülő- és gyermekösszetevő-inicializálás befejezési sorrendje nem határozható meg, mert az a futó inicializálási kódtól függ.

Szinkron művelet esetén bíráld felül a OnInitialized-t.

OnInit.razor:

@page "/on-init"

<PageTitle>On Initialized</PageTitle>

<h1>On Initialized Example</h1>

<p>@message</p>

@code {
    private string? message;

    protected override void OnInitialized() => 
        message = $"Initialized at {DateTime.Now}";
}
@page "/on-init"

<PageTitle>On Initialized</PageTitle>

<h1>On Initialized Example</h1>

<p>@message</p>

@code {
    private string? message;

    protected override void OnInitialized() => 
        message = $"Initialized at {DateTime.Now}";
}
@page "/on-init"

<p>@message</p>

@code {
    private string? message;

    protected override void OnInitialized()
    {
        message = $"Initialized at {DateTime.Now}";
    }
}
@page "/on-init"

<p>@message</p>

@code {
    private string? message;

    protected override void OnInitialized()
    {
        message = $"Initialized at {DateTime.Now}";
    }
}
@page "/on-init"

<p>@message</p>

@code {
    private string message;

    protected override void OnInitialized()
    {
        message = $"Initialized at {DateTime.Now}";
    }
}
@page "/on-init"

<p>@message</p>

@code {
    private string message;

    protected override void OnInitialized()
    {
        message = $"Initialized at {DateTime.Now}";
    }
}

Aszinkron művelet végrehajtásához felülbírálja OnInitializedAsync, és használja a await operátort:

protected override async Task OnInitializedAsync()
{
    await ...
}

Ha az egyéni alaposztály egyéni inicializálási logikával van használva, hívja meg a OnInitializedAsync metódust az alaposztályon:

protected override async Task OnInitializedAsync()
{
    await ...

    await base.OnInitializedAsync();
}

Nem szükséges meghívni ComponentBase.OnInitializedAsync, hacsak nem használ egyéni alaposztályt egyéni logikával. További információ: Alaposztály életciklus-módszerei szakasz.

Az összetevőnek biztosítania kell, hogy érvényes állapotban legyen a rendereléshez, amikor OnInitializedAsync egy potenciálisan hiányos Task-re vár. Ha a metódus hiányos Taskad vissza, a szinkron módon befejezett résznek érvényes állapotban kell hagynia az összetevőt a rendereléshez. További információért lásd a ASP.NET Core Blazor szinkronizációs környezetének és az ASP.NET Core összetevők Razor eltávolításánakbevezető megjegyzéseit.

Blazor olyan alkalmazások, amelyek a tartalmat a kiszolgálón előre renderelik, kétszer hívják meg a(z) OnInitializedAsync:

  • Egyszer, amikor az összetevő kezdetben statikusan megjelenik a lap részeként.
  • Másodszor, amikor a böngésző megjeleníti az összetevőt.

Ha meg szeretné akadályozni, hogy az OnInitializedAsync fejlesztői kódja kétszer fusson az előrendeléskor, tekintse meg az állapotalapú újracsatlakozást szakasz előrendelése után. A szakasz tartalma az Blazor Web App-okra és az állapotalapú SignalRújracsatlakozásra fókuszál. Ha az állapotot az inicializálási kód futtatása közben szeretné megőrizni az előzetes megjelenítés során, tekintse meg a Prerender ASP.NET Core Razor összetevőket.

Ha meg szeretné akadályozni, hogy az OnInitializedAsync fejlesztői kódja kétszer fusson az előrendeléskor, tekintse meg az állapotalapú újracsatlakozást szakasz előrendelése után. Bár a szakasz tartalma az Blazor Server és az állapotalapú SignalRújracsatlakozássalfoglalkozik, az üzemeltetett Blazor WebAssembly megoldások (WebAssemblyPrerendered) előrendelésének forgatókönyve hasonló feltételekkel és megközelítésekkel szolgál annak megakadályozására, hogy a fejlesztői kód kétszer végrehajtásra kerüljön. Ha az inicializálási kód végrehajtása során szeretné megőrizni az állapotot az előrendelés során, tekintse meg ASP.NET Core Razor összetevőinek integrálása MVC-vel vagy Razor Pages.

Bár egy Blazor alkalmazás előrerendezést végez, bizonyos műveletek, például a JavaScriptbe való hívás (JS interop) nem lehetséges. Előfordulhat, hogy az összetevőknek másképp kell renderelnie, ha előre van berendelve. További információért tekintse meg a Előfeldolgozás JavaScript együttműködéssel szakaszt.

Ha az eseménykezelők a fejlesztői kódban vannak megadva, szüntesse meg őket a felszámoláskor. További információért lásd: ASP.NET Core Razor összetevők eltávolítása.

A streaming alapú renderelést statikus kiszolgálóoldali rendereléssel (statikus SSR) vagy előzetes rendereléssel használja az olyan összetevők felhasználói élményének javítására, amelyek a OnInitializedAsync hosszú ideig futó aszinkron feladatokat hajtanak végre a teljes renderelés érdekében. További információ:

Paraméterek beállítása után (OnParametersSet{Async})

OnParametersSet vagy OnParametersSetAsync elnevezése:

  • Az összetevő OnInitialized-ban vagy OnInitializedAsync-ben történő inicializálása után.

  • Amikor a szülőösszetevő újrarendeli és szolgáltatja a következőt:

    • Ismert vagy primitív nem módosítható típusok, ha legalább egy paraméter módosult.
    • Összetett típusú paraméterek. A keretrendszer nem tudja, hogy egy összetett típusú paraméter értékei belsőleg mutálódnak-e, ezért a keretrendszer mindig módosítottként kezeli a paraméterkészletet egy vagy több összetett típusú paraméter jelenlétekor.

    A megjelenítési konvenciókról további információt a ASP.NET Core Razor összetevő renderelésicímű témakörben talál.

A szinkron metódust az aszinkron metódus előtt hívjuk meg.

A metódusok akkor is meghívhatók, ha a paraméterértékek nem változtak. Ez a viselkedés kiemeli, hogy a fejlesztőknek további logikát kell implementálniuk a metódusokon belül annak ellenőrzéséhez, hogy a paraméterértékek valóban megváltoztak-e, mielőtt újra inicializálják az adatokat vagy az adott paraméterektől függő állapotot.

A következő példaösszetevőhöz navigáljon az összetevő lapjára egy URL-címen:

  • A StartDate által kapott kezdési dátummal: /on-parameters-set/2021-03-19
  • Kezdési dátum nélkül, ahol StartDate az aktuális helyi időérték van hozzárendelve: /on-parameters-set

Megjegyzés

Egy összetevőútvonalon nem lehet DateTime paramétert korlátozni az útvonalkorláttal datetime, és a paramétert nem kötelezővé tenni. Ezért a következő OnParamsSet összetevő két @page direktívát használ az útválasztás kezeléséhez az URL-cím megadott dátumszegmensével és anélkül.

OnParamsSet.razor:

@page "/on-params-set"
@page "/on-params-set/{StartDate:datetime}"

<PageTitle>On Parameters Set</PageTitle>

<h1>On Parameters Set Example</h1>

<p>
    Pass a datetime in the URI of the browser's address bar. 
    For example, add <code>/1-1-2024</code> to the address.
</p>

<p>@message</p>

@code {
    private string? message;

    [Parameter]
    public DateTime StartDate { get; set; }

    protected override void OnParametersSet()
    {
        if (StartDate == default)
        {
            StartDate = DateTime.Now;

            message = $"No start date in URL. Default value applied " +
                $"(StartDate: {StartDate}).";
        }
        else
        {
            message = $"The start date in the URL was used " +
                $"(StartDate: {StartDate}).";
        }
    }
}
@page "/on-params-set"
@page "/on-params-set/{StartDate:datetime}"

<PageTitle>On Parameters Set</PageTitle>

<h1>On Parameters Set Example</h1>

<p>
    Pass a datetime in the URI of the browser's address bar. 
    For example, add <code>/1-1-2024</code> to the address.
</p>

<p>@message</p>

@code {
    private string? message;

    [Parameter]
    public DateTime StartDate { get; set; }

    protected override void OnParametersSet()
    {
        if (StartDate == default)
        {
            StartDate = DateTime.Now;

            message = $"No start date in URL. Default value applied " +
                $"(StartDate: {StartDate}).";
        }
        else
        {
            message = $"The start date in the URL was used " +
                $"(StartDate: {StartDate}).";
        }
    }
}
@page "/on-params-set"
@page "/on-params-set/{StartDate:datetime}"

<p>@message</p>

@code {
    private string? message;

    [Parameter]
    public DateTime StartDate { get; set; }

    protected override void OnParametersSet()
    {
        if (StartDate == default)
        {
            StartDate = DateTime.Now;

            message = $"No start date in URL. Default value applied (StartDate: {StartDate}).";
        }
        else
        {
            message = $"The start date in the URL was used (StartDate: {StartDate}).";
        }
    }
}
@page "/on-params-set"
@page "/on-params-set/{StartDate:datetime}"

<p>@message</p>

@code {
    private string? message;

    [Parameter]
    public DateTime StartDate { get; set; }

    protected override void OnParametersSet()
    {
        if (StartDate == default)
        {
            StartDate = DateTime.Now;

            message = $"No start date in URL. Default value applied (StartDate: {StartDate}).";
        }
        else
        {
            message = $"The start date in the URL was used (StartDate: {StartDate}).";
        }
    }
}
@page "/on-params-set"
@page "/on-params-set/{StartDate:datetime}"

<p>@message</p>

@code {
    private string message;

    [Parameter]
    public DateTime StartDate { get; set; }

    protected override void OnParametersSet()
    {
        if (StartDate == default)
        {
            StartDate = DateTime.Now;

            message = $"No start date in URL. Default value applied (StartDate: {StartDate}).";
        }
        else
        {
            message = $"The start date in the URL was used (StartDate: {StartDate}).";
        }
    }
}
@page "/on-params-set"
@page "/on-params-set/{StartDate:datetime}"

<p>@message</p>

@code {
    private string message;

    [Parameter]
    public DateTime StartDate { get; set; }

    protected override void OnParametersSet()
    {
        if (StartDate == default)
        {
            StartDate = DateTime.Now;

            message = $"No start date in URL. Default value applied (StartDate: {StartDate}).";
        }
        else
        {
            message = $"The start date in the URL was used (StartDate: {StartDate}).";
        }
    }
}

Paraméterek és tulajdonságértékek alkalmazásakor aszinkron munkának kell történnie a OnParametersSetAsync életciklus-esemény során:

protected override async Task OnParametersSetAsync()
{
    await ...
}

Ha az egyéni alaposztály egyéni inicializálási logikával van használva, hívja meg a OnParametersSetAsync metódust az alaposztályon:

protected override async Task OnParametersSetAsync()
{
    await ...

    await base.OnParametersSetAsync();
}

Nem szükséges meghívni ComponentBase.OnParametersSetAsync, hacsak nem használ egyéni alaposztályt egyéni logikával. További információ: Alaposztály életciklus-módszerei szakasz.

Az összetevőnek biztosítania kell, hogy érvényes állapotban legyen a rendereléshez, amikor OnParametersSetAsync egy potenciálisan hiányos Task-re vár. Ha a metódus hiányos Taskad vissza, a szinkron módon befejezett résznek érvényes állapotban kell hagynia az összetevőt a rendereléshez. További információért lásd a ASP.NET Core Blazor szinkronizációs környezetének és az ASP.NET Core összetevők Razor eltávolításánakbevezető megjegyzéseit.

Ha az eseménykezelők a fejlesztői kódban vannak megadva, szüntesse meg őket a felszámoláskor. További információért lásd: ASP.NET Core Razor összetevők eltávolítása.

Ha egy eldobható összetevő nem használja a CancellationToken-t, akkor a OnParametersSet-nek és OnParametersSetAsync-nek ellenőrizniük kell, hogy az összetevő meg lett-e semmisítve. Ha OnParametersSetAsync hiányos Taskad vissza, az összetevőnek biztosítania kell, hogy a módszer szinkron módon befejezett része érvényes állapotban hagyja az összetevőt a rendereléshez. További információért lásd a ASP.NET Core Blazor szinkronizációs környezetének és az ASP.NET Core összetevők Razor eltávolításánakbevezető megjegyzéseit.

Az útvonalparaméterekről és korlátozásokról további információt ASP.NET Core Blazor útválasztási és navigációscímű témakörben talál.

Példa a SetParametersAsync manuális implementálására egyes forgatókönyvekben a teljesítmény javítása érdekében: ASP.NET Core Blazor teljesítményre vonatkozó ajánlott eljárások.

Összetevő renderelése után (OnAfterRender{Async})

OnAfterRender és OnAfterRenderAsync egy összetevő interaktív megjelenítése és a felhasználói felület frissítése után (például az elemek böngésző DOM-hoz való hozzáadása után) lesz meghívva. Ezen a ponton az elem- és összetevőhivatkozások kitöltésre kerültek. Ezen a szakaszon további inicializálási lépéseket hajthat végre a renderelt tartalommal, például JS a renderelt DOM-elemekkel interakcióba lépő interop hívásokat. A szinkron metódust az aszinkron metódus előtt hívjuk meg.

Ezek a metódusok nem lesznek meghívva a kiszolgáló előrendelése vagy statikus kiszolgálóoldali renderelése (statikus SSR) során, mert ezek a folyamatok nincsenek élő böngészőbeli DOM-hez csatolva, és már a DOM frissítése előtt befejeződnek.

A OnAfterRenderAsyncesetében az összetevő nem lesz automatikusan újrarendezve a visszaadott Task befejezése után, hogy elkerülje a végtelen renderelési ciklust.

OnAfterRender és OnAfterRenderAsync az összetevő renderelésének befejezése után lesz meghívva. Ezen a ponton az elem- és összetevőhivatkozások kitöltésre kerültek. Ezen a szakaszon további inicializálási lépéseket hajthat végre a renderelt tartalommal, például JS a renderelt DOM-elemekkel interakcióba lépő interop hívásokat. A szinkron metódust az aszinkron metódus előtt hívjuk meg.

Ezek a metódusok nem lesznek meghívva az előrendelés során, mert az előrendelés nem csatlakozik egy élő böngészőbeli DOM-hoz, és a DOM frissítése előtt már befejeződött.

A OnAfterRenderAsyncesetében az összetevő nem lesz automatikusan újrarendezve a visszaadott Task befejezése után, hogy elkerülje a végtelen renderelési ciklust.

A firstRender paramétere a OnAfterRender-hez és OnAfterRenderAsync-höz:

  • Az összetevőpéldány első renderelésekor beállítódik true-ra.
  • Az inicializálási munka elvégzésének biztosítására használható, hogy az csak egyszer történjen meg.

AfterRender.razor:

@page "/after-render"
@inject ILogger<AfterRender> Logger 

<PageTitle>After Render</PageTitle>

<h1>After Render Example</h1>

<p>
    <button @onclick="HandleClick">Log information (and trigger a render)</button>
</p>

<p>Study logged messages in the console.</p>

@code {
    protected override void OnAfterRender(bool firstRender) =>
        Logger.LogInformation("firstRender = {FirstRender}", firstRender);

    private void HandleClick() => Logger.LogInformation("HandleClick called");
}
@page "/after-render"
@inject ILogger<AfterRender> Logger 

<PageTitle>After Render</PageTitle>

<h1>After Render Example</h1>

<p>
    <button @onclick="HandleClick">Log information (and trigger a render)</button>
</p>

<p>Study logged messages in the console.</p>

@code {
    protected override void OnAfterRender(bool firstRender) =>
        Logger.LogInformation("firstRender = {FirstRender}", firstRender);

    private void HandleClick() => Logger.LogInformation("HandleClick called");
}
@page "/after-render"
@inject ILogger<AfterRender> Logger

<PageTitle>After Render</PageTitle>

<h1>After Render Example</h1>

<p>
    <button @onclick="HandleClick">Log information (and trigger a render)</button>
</p>

<p>Study logged messages in the console.</p>

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        Logger.LogInformation("OnAfterRender: firstRender = {FirstRender}", firstRender);
    }

    private void HandleClick()
    {
        Logger.LogInformation("HandleClick called");
    }
}
@page "/after-render"
@inject ILogger<AfterRender> Logger 

<PageTitle>After Render</PageTitle>

<h1>After Render Example</h1>

<p>
    <button @onclick="HandleClick">Log information (and trigger a render)</button>
</p>

<p>Study logged messages in the console.</p>

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        Logger.LogInformation("OnAfterRender: firstRender = {FirstRender}", firstRender);
    }

    private void HandleClick()
    {
        Logger.LogInformation("HandleClick called");
    }
}
@page "/after-render"
@using Microsoft.Extensions.Logging
@inject ILogger<AfterRender> Logger 

<h1>After Render Example</h1>

<p>
    <button @onclick="HandleClick">Log information (and trigger a render)</button>
</p>

<p>Study logged messages in the console.</p>

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        Logger.LogInformation("OnAfterRender: firstRender = {FirstRender}", firstRender);
    }

    private void HandleClick()
    {
        Logger.LogInformation("HandleClick called");
    }
}
@page "/after-render"
@using Microsoft.Extensions.Logging
@inject ILogger<AfterRender> Logger

<h1>After Render Example</h1>

<p>
    <button @onclick="HandleClick">Log information (and trigger a render)</button>
</p>

<p>Study logged messages in the console.</p>

@code {
    protected override void OnAfterRender(bool firstRender)
    {
        Logger.LogInformation("OnAfterRender: firstRender = {FirstRender}", firstRender);
    }

    private void HandleClick()
    {
        Logger.LogInformation("HandleClick called");
    }
}

A AfterRender.razor minta a következő kimenetet hozza létre a konzolon a lap betöltésekor és a gomb kiválasztásakor:

OnAfterRender: firstRender = True
HandleClick called
OnAfterRender: firstRender = False

Az aszinkron munkát közvetlenül a renderelés után kell elvégezni a OnAfterRenderAsync életciklus-esemény során:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    ...
}

Ha az egyéni alaposztály egyéni inicializálási logikával van használva, hívja meg a OnAfterRenderAsync metódust az alaposztályon:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    ...

    await base.OnAfterRenderAsync(firstRender);
}

Nem szükséges meghívni ComponentBase.OnAfterRenderAsync, hacsak nem használ egyéni alaposztályt egyéni logikával. További információ: Alaposztály életciklus-módszerei szakasz.

Még ha Task-ből OnAfterRenderAsync-t is ad vissza, a keretrendszer nem ütemez további renderelési ciklust az összetevőhöz, miután a feladat befejeződik. Ennek célja, hogy elkerülje a végtelen renderelési ciklust. Ez eltér a többi életciklus-módszertől, amelyek egy újabb renderelési ciklust ütemeznek a visszaadott Task befejeződése után.

OnAfterRender és OnAfterRenderAsyncnem hívódnak meg az előrenderelési folyamat során a kiszolgálón. A metódusok akkor hívódnak meg, amikor az összetevő interaktívan jelenik meg az előrenderelés után. Amikor az alkalmazás előrenderel:

  1. Az összetevő a kiszolgálón hajt végre néhány statikus HTML-korrektúrát a HTTP-válaszban. Ebben a fázisban a OnAfterRender és a OnAfterRenderAsync nem lesznek meghívva.
  2. Amikor a Blazor szkript (blazor.{server|webassembly|web}.js) elindul a böngészőben, az összetevő interaktív renderelési módban újraindul. Az összetevő újraindítása után a és a meghívásra kerülnek, mert az alkalmazás már nincs az előrenderelési fázisban.

Ha az eseménykezelők a fejlesztői kódban vannak megadva, szüntesse meg őket a felszámoláskor. További információért lásd: ASP.NET Core Razor összetevők eltávolítása.

Alaposztály életciklus-módszerei

Blazoréletciklus-metódusainak felülírásakor nem szükséges meghívni az alaposztály életciklus-metódusait ComponentBaseesetén. Az összetevőnek azonban meg kell hívnia az alaposztály felülírt életciklus-metódusát a következő helyzetekben:

  • A ComponentBase.SetParametersAsyncfelülírásakor a await base.SetParametersAsync(parameters);-et általában azért hívjuk meg, mert az alaposztály metódusa más életciklus-metódusokat hív meg és összetett módon elindítja a renderelést. További információért lásd a A paraméterek beállítása (SetParametersAsync) szakaszt.
  • Ha az alaposztály-metódus olyan logikát tartalmaz, amelyet végre kell hajtani. A kódtár felhasználói általában alaposztály-életciklus-metódusokat neveznek az alaposztály öröklésekor, mivel a kódtár alaposztályai gyakran egyéni életciklus-logikával rendelkeznek. Ha az alkalmazás egy tár alaposztályát használja, útmutatásért tekintse meg a könyvtár dokumentációját.

Az alábbi példában base.OnInitialized(); hívjuk meg, hogy az alaposztály OnInitialized metódusa végrehajtásra kerüljön. A hívás nélkül a BlazorRocksBase2.OnInitialized nem kerül végrehajtásra.

BlazorRocks2.razor:

@page "/blazor-rocks-2"
@inherits BlazorRocksBase2
@inject ILogger<BlazorRocks2> Logger

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 2</h1>

<p>
    @BlazorRocksText
</p>

@code {
    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocks2 executed!");

        base.OnInitialized();
    }
}
@page "/blazor-rocks-2"
@inherits BlazorRocksBase2
@inject ILogger<BlazorRocks2> Logger

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 2</h1>

<p>
    @BlazorRocksText
</p>

@code {
    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocks2 executed!");

        base.OnInitialized();
    }
}
@page "/blazor-rocks-2"
@inherits BlazorRocksBase2
@inject ILogger<BlazorRocks2> Logger

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 2</h1>

<p>
    @BlazorRocksText
</p>

@code {
    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocks2 executed!");

        base.OnInitialized();
    }
}
@page "/blazor-rocks-2"
@inherits BlazorRocksBase2
@inject ILogger<BlazorRocks2> Logger

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 2</h1>

<p>
    @BlazorRocksText
</p>

@code {
    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocks2 executed!");

        base.OnInitialized();
    }
}
@page "/blazor-rocks-2"
@using Microsoft.Extensions.Logging
@inherits BlazorRocksBase2
@inject ILogger<BlazorRocks2> Logger

<h1>Blazor Rocks! Example 2</h1>

<p>
    @BlazorRocksText
</p>

@code {
    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocks2 executed!");

        base.OnInitialized();
    }
}
@page "/blazor-rocks-2"
@using Microsoft.Extensions.Logging
@inherits BlazorRocksBase2
@inject ILogger<BlazorRocks2> Logger

<h1>Blazor Rocks! Example 2</h1>

<p>
    @BlazorRocksText
</p>

@code {
    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocks2 executed!");

        base.OnInitialized();
    }
}

BlazorRocksBase2.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase2 : ComponentBase
{
    [Inject]
    private ILogger<BlazorRocksBase2> Logger { get; set; } = default!;

    public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";

    protected override void OnInitialized() =>
        Logger.LogInformation("Initialization code of BlazorRocksBase2 executed!");
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase2 : ComponentBase
{
    [Inject]
    private ILogger<BlazorRocksBase2> Logger { get; set; } = default!;

    public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";

    protected override void OnInitialized() =>
        Logger.LogInformation("Initialization code of BlazorRocksBase2 executed!");
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase2 : ComponentBase
{
    [Inject]
    private ILogger<BlazorRocksBase2> Logger { get; set; } = default!;

    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";

    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocksBase2 executed!");
    }
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase2 : ComponentBase
{
    [Inject]
    private ILogger<BlazorRocksBase2> Logger { get; set; } = default!;

    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";

    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocksBase2 executed!");
    }
}
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Logging;

namespace BlazorSample;

public class BlazorRocksBase2 : ComponentBase
{
    [Inject]
    private ILogger<BlazorRocksBase2> Logger { get; set; } = default!;

    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";

    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocksBase2 executed!");
    }
}
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Logging;

namespace BlazorSample;

public class BlazorRocksBase2 : ComponentBase
{
    [Inject]
    private ILogger<BlazorRocksBase2> Logger { get; set; } = default!;

    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";

    protected override void OnInitialized()
    {
        Logger.LogInformation("Initialization code of BlazorRocksBase2 executed!");
    }
}

Állapotváltozások (StateHasChanged)

StateHasChanged értesíti az összetevőt, hogy az állapota megváltozott. Adott esetben a StateHasChanged meghívása egy újrarenderelést sorba állít, amely akkor hajtódik végre, amikor az alkalmazás fő szála nincs terhelés alatt.

StateHasChanged EventCallback metódusok esetén a rendszer automatikusan meghívja. További információ az eseményvisszahívásokról: ASP.NET Core Blazor eseménykezelési.

További információkért az összetevők rendereléséről és a StateHasChangedhívásáról, beleértve azt is, hogy mikor kell meghívni a ComponentBase.InvokeAsync-et, lásd a ASP.NET Core Razor összetevő renderelésicímű témakört.

Hiányos aszinkron műveletek kezelése rendereléskor

Előfordulhat, hogy az életciklus-eseményekben végrehajtott aszinkron műveletek nem fejeződtek be az összetevő renderelése előtt. Előfordulhat, hogy az objektumok null vagy hiányosan töltik ki az adatokat az életciklus-metódus végrehajtása közben. Adja meg a renderelési logikát az objektumok inicializálásának ellenőrzéséhez. A helyőrző felhasználói felület elemeinek megjelenítése (például egy betöltési üzenet), amíg az objektumok a nullállapoton vannak.

Az alábbi Slow összetevőben a OnInitializedAsync felülírásra kerül, hogy aszinkron módon hajtsa végre a hosszú ideig futó feladatot. Amíg isLoadingtrue, egy betöltési üzenet jelenik meg a felhasználó számára. Miután a Task által visszaadott OnInitializedAsync befejeződött, az összetevőt újrarendereljük a frissített állapottal, és megjelenik a "Finished!" üzenet.

Slow.razor:

@page "/slow"

<h2>Slow Component</h2>

@if (isLoading)
{
    <div><em>Loading...</em></div>
}
else
{
    <div>Finished!</div>
}

@code {
    private bool isLoading = true;

    protected override async Task OnInitializedAsync()
    {
        await LoadDataAsync();
        isLoading = false;
    }

    private Task LoadDataAsync()
    {
        return Task.Delay(10000);
    }
}

Az előző összetevő egy isLoading változót használ a betöltési üzenet megjelenítéséhez. Hasonló megközelítést használunk egy olyan összetevőhöz, amely adatokat tölt be egy gyűjteménybe, és ellenőrzi, hogy a gyűjtemény null-e a betöltési üzenet bemutatásához. Az alábbi példa ellenőrzi a movies gyűjteményt, hogy null megjelenítse-e a betöltési üzenetet, vagy a filmek gyűjteményét jelenítse meg.

@if (movies == null)
{
    <p><em>Loading...</em></p>
}
else
{
    @* display movies *@
}

@code {
    private Movies[]? movies;

    protected override async Task OnInitializedAsync()
    {
        movies = await GetMovies();
    }
}

Az előrenderelés megvárja nyugalmi állapot, ami azt jelenti, hogy egy összetevő csak akkor renderelődik, ha a renderelési fa összes összetevője befejezte a renderelést. Ez azt jelenti, hogy egy betöltési üzenet nem jelenik meg, miközben a gyermekösszetevő OnInitializedAsync metódusa hosszú ideig futó feladatot hajt végre az előrenderelés során. Ennek a viselkedésnek a bemutatásához helyezze az előző Slow összetevőt egy tesztalkalmazás Home összetevőjére:

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<Slow />

Megjegyzés

Bár az ebben a szakaszban szereplő példák az OnInitializedAsync életciklus-módszert ismertetik, az előrendelés során végrehajtott egyéb életciklus-metódusok késleltethetik az összetevők végleges renderelését. Csak a OnAfterRender{Async} nincsen végrehajtva az előrendelés során, és immunis a nyugalmi idő miatti késésekre.

Az előrendelés során a Home összetevő csak akkor jelenik meg, ha a Slow összetevő megjelenik, ami tíz másodpercet vesz igénybe. A felhasználói felület ebben a tíz másodperces időszakban üres, és nincs betöltési üzenet. Az előrendelés után megjelenik a Home összetevő, és megjelenik a Slow összetevő betöltési üzenete. További tíz másodperc elteltével a Slow összetevő végül megjeleníti a kész üzenetet.

Ahogy az előző bemutató is szemlélteti, a nyugalom a prerenderelés során rossz felhasználói élményt eredményez. A felhasználói élmény javítása érdekében először implementálja a streamelő renderelést, hogy elkerülje az aszinkron feladat elvégzésére való várakozást az előrenderelés során.

Adja hozzá a [StreamRendering] attribútumot a Slow összetevőhöz (használja a [StreamRendering(true)] a .NET 8-ban):

@attribute [StreamRendering]

Ha a Home összetevő előrerendezést használ, a Slow összetevő gyorsan megjelenik a betöltési üzenettel. A Home összetevő nem vár tíz másodpercig, amíg a Slow összetevő befejezi a renderelést. Az előrendelés végén megjelenő kész üzenetet azonban a betöltési üzenet váltja fel, míg az összetevő végül renderel, ami újabb tíz másodperces késés. Ez azért fordul elő, mert a Slow összetevő kétszer renderel, és LoadDataAsync kétszer hajtja végre. Amikor egy összetevő hozzáfér az erőforrásokhoz, például a szolgáltatásokhoz és az adatbázisokhoz, a szolgáltatáshívások és az adatbázis-lekérdezések kettős végrehajtása nemkívánatos terhelést okoz az alkalmazás erőforrásain.

A betöltési üzenet kettős renderelésének és a szolgáltatás- és adatbázis-hívások újrafuttatásának kezeléséhez őrizze meg az előrerendezett állapotot PersistentComponentState az összetevő végleges rendereléséhez, ahogyan az Slow összetevő alábbi frissítéseiben látható:

@page "/slow"
@attribute [StreamRendering]

<h2>Slow Component</h2>

@if (Data is null)
{
    <div><em>Loading...</em></div>
}
else
{
    <div>@Data</div>
}

@code {
    [SupplyParameterFromPersistentComponentState]
    public string? Data { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Data ??= await LoadDataAsync();
    }

    private async Task<string> LoadDataAsync()
    {
        await Task.Delay(5000);
        return "Finished!";
    }
}
@page "/slow"
@attribute [StreamRendering]
@implements IDisposable
@inject PersistentComponentState ApplicationState

<h2>Slow Component</h2>

@if (data is null)
{
    <div><em>Loading...</em></div>
}
else
{
    <div>@data</div>
}

@code {
    private string? data;
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        if (!ApplicationState.TryTakeFromJson<string>(nameof(data), out var restored))
        {
            data = await LoadDataAsync();
        }
        else
        {
            data = restored!;
        }

        // Call at the end to avoid a potential race condition at app shutdown
        persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson(nameof(data), data);

        return Task.CompletedTask;
    }

    private async Task<string> LoadDataAsync()
    {
        await Task.Delay(5000);
        return "Finished!";
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

A streamelési renderelés és az állandó összetevő állapotának kombinálásával:

  • A szolgáltatások és adatbázisok csak egyetlen hívást igényelnek az összetevők inicializálásához.
  • Az összetevők gyorsan renderelik felhasználói felületeiket az üzenetek betöltésekor a hosszú ideig futó feladatok során a legjobb felhasználói élmény érdekében.

További információ:

:::moniker-end

A nyugalmi állapot a prerenderezés során rossz felhasználói élményt eredményez. A késés a .NET 8-hoz vagy újabbhoz szánt alkalmazásokban kezelhető egy adatfolyam-alapú renderelésnevű funkcióval, amelyet általában az összetevő állapotának megtartásával kombinálnak az előrendelés során, elkerülendő az aszinkron feladat befejezésére való várakozást. A .NET 8.0 előtti verziókban egy hosszú ideig futó háttérfeladat végrehajtása, amely az adatokat betölti a végleges renderelés után, csökkentheti a hosszú renderelési késedelmet a csendesség miatt.

Hibák kezelése

Az életciklus-metódus végrehajtása során előforduló hibák kezeléséről további információt ASP.NET Core Blazor-alkalmazások hibáinak kezelésecímű témakörben talál.

Állapotmegőrző újracsatlakozás az előrenderelés után

A szerveroldali előrendezés során egy összetevő kezdetben statikusan van előrendezve, mint az oldal része. Miután a böngésző létrehoz egy SignalR kapcsolatot a kiszolgálóval, az összetevő ismét és interaktív lesz. Ha az összetevő inicializálására szolgáló OnInitialized{Async} életciklus-módszer jelen van, a módszer kétszer kerül végrehajtásra .

  • Ha az összetevő statikusan előre van berendítve.
  • A kiszolgálókapcsolat létrejötte után.

Ez a felhasználói felületen megjelenő adatok észrevehető változásához vezethet, amikor az összetevőt végre rendereli. A viselkedés elkerülése érdekében adjon meg egy azonosítót, hogy a gyorsítótárba helyezze az állapotot az előzetes renderelés során, és kérje le az állapotot az előzetes renderelés után.

Az alábbi kód egy olyan WeatherForecastService-t mutat be, amely elkerüli az adatmegjelenítés előrenderelés miatti módosítását. A várt Delay (await Task.Delay(...)) rövid késleltetést szimulál, mielőtt adatokat ad vissza a GetForecastAsync metódusból.

Adjon hozzá IMemoryCache szolgáltatásokat a szolgáltatásgyűjteményhez AddMemoryCache, amely az alkalmazás Program fájljában található.

builder.Services.AddMemoryCache();

WeatherForecastService.cs:

using Microsoft.Extensions.Caching.Memory;

namespace BlazorSample;

public class WeatherForecastService(IMemoryCache memoryCache)
{
    private static readonly string[] summaries =
    [
        "Freezing", "Bracing", "Chilly", "Cool", "Mild",
        "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    ];

    public IMemoryCache MemoryCache { get; } = memoryCache;

    public Task<WeatherForecast[]?> GetForecastAsync(DateOnly startDate)
    {
        return MemoryCache.GetOrCreateAsync(startDate, async e =>
        {
            e.SetOptions(new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow =
                    TimeSpan.FromSeconds(30)
            });

            await Task.Delay(TimeSpan.FromSeconds(10));

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = summaries[Random.Shared.Next(summaries.Length)]
            }).ToArray();
        });
    }
}
using Microsoft.Extensions.Caching.Memory;

namespace BlazorSample;

public class WeatherForecastService(IMemoryCache memoryCache)
{
    private static readonly string[] summaries =
    [
        "Freezing", "Bracing", "Chilly", "Cool", "Mild",
        "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    ];

    public IMemoryCache MemoryCache { get; } = memoryCache;

    public Task<WeatherForecast[]?> GetForecastAsync(DateOnly startDate)
    {
        return MemoryCache.GetOrCreateAsync(startDate, async e =>
        {
            e.SetOptions(new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow =
                    TimeSpan.FromSeconds(30)
            });

            await Task.Delay(TimeSpan.FromSeconds(10));

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = summaries[Random.Shared.Next(summaries.Length)]
            }).ToArray();
        });
    }
}
using Microsoft.Extensions.Caching.Memory;

public class WeatherForecastService
{
    private static readonly string[] summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild",
        "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    public WeatherForecastService(IMemoryCache memoryCache)
    {
        MemoryCache = memoryCache;
    }

    public IMemoryCache MemoryCache { get; }

    public Task<WeatherForecast[]?> GetForecastAsync(DateTime startDate)
    {
        return MemoryCache.GetOrCreateAsync(startDate, async e =>
        {
            e.SetOptions(new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow =
                    TimeSpan.FromSeconds(30)
            });

            await Task.Delay(TimeSpan.FromSeconds(10));

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = summaries[Random.Shared.Next(summaries.Length)]
            }).ToArray();
        });
    }
}
using Microsoft.Extensions.Caching.Memory;

public class WeatherForecastService
{
    private static readonly string[] summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild",
        "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    public WeatherForecastService(IMemoryCache memoryCache)
    {
        MemoryCache = memoryCache;
    }

    public IMemoryCache MemoryCache { get; }

    public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
    {
        return MemoryCache.GetOrCreateAsync(startDate, async e =>
        {
            e.SetOptions(new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow =
                    TimeSpan.FromSeconds(30)
            });

            await Task.Delay(TimeSpan.FromSeconds(10));

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = summaries[Random.Shared.Next(summaries.Length)]
            }).ToArray();
        });
    }
}
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using BlazorSample.Shared;

public class WeatherForecastService
{
    private static readonly string[] summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild",
        "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    public WeatherForecastService(IMemoryCache memoryCache)
    {
        MemoryCache = memoryCache;
    }

    public IMemoryCache MemoryCache { get; }

    public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
    {
        return MemoryCache.GetOrCreateAsync(startDate, async e =>
        {
            e.SetOptions(new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow =
                    TimeSpan.FromSeconds(30)
            });

            var rng = new Random();

            await Task.Delay(TimeSpan.FromSeconds(10));

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = summaries[rng.Next(summaries.Length)]
            }).ToArray();
        });
    }
}
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using BlazorSample.Shared;

public class WeatherForecastService
{
    private static readonly string[] summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild",
        "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    public WeatherForecastService(IMemoryCache memoryCache)
    {
        MemoryCache = memoryCache;
    }

    public IMemoryCache MemoryCache { get; }

    public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
    {
        return MemoryCache.GetOrCreateAsync(startDate, async e =>
        {
            e.SetOptions(new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow =
                    TimeSpan.FromSeconds(30)
            });

            var rng = new Random();

            await Task.Delay(TimeSpan.FromSeconds(10));

            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = startDate.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = summaries[rng.Next(summaries.Length)]
            }).ToArray();
        });
    }
}

A RenderModekapcsolatos további információkért lásd a ASP.NET Core BlazorSignalR útmutatóját.

Ebben a szakaszban a Blazor Web App és az állapotalapú SignalRújracsatlakozás foglalkozik. Ha az állapotot az inicializálási kód futtatása közben szeretné megőrizni az előzetes megjelenítés során, tekintse meg a Prerender ASP.NET Core Razor összetevőket.

Bár ebben a szakaszban a tartalom a Blazor Server és az állapotalapú SignalRújracsatlakozásifoglalkozik, az üzemeltetett Blazor WebAssembly megoldások (WebAssemblyPrerendered) előrendelésének forgatókönyve hasonló feltételekkel és megközelítésekkel akadályozza meg a fejlesztői kód kétszeri végrehajtását. Ha az inicializálási kód végrehajtása során szeretné megőrizni az állapotot az előrendelés során, tekintse meg ASP.NET Core Razor összetevőinek integrálása MVC-vel vagy Razor Pages.

Előrerendezés JavaScript-interop használatával

Ez a szakasz azokra a kiszolgálóoldali alkalmazásokra vonatkozik, amelyek előre renderelik a Razor összetevőket. Az előrenderelést a Prerender ASP.NET Core Razor összetevőktárgyalják.

Megjegyzés

A belső navigációja a Blazor Web App esetén nem igényli új oldaltartalom kérését a szervertől. Ezért a belső lapkérelmek esetében nem történik meg az előrenderelés. Ha az alkalmazás az interaktív útválasztást alkalmazza, végezzen teljes oldal újratöltést az előrerenderelő viselkedést bemutató komponensek példáihoz. További információ: Prerender ASP.NET Core Razor-összetevők.

Ez a szakasz a kiszolgálóoldali alkalmazásokra és az Blazor WebAssembly alkalmazásokra vonatkozik, amelyek előrenderelik az Razor összetevőket. Az előrenderelés szerepel a ASP.NET Core Razor komponenseinek integrálásában az MVC-vel vagy a Razor oldalakkal.

Az előzetes renderelés során a JavaScript hívása (JS) nem lehetséges. Az alábbi példa bemutatja, hogyan használható JS interop egy összetevő inicializálási logikájának részeként az előrendeléssel kompatibilis módon.

A következő scrollElementIntoView függvény:

window.scrollElementIntoView = (element) => {
  element.scrollIntoView();
  return element.getBoundingClientRect().top;
}

Ha a IJSRuntime.InvokeAsync az összetevőkódban meghívja a JS függvényt, akkor a ElementReference csak a OnAfterRenderAsync alatt kerül felhasználásra, és nem egy korábbi életciklus-metódusban, mert az összetevő renderelése előtt nincs HTML DOM-elem.

StateHasChanged (referenciaforrás) az összetevő újrarenderelésének sorba állítására szolgál az JS interop hívásból kapott új állapottal (további információ: ASP.NET Core Razor komponens renderelése). A rendszer nem hoz létre végtelen hurkot, mert StateHasChanged csak akkor hívjuk meg, ha scrollPositionnull.

PrerenderedInterop.razor:

@page "/prerendered-interop"
@using Microsoft.AspNetCore.Components
@using Microsoft.JSInterop
@inject IJSRuntime JS

<PageTitle>Prerendered Interop</PageTitle>

<h1>Prerendered Interop Example</h1>

<div @ref="divElement" style="margin-top:2000px">
    Set value via JS interop call: <strong>@scrollPosition</strong>
</div>

@code {
    private ElementReference divElement;
    private double? scrollPosition;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && scrollPosition is null)
        {
            scrollPosition = await JS.InvokeAsync<double>(
                "scrollElementIntoView", divElement);

            StateHasChanged();
        }
    }
}
@page "/prerendered-interop"
@using Microsoft.AspNetCore.Components
@using Microsoft.JSInterop
@inject IJSRuntime JS

<h1>Prerendered Interop Example</h1>

<div @ref="divElement" style="margin-top:2000px">
    Set value via JS interop call: <strong>@scrollPosition</strong>
</div>

@code {
    private ElementReference divElement;
    private double? scrollPosition;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && scrollPosition is null)
        {
            scrollPosition = await JS.InvokeAsync<double>(
                "scrollElementIntoView", divElement);

            StateHasChanged();
        }
    }
}
@page "/prerendered-interop"
@using Microsoft.AspNetCore.Components
@using Microsoft.JSInterop
@inject IJSRuntime JS

<h1>Prerendered Interop Example</h1>

<div @ref="divElement" style="margin-top:2000px">
    Set value via JS interop call: <strong>@scrollPosition</strong>
</div>

@code {
    private ElementReference divElement;
    private double? scrollPosition;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && scrollPosition is null)
        {
            scrollPosition = await JS.InvokeAsync<double>(
                "scrollElementIntoView", divElement);

            StateHasChanged();
        }
    }
}
@page "/prerendered-interop"
@using Microsoft.AspNetCore.Components
@using Microsoft.JSInterop
@inject IJSRuntime JS

<h1>Prerendered Interop Example</h1>

<div @ref="divElement" style="margin-top:2000px">
    Set value via JS interop call: <strong>@scrollPosition</strong>
</div>

@code {
    private ElementReference divElement;
    private double? scrollPosition;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && scrollPosition is null)
        {
            scrollPosition = await JS.InvokeAsync<double>(
                "scrollElementIntoView", divElement);

            StateHasChanged();
        }
    }
}
@page "/prerendered-interop"
@using Microsoft.AspNetCore.Components
@using Microsoft.JSInterop
@inject IJSRuntime JS

<h1>Prerendered Interop Example</h1>

<div @ref="divElement" style="margin-top:2000px">
    Set value via JS interop call: <strong>@scrollPosition</strong>
</div>

@code {
    private ElementReference divElement;
    private double? scrollPosition;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender && scrollPosition is null)
        {
            scrollPosition = await JS.InvokeAsync<double>(
                "scrollElementIntoView", divElement);

            StateHasChanged();
        }
    }
}

Az előző példa egy globális függvénnyel terheli a klienst. A gyártási alkalmazások jobb módszeréért lásd: JavaScript-elkülönítés a JavaScript-modulokban.

Megszakítható háttérmunka

Az összetevők gyakran hosszú ideig futó háttérmunkát végeznek, például hálózati hívásokat kezdeményeznek (HttpClient) és együttműködnek az adatbázisokkal. Célszerű leállítani a háttérmunkát a rendszererőforrások több helyzetben történő megőrzéséhez. A háttérbeli aszinkron műveletek például nem állnak le automatikusan, amikor egy felhasználó ellép egy összetevőtől.

Egyéb okok, amelyek miatt a háttérmunkaelemek lemondást igényelhetnek, a következők lehetnek:

  • A háttérfeladat végrehajtása hibás bemeneti adatokkal vagy feldolgozási paraméterekkel kezdődött.
  • A háttérbeli munkaelemek végrehajtásának jelenlegi készletét új munkaelemkészletre kell cserélni.
  • A feladatok jelenleg történő végrehajtásának prioritását módosítani kell.
  • Az alkalmazást le kell állítani a kiszolgáló újbóli üzembe helyezéséhez.
  • A kiszolgáló erőforrásai korlátozottak lesznek, ami szükségessé teszi a háttérmunkaelemek átütemezését.

Megszakítható háttérmunkaminta implementálása egy összetevőben:

Az alábbi példában:

  • await Task.Delay(10000, cts.Token); hosszú ideig futó aszinkron háttérmunkát jelöl.
  • BackgroundResourceMethod egy hosszú ideig futó háttérmetódus, amely nem indul el, ha a Resource a metódus meghívása előtt el lett távolítva.

BackgroundWork.razor:

@page "/background-work"
@implements IDisposable
@inject ILogger<BackgroundWork> Logger

<PageTitle>Background Work</PageTitle>

<h1>Background Work Example</h1>

<p>
    <button @onclick="LongRunningWork">Trigger long running work</button>
    <button @onclick="Dispose">Trigger Disposal</button>
</p>
<p>Study logged messages in the console.</p>
<p>
    If you trigger disposal within 10 seconds of page load, the 
    <code>BackgroundResourceMethod</code> isn't executed.
</p>
<p>
    If disposal occurs after <code>BackgroundResourceMethod</code> is called but
    before action is taken on the resource, an <code>ObjectDisposedException</code>
    is thrown by <code>BackgroundResourceMethod</code>, and the resource isn't
    processed.
</p>

@code {
    private Resource resource = new();
    private CancellationTokenSource cts = new();
    private IList<string> messages = [];

    protected async Task LongRunningWork()
    {
        Logger.LogInformation("Long running work started");

        await Task.Delay(10000, cts.Token);

        cts.Token.ThrowIfCancellationRequested();
        resource.BackgroundResourceMethod(Logger);
    }

    public void Dispose()
    {
        Logger.LogInformation("Executing Dispose");

        if (!cts.IsCancellationRequested)
        {
            cts.Cancel();
        }
        
        cts?.Dispose();
        resource?.Dispose();
    }

    private class Resource : IDisposable
    {
        private bool disposed;

        public void BackgroundResourceMethod(ILogger<BackgroundWork> logger)
        {
            logger.LogInformation("BackgroundResourceMethod: Start method");

            if (disposed)
            {
                logger.LogInformation("BackgroundResourceMethod: Disposed");
                throw new ObjectDisposedException(nameof(Resource));
            }

            // Take action on the Resource

            logger.LogInformation("BackgroundResourceMethod: Action on Resource");
        }

        public void Dispose() => disposed = true;
    }
}
@page "/background-work"
@implements IDisposable
@inject ILogger<BackgroundWork> Logger

<PageTitle>Background Work</PageTitle>

<h1>Background Work Example</h1>

<p>
    <button @onclick="LongRunningWork">Trigger long running work</button>
    <button @onclick="Dispose">Trigger Disposal</button>
</p>
<p>Study logged messages in the console.</p>
<p>
    If you trigger disposal within 10 seconds of page load, the 
    <code>BackgroundResourceMethod</code> isn't executed.
</p>
<p>
    If disposal occurs after <code>BackgroundResourceMethod</code> is called but
    before action is taken on the resource, an <code>ObjectDisposedException</code>
    is thrown by <code>BackgroundResourceMethod</code>, and the resource isn't
    processed.
</p>

@code {
    private Resource resource = new();
    private CancellationTokenSource cts = new();
    private IList<string> messages = [];

    protected async Task LongRunningWork()
    {
        Logger.LogInformation("Long running work started");

        await Task.Delay(10000, cts.Token);

        cts.Token.ThrowIfCancellationRequested();
        resource.BackgroundResourceMethod(Logger);
    }

    public void Dispose()
    {
        Logger.LogInformation("Executing Dispose");

        if (!cts.IsCancellationRequested)
        {
            cts.Cancel();
        }
        
        cts?.Dispose();
        resource?.Dispose();
    }

    private class Resource : IDisposable
    {
        private bool disposed;

        public void BackgroundResourceMethod(ILogger<BackgroundWork> logger)
        {
            logger.LogInformation("BackgroundResourceMethod: Start method");

            if (disposed)
            {
                logger.LogInformation("BackgroundResourceMethod: Disposed");
                throw new ObjectDisposedException(nameof(Resource));
            }

            // Take action on the Resource

            logger.LogInformation("BackgroundResourceMethod: Action on Resource");
        }

        public void Dispose() => disposed = true;
    }
}
@page "/background-work"
@using System.Threading
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<BackgroundWork> Logger

<button @onclick="LongRunningWork">Trigger long running work</button>
<button @onclick="Dispose">Trigger Disposal</button>

@code {
    private Resource resource = new();
    private CancellationTokenSource cts = new();

    protected async Task LongRunningWork()
    {
        Logger.LogInformation("Long running work started");

        await Task.Delay(5000, cts.Token);

        cts.Token.ThrowIfCancellationRequested();
        resource.BackgroundResourceMethod(Logger);
    }

    public void Dispose()
    {
        Logger.LogInformation("Executing Dispose");
        cts.Cancel();
        cts.Dispose();
        resource?.Dispose();
    }

    private class Resource : IDisposable
    {
        private bool disposed;

        public void BackgroundResourceMethod(ILogger<BackgroundWork> logger)
        {
            logger.LogInformation("BackgroundResourceMethod: Start method");

            if (disposed)
            {
                logger.LogInformation("BackgroundResourceMethod: Disposed");
                throw new ObjectDisposedException(nameof(Resource));
            }

            // Take action on the Resource

            logger.LogInformation("BackgroundResourceMethod: Action on Resource");
        }

        public void Dispose()
        {
            disposed = true;
        }
    }
}
@page "/background-work"
@using System.Threading
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<BackgroundWork> Logger

<button @onclick="LongRunningWork">Trigger long running work</button>
<button @onclick="Dispose">Trigger Disposal</button>

@code {
    private Resource resource = new();
    private CancellationTokenSource cts = new();

    protected async Task LongRunningWork()
    {
        Logger.LogInformation("Long running work started");

        await Task.Delay(5000, cts.Token);

        cts.Token.ThrowIfCancellationRequested();
        resource.BackgroundResourceMethod(Logger);
    }

    public void Dispose()
    {
        Logger.LogInformation("Executing Dispose");
        cts.Cancel();
        cts.Dispose();
        resource?.Dispose();
    }

    private class Resource : IDisposable
    {
        private bool disposed;

        public void BackgroundResourceMethod(ILogger<BackgroundWork> logger)
        {
            logger.LogInformation("BackgroundResourceMethod: Start method");

            if (disposed)
            {
                logger.LogInformation("BackgroundResourceMethod: Disposed");
                throw new ObjectDisposedException(nameof(Resource));
            }

            // Take action on the Resource

            logger.LogInformation("BackgroundResourceMethod: Action on Resource");
        }

        public void Dispose()
        {
            disposed = true;
        }
    }
}
@page "/background-work"
@using System.Threading
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<BackgroundWork> Logger

<button @onclick="LongRunningWork">Trigger long running work</button>
<button @onclick="Dispose">Trigger Disposal</button>

@code {
    private Resource resource = new();
    private CancellationTokenSource cts = new();

    protected async Task LongRunningWork()
    {
        Logger.LogInformation("Long running work started");

        await Task.Delay(5000, cts.Token);

        cts.Token.ThrowIfCancellationRequested();
        resource.BackgroundResourceMethod(Logger);
    }

    public void Dispose()
    {
        Logger.LogInformation("Executing Dispose");
        cts.Cancel();
        cts.Dispose();
        resource?.Dispose();
    }

    private class Resource : IDisposable
    {
        private bool disposed;

        public void BackgroundResourceMethod(ILogger<BackgroundWork> logger)
        {
            logger.LogInformation("BackgroundResourceMethod: Start method");

            if (disposed)
            {
                logger.LogInformation("BackgroundResourceMethod: Disposed");
                throw new ObjectDisposedException(nameof(Resource));
            }

            // Take action on the Resource

            logger.LogInformation("BackgroundResourceMethod: Action on Resource");
        }

        public void Dispose()
        {
            disposed = true;
        }
    }
}
@page "/background-work"
@using System.Threading
@using Microsoft.Extensions.Logging
@implements IDisposable
@inject ILogger<BackgroundWork> Logger

<button @onclick="LongRunningWork">Trigger long running work</button>
<button @onclick="Dispose">Trigger Disposal</button>

@code {
    private Resource resource = new Resource();
    private CancellationTokenSource cts = new CancellationTokenSource();

    protected async Task LongRunningWork()
    {
        Logger.LogInformation("Long running work started");

        await Task.Delay(5000, cts.Token);

        cts.Token.ThrowIfCancellationRequested();
        resource.BackgroundResourceMethod(Logger);
    }

    public void Dispose()
    {
        Logger.LogInformation("Executing Dispose");
        cts.Cancel();
        cts.Dispose();
        resource?.Dispose();
    }

    private class Resource : IDisposable
    {
        private bool disposed;

        public void BackgroundResourceMethod(ILogger<BackgroundWork> logger)
        {
            logger.LogInformation("BackgroundResourceMethod: Start method");

            if (disposed)
            {
                logger.LogInformation("BackgroundResourceMethod: Disposed");
                throw new ObjectDisposedException(nameof(Resource));
            }

            // Take action on the Resource

            logger.LogInformation("BackgroundResourceMethod: Action on Resource");
        }

        public void Dispose()
        {
            disposed = true;
        }
    }
}

Ha egy betöltési jelzőt szeretne megjeleníteni a háttérmunka során, használja az alábbi megközelítést.

Hozzon létre egy betöltési jelző összetevőt egy Loading paraméterrel, amely megjelenítheti a gyermektartalmakat egy RenderFragment. Loading A paraméter esetében:

ContentLoading.razor:

@if (Loading)
{
    <progress id="loadingIndicator" aria-label="Content loading…"></progress>
}
else
{
    @ChildContent
}

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    [Parameter]
    public bool Loading { get; set; }
}

Ha CSS-stílusokat szeretne betölteni a mutatóhoz, adja hozzá a stílusokat a <head> tartalmához az HeadContent összetevővel. További információ: Vezérlőfej tartalma ASP.NET Core-alkalmazásokbanBlazor.

@if (Loading)
{
    <!-- OPTIONAL ...
    <HeadContent>
        <style>
            ...
        </style>
    </HeadContent>
    -->
    <progress id="loadingIndicator" aria-label="Content loading…"></progress>
}
else
{
    @ChildContent
}

...

Burkolja be a komponens Razor jelölését a ContentLoading komponenssel, és adjon át egy értéket egy C# mezőből a Loading paraméternek, amikor az összetevő végzi az inicializálási műveleteit.

<ContentLoading Loading="@loading">
    ...
</ContentLoading>

@code {
    private bool loading = true;
    ...

    protected override async Task OnInitializedAsync()
    {
        await LongRunningWork().ContinueWith(_ => loading = false);
    }

    ...
}

Blazor Server újracsatlakozási események

A cikkben tárgyalt összetevők életciklus-eseményei külön működnek kiszolgálóoldali újracsatlakozási eseménykezelőktől. Ha az ügyfélhez való SignalR kapcsolat megszakad, csak a felhasználói felület frissítései szakadnak meg. A felhasználói felület frissítései a kapcsolat újbóli létrehozásakor újraindulnak. További információ az áramköri kezelő eseményeiről és konfigurációjáról: lásd az ASP.NET Core BlazorSignalR útmutatót.

További erőforrások

Razor összetevő életciklusán kívüli kivételeket kezel