Aracılığıyla paylaş


ASP.NET Core Razor bileşen yaşam döngüsü

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 9 sürümüne bakın.

Uyarı

ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 9 sürümüne bakın.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

Geçerli sürüm için bu makalenin .NET 9 sürümüne bakın.

Bu makalede, ASP.NET Temel Razor bileşen yaşam döngüsü ve yaşam döngüsü olaylarının nasıl kullanılacağı açıklanmaktadır.

Yaşam döngüsü olayları

Bileşen, Razor bileşen yaşam döngüsü olaylarını Razor bir dizi zaman uyumlu ve zaman uyumsuz yaşam döngüsü yönteminde işler. Bileşen başlatma ve işleme sırasında bileşenlerde ek işlemler gerçekleştirmek için yaşam döngüsü yöntemleri geçersiz kılınabilir.

Bu makale, karmaşık çerçeve mantığını netleştirmek için bileşen yaşam döngüsü olay işlemeyi basitleştirir ve yıllar içinde yapılan her değişikliği kapsamaz. Özel olay işlemeyi Blazor erişmeniz gerekebilir. Başvuru kaynağındaki kod açıklamaları, bu makalede veya API belgelerinde görünmeyen yaşam döngüsü olay işleme hakkında ek açıklamalar içerir.

Not

.NET başvuru kaynağına yönelik belge bağlantıları genellikle deponun varsayılan dalını yükler ve bu dal .NET'in sonraki sürümü için geçerli geliştirmeyi temsil eder. Belirli bir sürümün etiketini seçmek için Dalları veya etiketleri değiştir açılan listesini kullanın. Daha fazla bilgi için bkz. ASP.NET Core kaynak kodunun sürüm etiketini seçme (dotnet/AspNetCore.Docs #26205).

Aşağıdaki basitleştirilmiş diyagramlarda bileşen yaşam döngüsü olay işleme gösterilmektedir Razor . Yaşam döngüsü olaylarıyla ilişkili C# yöntemleri, bu makalenin aşağıdaki bölümlerindeki örneklerle tanımlanır.

Bileşen yaşam döngüsü olayları:

  1. Bileşen bir istekte ilk kez işleniyorsa:
    • Bileşenin örneğini oluşturun.
    • Özellik ekleme işlemi gerçekleştirin.
    • OnInitialized{Async} çağrısı yapın. Tamamlanmamış Task bir döndürülürse, Task öğesini bekler ve ardından bileşen yeniden oluşturulur. Zaman uyumlu yöntem, zaman uyumsuz yöntemden önce çağrılır.
  2. OnParametersSet{Async} çağrısı yapın. Tamamlanmamış Task bir döndürülürse, Task öğesini bekler ve ardından bileşen yeniden oluşturulur. Zaman uyumlu yöntem, zaman uyumsuz yöntemden önce çağrılır.
  3. Tüm zaman uyumlu işler ve tamamlamalar Taskiçin işleyin.

Not

Yaşam döngüsü olaylarında gerçekleştirilen zaman uyumsuz eylemler, bileşenin işlenmesini veya verilerin görüntülenmesini geciktirebilir. Daha fazla bilgi için, bu makalenin ilerleyen bölümlerinde bulunan Tamamlanmamış zaman uyumsuz eylemleri işleme konusuna bakın.

Hangi alt bileşenlerin mevcut olduğunu belirleyen işleme olduğundan, bir üst bileşen alt bileşenlerden önce işlenir. Zaman uyumlu üst bileşen başlatma kullanılırsa, önce üst başlatmanın tamamlanması garanti edilir. Zaman uyumsuz üst bileşen başlatma kullanılırsa, çalışan başlatma koduna bağlı olduğundan üst ve alt bileşen başlatmanın tamamlanma sırası belirlenemez.

içindeki bir Razor bileşenin bileşen yaşam döngüsü olayları Blazor

DOM olay işleme:

  1. Olay işleyicisi çalıştırılır.
  2. Tamamlanmamış Task bir döndürülürse, Task öğesini bekler ve ardından bileşen yeniden oluşturulur.
  3. Tüm zaman uyumlu işler ve tamamlamalar Taskiçin işleyin.

DOM olay işleme

Yaşam Render döngüsü:

  1. Aşağıdaki koşulların her ikisi de karşılandığında bileşen üzerinde daha fazla işleme işlemi yapmaktan kaçının:
  2. İşleme ağacı farkını (fark) oluşturun ve bileşeni işleyin.
  3. DOM'un güncelleştirilecek olmasını bekle.
  4. OnAfterRender{Async} çağrısı yapın. Zaman uyumlu yöntem, zaman uyumsuz yöntemden önce çağrılır.

İşleme yaşam döngüsü

Geliştirici, bir rerender ile sonuçlanır StateHasChanged çağrısında bulunur. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşenini işleme.

İşleme öncesi sessizlik durumu

Sunucu tarafı uygulamalarında, ön kayıtsessiz moda geçmesini bekler. Bu, işleme ağacındaki tüm bileşenlerin işlenmesi tamamlanana kadar bileşenin işlenmediği anlamına gelir. Sessiz moda geçme, bir bileşen başlatma ve diğer yaşam döngüsü yöntemleri sırasında uzun süre çalışan görevler gerçekleştirdiğinde işlemede belirgin gecikmelere yol açarak kötü bir kullanıcı deneyimine yol açabilir. Daha fazla bilgi için bu makalenin devamında yer alan Render sırasında tamamlanmamış zaman uyumsuz eylemleri işleme bölümüne bakın.

Parametreler ayarlandığında (SetParametersAsync)

SetParametersAsync , bileşenin üst öğesi tarafından işleme ağacında veya yol parametrelerinden sağlanan parametreleri ayarlar.

Yöntemin ParameterView parametresi, her çağrılışında bileşen için bileşen parametreSetParametersAsynciçerir. Geliştirici kodu, yöntemini geçersiz kılarak SetParametersAsync doğrudan 'nin parametreleriyle ParameterViewetkileşimde bulunabilir.

varsayılan uygulamasıSetParametersAsync, içinde karşılık gelen bir değere sahip olan veya[Parameter][CascadingParameter] her özelliğin ParameterViewdeğerini ayarlar. içinde ParameterView karşılık gelen bir değere sahip olmayan parametreler değişmeden bırakılır.

Genellikle, kodunuz geçersiz kılma await base.SetParametersAsync(parameters);sırasında temel sınıf yöntemini (SetParametersAsync) çağırmalıdır. Gelişmiş senaryolarda geliştirici kodu, temel sınıf yöntemini çağırmayarak gelen parametrelerin değerlerini herhangi bir şekilde yorumlayabilir. Örneğin, gelen parametreleri sınıfın özelliklerine atama gereksinimi yoktur. Ancak, temel sınıf yöntemini çağırmadan kodunuzu yapılandırırken başvuru kaynağınaComponentBase gerekir çünkü diğer yaşam döngüsü yöntemlerini çağırır ve karmaşık bir şekilde işlemeyi tetikler.

Not

.NET başvuru kaynağına yönelik belge bağlantıları genellikle deponun varsayılan dalını yükler ve bu dal .NET'in sonraki sürümü için geçerli geliştirmeyi temsil eder. Belirli bir sürümün etiketini seçmek için Dalları veya etiketleri değiştir açılan listesini kullanın. Daha fazla bilgi için bkz. ASP.NET Core kaynak kodunun sürüm etiketini seçme (dotnet/AspNetCore.Docs #26205).

Gelen parametrelerin başlatma ve işleme mantığına ComponentBase.SetParametersAsync güvenmek ancak işlememek istiyorsanız, temel sınıf yöntemine boş ParameterView bir geçirme seçeneğiniz vardır:

await base.SetParametersAsync(ParameterView.Empty);

Geliştirici kodunda olay işleyicileri sağlanıyorsa, bunları elden çıkarıldığında çıkarın. Daha fazla bilgi için ve IDisposable ile IAsyncDisposable bileşen elden çıkarma bölümüne bakın.

Aşağıdaki örnekte, ParameterView.TryGetValue bir yol parametresinin Param ayrıştırılması başarılı olursa parametresinin value değerini Param atar. olmadığında valuenull, değer bileşen tarafından görüntülenir.

Yol parametresi eşleştirme büyük/küçük harfe duyarsız olsa da, TryGetValue yalnızca yol şablonundaki büyük/küçük harfe duyarlı parametre adlarını eşleştirir. Aşağıdaki örnek, değerini değil ile /{Param?}TryGetValuealmak için yol şablonunda öğesinin kullanılmasını /{param?} gerektirir. Bu senaryoda kullanılıyorsa /{param?} , TryGetValue döndürür false ve message iki dizeye de message ayarlanmadı.

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

Bileşen başlatma (OnInitialized{Async})

OnInitialized ve OnInitializedAsync yalnızca bileşen örneğinin tüm ömrü boyunca bir bileşeni başlatmak için kullanılır. Parametre değerleri ve parametre değeri değişiklikleri, bu yöntemlerde gerçekleştirilen başlatmayı etkilememelidir. Örneğin, statik seçenekleri bileşenin ömrü boyunca değişmeyen ve parametre değerlerine bağımlı olmayan bir açılan listeye yükleme işlemi bu yaşam döngüsü yöntemlerinden birinde gerçekleştirilir. Parametre değerleri veya parametre değerlerindeki değişiklikler bileşen durumunu etkiliyorsa, bunun yerine kullanın OnParametersSet{Async} .

Bu yöntemler, içinde ilk parametrelerini aldıktan sonra bileşen başlatıldığında çağrılır SetParametersAsync. Zaman uyumlu yöntem, zaman uyumsuz yöntemden önce çağrılır.

Zaman uyumlu üst bileşen başlatma kullanılırsa, alt bileşen başlatmadan önce üst başlatmanın tamamlanması garanti edilir. Zaman uyumsuz üst bileşen başlatma kullanılırsa, çalışan başlatma koduna bağlı olduğundan üst ve alt bileşen başlatmanın tamamlanma sırası belirlenemez.

Zaman uyumlu bir işlem için öğesini geçersiz kılın OnInitialized:

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

Zaman uyumsuz bir işlem gerçekleştirmek için geçersiz kılın OnInitializedAsync ve işlecini await kullanın:

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

Özel bir temel sınıf özel başlatma mantığıyla kullanılıyorsa, temel sınıfı çağırınOnInitializedAsync:

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

    await base.OnInitializedAsync();
}

Özel bir temel sınıf özel mantıkla kullanılmadığı sürece çağrı ComponentBase.OnInitializedAsync yapılması gerekmez. Daha fazla bilgi için Temel sınıf yaşam döngüsü yöntemleri bölümüne bakın.

Blazorsunucudaki içeriklerini önceden oluşturan uygulamalar iki kez arar OnInitializedAsync:

  • Bileşen başlangıçta sayfanın bir parçası olarak statik olarak işlendiğinde.
  • Tarayıcı bileşeni işlerken ikinci kez.

'de OnInitializedAsync geliştirici kodunun ön kayıt sırasında iki kez çalışmasını önlemek için, Ön kayıttan sonra durum bilgisi olan yeniden bağlanma bölümüne bakın. Bölümdeki içerik, s ve durum bilgisi olan Blazor Web AppSignalR odaklanır. Ön kayıt sırasında başlatma kodunun yürütülmesi sırasında durumu korumak için bkz . Prerender ASP.NET Core Razor bileşenleri.

'de OnInitializedAsync geliştirici kodunun ön kayıt sırasında iki kez çalışmasını önlemek için, Ön kayıttan sonra durum bilgisi olan yeniden bağlanma bölümüne bakın. Bölümdeki içerik ve durum bilgisi olanSignalR odaklansa da, barındırılan Blazor WebAssembly çözümlerde (WebAssemblyPrerendered) ön kayıt senaryosu, geliştirici kodunun iki kez yürütülmesini önlemeye yönelik benzer koşullar ve yaklaşımlar içerir. Başlatma kodunun ön kullanım sırasında yürütülmesi sırasında durumu korumak için bkz . ASP.NET Core Razor bileşenlerini MVC veya Razor Pages ile tümleştirme.

Bir Blazor uygulama önceden çalıştırılırken JavaScript'e çağırma (JS birlikte çalışma) gibi bazı eylemler mümkün değildir. Bileşenlerin önceden girildiğinde farklı şekilde işlenmesi gerekebilir. Daha fazla bilgi için JavaScript birlikte çalışma ile ön giriş yapma bölümüne bakın.

Geliştirici kodunda olay işleyicileri sağlanıyorsa, bunları elden çıkarıldığında çıkarın. Daha fazla bilgi için Bileşen atma ve IDisposableIAsyncDisposable atma bölümüne bakın.

'de uzun süre çalışan zaman uyumsuz görevleri tam olarak işlemek üzere gerçekleştiren bileşenler için kullanıcı deneyimini geliştirmek için statik sunucu tarafı işleme (statik SSR) veya ön işlem ile akışOnInitializedAsync. Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın:

Parametreler ayarlandıktan sonra (OnParametersSet{Async})

OnParametersSet veya OnParametersSetAsync çağrılır:

  • bileşen veya OnInitializediçinde OnInitializedAsync başlatıldıktan sonra.

  • Üst bileşen yeniden başlatıldığında ve sağladığında:

    • En az bir parametre değiştiğinde bilinen veya ilkel sabit türler.
    • Karmaşık türemiş parametreler. Çerçeve, karmaşık türdeki bir parametrenin değerlerinin dahili olarak sessize alınıp alınmadığını bilemez, bu nedenle çerçeve her zaman bir veya daha fazla karmaşık türe sahip parametre mevcut olduğunda parametre kümesini değiştirilmiş olarak değerlendirir.

    İşleme kuralları hakkında daha fazla bilgi için bkz . ASP.NET Core Razor bileşeni işleme.

Zaman uyumlu yöntem, zaman uyumsuz yöntemden önce çağrılır.

Parametre değerleri değişmemiş olsa bile yöntemler çağrılabilir. Bu davranış, geliştiricilerin bu parametrelere bağımlı verileri veya durumu yeniden başlatmadan önce parametre değerlerinin gerçekten değişip değişmediğini denetlemek için yöntemler içinde ek mantık uygulama gereksiniminin altını çizer.

Aşağıdaki örnek bileşen için, url'deki bileşenin sayfasına gidin:

  • tarafından alınan bir başlangıç tarihiyle StartDate: /on-parameters-set/2021-03-19
  • Başlangıç tarihi olmadan, burada StartDate geçerli yerel saatin bir değeri atanır: /on-parameters-set

Not

Bileşen yolunda, bir parametreyi yol kısıtlamasıDateTimeile kısıtlamak datetime ve parametreyi isteğe bağlı hale getirmek mümkün değildir. Bu nedenle, aşağıdaki OnParamsSet bileşen URL'de sağlanan bir tarih kesimi ile ve olmadan yönlendirmeyi işlemek için iki @page yönerge kullanır.

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

Parametreleri ve özellik değerlerini uygularken zaman uyumsuz çalışma yaşam döngüsü olayı sırasında OnParametersSetAsync gerçekleşmelidir:

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

Özel bir temel sınıf özel başlatma mantığıyla kullanılıyorsa, temel sınıfı çağırınOnParametersSetAsync:

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

    await base.OnParametersSetAsync();
}

Özel bir temel sınıf özel mantıkla kullanılmadığı sürece çağrı ComponentBase.OnParametersSetAsync yapılması gerekmez. Daha fazla bilgi için Temel sınıf yaşam döngüsü yöntemleri bölümüne bakın.

Geliştirici kodunda olay işleyicileri sağlanıyorsa, bunları elden çıkarıldığında çıkarın. Daha fazla bilgi için Bileşen atma ve IDisposableIAsyncDisposable atma bölümüne bakın.

Yol parametreleri ve kısıtlamaları hakkında daha fazla bilgi için bkz . ASP.NET Çekirdek Blazor yönlendirme ve gezinti.

Bazı senaryolarda performansı geliştirmek için el ile uygulama SetParametersAsync örneği için bkz . ASP.NET Temel Blazor performans en iyi yöntemleri.

Bileşen işlendikten sonra (OnAfterRender{Async})

OnAfterRender ve OnAfterRenderAsync bir bileşen etkileşimli olarak işlendikten ve kullanıcı arabirimi güncelleştirmeyi tamamladıktan sonra (örneğin, tarayıcı DOM'sine öğeler eklendikten sonra) çağrılır. Öğe ve bileşen başvuruları bu noktada doldurulur. İşlenen dom öğeleriyle etkileşim kuran birlikte çalışma çağrıları gibi JS işlenen içerikle ek başlatma adımları gerçekleştirmek için bu aşamayı kullanın. Zaman uyumlu yöntem, zaman uyumsuz yöntemden önce çağrılır.

Bu işlemler bir canlı tarayıcı DOM'sine bağlı olmadığından ve DOM güncelleştirilmeden önce zaten tamamlandığından, bu yöntemler sunucuda ön kayıt veya statik sunucu tarafı işleme (statik SSR) sırasında çağrılamaz.

için OnAfterRenderAsync, sonsuz bir işleme döngüsünden kaçınmak için döndürülen Task herhangi bir öğe tamamlandıktan sonra bileşen otomatik olarak yeniden oluşturulmaz.

OnAfterRender ve OnAfterRenderAsync bir bileşenin işlenmesi tamamlandıktan sonra çağrılır. Öğe ve bileşen başvuruları bu noktada doldurulur. İşlenen dom öğeleriyle etkileşim kuran birlikte çalışma çağrıları gibi JS işlenen içerikle ek başlatma adımları gerçekleştirmek için bu aşamayı kullanın. Zaman uyumlu yöntem, zaman uyumsuz yöntemden önce çağrılır.

Bu yöntemler, canlı tarayıcı DOM'sine eklenmediğinden ve DOM güncelleştirilmeden önce zaten tamamlandığından, ön kayıt sırasında çağrılamaz.

için OnAfterRenderAsync, sonsuz bir işleme döngüsünden kaçınmak için döndürülen Task herhangi bir öğe tamamlandıktan sonra bileşen otomatik olarak yeniden oluşturulmaz.

firstRender ve OnAfterRenderparametresiOnAfterRenderAsync:

  • Bileşen örneğinin ilk işlenme zamanına ayarlanır true .
  • Başlatma işinin yalnızca bir kez gerçekleştirildiğinden emin olmak için kullanılabilir.

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

Örnek, AfterRender.razor sayfa yüklendiğinde ve düğme seçildiğinde konsola aşağıdaki çıkışı oluşturur:

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

İşlemeden hemen sonra zaman uyumsuz çalışma yaşam döngüsü olayı sırasında OnAfterRenderAsync gerçekleşmelidir:

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

Özel bir temel sınıf özel başlatma mantığıyla kullanılıyorsa, temel sınıfı çağırınOnAfterRenderAsync:

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

    await base.OnAfterRenderAsync(firstRender);
}

Özel bir temel sınıf özel mantıkla kullanılmadığı sürece çağrı ComponentBase.OnAfterRenderAsync yapılması gerekmez. Daha fazla bilgi için Temel sınıf yaşam döngüsü yöntemleri bölümüne bakın.

'den Taskdöndürseniz OnAfterRenderAsync bile, görev tamamlandıktan sonra çerçeve bileşeniniz için başka bir işleme döngüsü zamanlamaz. Bu, sonsuz bir işleme döngüsünden kaçınmaktır. Bu, döndürülen Task bir işlem tamamlandıktan sonra daha fazla işleme döngüsü zamanlayan diğer yaşam döngüsü yöntemlerinden farklıdır.

OnAfterRender ve OnAfterRenderAsyncsunucudaki ön kayıt işlemi sırasında çağrılmaz. Bileşenler, ön kayıt sonrasında etkileşimli olarak işlendiğinde çağrılır. Uygulama yöneticileri:

  1. Bileşen, HTTP yanıtında bazı statik HTML işaretlemeleri oluşturmak için sunucuda yürütülür. Bu aşamada OnAfterRenderOnAfterRenderAsync çağrılmaz.
  2. Blazor Betik (blazor.{server|webassembly|web}.js) tarayıcıda başlatıldığında, bileşen etkileşimli işleme modunda yeniden başlatılır. Bir bileşen yeniden başlatıldıktan OnAfterRender sonra ve OnAfterRenderAsync uygulama artık ön kayıt aşamasında olmadığından çağrılır.

Geliştirici kodunda olay işleyicileri sağlanıyorsa, bunları elden çıkarıldığında çıkarın. Daha fazla bilgi için Bileşen atma ve IDisposableIAsyncDisposable atma bölümüne bakın.

Temel sınıf yaşam döngüsü yöntemleri

'nin yaşam döngüsü yöntemleri geçersiz kılınırken Blazoriçin temel sınıf yaşam döngüsü yöntemlerini ComponentBaseçağırmak gerekmez. Ancak, bir bileşen aşağıdaki durumlarda geçersiz kılınmış bir temel sınıf yaşam döngüsü yöntemini çağırmalıdır:

  • geçersiz kılınırken ComponentBase.SetParametersAsyncawait base.SetParametersAsync(parameters); genellikle temel sınıf yöntemi diğer yaşam döngüsü yöntemlerini çağırdığından ve karmaşık bir şekilde işlemeyi tetiklediğinden çağrılır. Daha fazla bilgi için Parametreler ayarlandığında (SetParametersAsync) bölümüne bakın.
  • Temel sınıf yöntemi yürütülmesi gereken mantık içeriyorsa. Kitaplık temel sınıfları genellikle yürütülecek özel yaşam döngüsü mantığına sahip olduğundan, kitaplık tüketicileri genellikle bir temel sınıfı devralırken temel sınıf yaşam döngüsü yöntemlerini çağırır. Uygulama bir kitaplıktan temel sınıf kullanıyorsa, rehberlik için kitaplığın belgelerine bakın.

Aşağıdaki örnekte, base.OnInitialized(); temel sınıfın OnInitialized yönteminin yürütülmesini sağlamak için çağrılır. Çağrı BlazorRocksBase2.OnInitialized olmadan yürütülemez.

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

Durum değişiklikleri (StateHasChanged)

StateHasChanged bileşene durumunun değiştiğini bildirir. Uygun olduğunda, çağrı, StateHasChanged uygulamanın ana iş parçacığı boş olduğunda oluşan bir rerender'ı sıralar.

StateHasChanged , yöntemler için EventCallback otomatik olarak çağrılır. Olay geri çağırmaları hakkında daha fazla bilgi için bkz . ASP.NET Core Blazor olay işleme.

Bileşen işleme ve ile ne zaman çağrılacakları StateHasChangedhakkında daha fazla bilgi için bkzRazor.

İşleme sırasında tamamlanmamış asenkron eylemleri yönetme

Bileşen işlenmeden önce yaşam döngüsü olaylarında gerçekleştirilen zaman uyumsuz eylemler tamamlanmamış olabilir. Yaşam döngüsü yöntemi yürütülürken nesneler verilerle doldurulabilir veya tamamlanmamış olabilir null . Nesnelerin başlatıldığını onaylamak için işleme mantığı sağlayın. Yer tutucu kullanıcı arabirimi öğelerini (örneğin, bir yükleme iletisi) işlerken nesneler olur null.

Aşağıdaki Slow bileşeninde, uzun süre çalışan bir görevi zaman uyumsuz olarak yürütmek için OnInitializedAsync geçersiz kılınmış olur. isLoading truesüresince kullanıcıya bir yükleme mesajı gösterilir. OnInitializedAsync tarafından döndürülen Task tamamlandıktan sonra, bileşen güncelleştirilmiş duruma döndürülür ve "Finished!" iletisi gösterilir.

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

Önceki bileşen, yükleme iletisini görüntülemek için bir isLoading değişkeni kullanır. Benzer bir yaklaşım, bir koleksiyona veri yükleyen ve koleksiyonun yükleme iletisini sunmak için null olup olmadığını denetleen bir bileşen için kullanılır. Aşağıdaki örnek, yükleme iletisini görüntülemek veya film koleksiyonunu görüntülemek için movies koleksiyonunu null denetler:

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

@code {
    private Movies[]? movies;

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

Prerendering, durgunluk durumubekler. Bu, işleme ağacındaki tüm bileşenlerin işlenmesi tamamlanana kadar herhangi bir bileşenin işlenmemesi gerektiği anlamına gelir. Bu, bir alt bileşenin OnInitializedAsync yöntemi ön işleme sırasında uzun süre çalışan bir görevi yürütürken, yükleme iletisinin görüntülenmediği anlamına gelir. Bu davranışı göstermek için önceki Slow bileşenini bir test uygulamasının Home bileşenine yerleştirin:

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<SlowComponent />

Not

Bu bölümdeki örneklerde OnInitializedAsync yaşam döngüsü yöntemi ele alınsa da, ön kullanım sırasında yürütülen diğer yaşam döngüsü yöntemleri bir bileşenin son işlenmesini geciktirebilir. Yalnızca OnAfterRender{Async}, prerendering sırasında çalıştırılmaz ve sakinlikten kaynaklanan gecikmelerden etkilenmez.

Önceden işleme sırasında, Home bileşeni, Slow bileşeni işlenene kadar işlenmez ve bu işlem on saniye sürer. Bu on saniyelik süre boyunca kullanıcı arabirimi boş olur ve yükleme iletisi yoktur. Ön kayıt sonrasında Home bileşeni işlenir ve Slow bileşenin yükleme iletisi görüntülenir. On saniye daha sonra, Slow bileşeni son olarak tamamlanmış iletiyi görüntüler.

Önceki gösterimde de gösterildiği gibi, ön-işleme sırasında durgunluk zayıf bir kullanıcı deneyimi sağlar. Kullanıcı deneyimini geliştirmek için, ön kayıt sırasında zaman uyumsuz görevin tamamlanmasını beklememek için akış işleme uygulayarak başlayın.

bileşenine özniteliğini ekleyin (.NET 8'de kullanın):

@attribute [StreamRendering]

Home bileşeni önceden render edilirken, Slow bileşeni yükleme mesajıyla hızla render edilir. Home bileşeni, Slow bileşeninin işlenmesinin bitmesi için on saniye beklemez. Ancak, ön kayıt sonunda görüntülenen tamamlanmış ileti, bileşen son olarak işlenirken yükleme iletisiyle değiştirilir ve bu da on saniyelik bir gecikmedir. Bunun nedeni, Slow bileşeninin iki kez işlenmesi ve LoadDataAsync iki kez yürütülmesidir. Bir bileşen hizmetler ve veritabanları gibi kaynaklara eriştiğinde, hizmet çağrılarının ve veritabanı sorgularının iki kez yürütülmesi uygulamanın kaynakları üzerinde istenmeyen yük oluşturur.

Yükleme iletisinin çift işlenmesini ve hizmet ile veritabanı çağrılarının yeniden yürütülmesini ele almak için, bileşenin son işlemesi sırasında kullanılmak üzere PersistentComponentState ile önceden işlenmiş durumu kalıcı hale getirin. Bu durum, Slow bileşenine yönelik aşağıdaki güncellemelerde görülebilir.

@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()
    {
        persistingSubscription =
            ApplicationState.RegisterOnPersisting(PersistData);

        if (!ApplicationState.TryTakeFromJson<string>("data", out var restored))
        {
            data = await LoadDataAsync();
        }
        else
        {
            data = restored!;
        }
    }

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

        return Task.CompletedTask;
    }

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

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

Akış işlemeyi kalıcı bileşen durumuyla birleştirerek:

  • Hizmetler ve veritabanları, bileşen başlatma için yalnızca tek bir çağrı gerektirir.
  • Bileşenler, en iyi kullanıcı deneyimi için uzun süren görevler sırasında yükleme iletileri göstererek UI'larını hızla işler.

Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın:

Ön kullanım sırasında sessiz moda geçme, kötü bir kullanıcı deneyimine neden olur. Gecikme, .NET 8 veya sonraki sürümleri hedefleyen uygulamalarda akış işlemeadlı bir özellikle ele alınabilir ve zaman uyumsuz görevin tamamlanmasını beklememek için genellikle ön kayıt sırasında kalıcı bileşen durumuyla birleştirilir. .NET'in 8.0'dan önceki sürümlerinde, son işlemeden sonra verileri yükleyen uzun süre çalışan bir arka plan görevi yürütmek sessiz moda alma nedeniyle uzun süren işleme gecikmesini giderebilir.

Hataları işleme

Yaşam döngüsü yöntemi yürütme sırasındaki hataları işleme hakkında bilgi için bkz . ASP.NET Core Blazor uygulamalarında hataları işleme.

Prerendering sonrasında durum bilgisi olan yeniden bağlantı

Sunucuda önceden oturum açılırken, başlangıçta bir bileşen sayfanın bir parçası olarak statik olarak işlenir. Tarayıcı sunucuyla yeniden bağlantı SignalR kurduktan sonra bileşen yeniden işlenir ve etkileşimli olur. OnInitialized{Async} Bileşeni başlatmak için yaşam döngüsü yöntemi varsa, yöntem iki kez yürütülür:

  • Bileşen statik olarak önceden girildiğinde.
  • Sunucu bağlantısı kurulduktan sonra.

Bu, bileşen sonunda işlendiğinde kullanıcı arabiriminde görüntülenen verilerde belirgin bir değişikliğe neden olabilir. Bu davranışı önlemek için, ön kayıt sırasında durumu önbelleğe almak ve ön kayıttan sonra durumu almak için bir tanımlayıcı geçirin.

Aşağıdaki kod, ön kayıt nedeniyle veri görüntüsündeki değişikliği önleyen bir WeatherForecastService gösterir. Beklenen Delay (await Task.Delay(...)) yönteminden veri döndürmeden önce kısa bir gecikmenin benzetimini gerçekleştirmektedir GetForecastAsync .

Uygulamasının IMemoryCache dosyasındaki hizmet koleksiyonunda ile hizmetlerini AddMemoryCache ekleyinProgram:

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

hakkında RenderModedaha fazla bilgi için bkz . ASP.NET Temel BlazorSignalR kılavuzu.

Bu bölümdeki içerik, s ve durum bilgisi olan Blazor Web AppSignalR odaklanır. Ön kayıt sırasında başlatma kodunun yürütülmesi sırasında durumu korumak için bkz . Prerender ASP.NET Core Razor bileşenleri.

Bu bölümdeki içerik, durum bilgisi olanSignalR odaklansa da, barındırılan Blazor WebAssembly çözümlerde (WebAssemblyPrerendered) önceden giriş senaryosu, geliştirici kodunun iki kez yürütülmesini önlemek için benzer koşullar ve yaklaşımlar içerir. Başlatma kodunun ön kullanım sırasında yürütülmesi sırasında durumu korumak için bkz . ASP.NET Core Razor bileşenlerini MVC veya Razor Pages ile tümleştirme.

JavaScript birlikte çalışma ile ön kayıt

Bu bölüm, bileşenleri önceden Razor oluşturan sunucu tarafı uygulamalar için geçerlidir. Prerendering, Prerender ASP.NET Core bileşenlerinde Razor.

Not

'de etkileşimli yönlendirmeBlazor Web Appiç gezinti, sunucudan yeni sayfa içeriği istemeyi içermez. Bu nedenle, iç sayfa istekleri için ön kayıt gerçekleşmez. Uygulama etkileşimli yönlendirmeyi benimsediyse, önyükleme davranışını gösteren bileşen örnekleri için tam sayfa yeniden yükleme gerçekleştirin. Daha fazla bilgi için bkz . Prerender ASP.NET Core Razor bileşenleri.

Bu bölüm, sunucu tarafı uygulamalar ve bileşenleri önceden Blazor WebAssembly oluşturan barındırılan Razor uygulamalar için geçerlidir. Prerendering, ASP.NET Core Razor bileşenlerini MVC veya Razor Pages ile tümleştirme bölümünde ele alınmıştır.

Ön kayıt sırasında JavaScript'e (JS) çağrı yapılamaz. Aşağıdaki örnekte, bir bileşenin başlatma mantığının bir parçası olarak birlikte çalışma özelliğinin, ön kayıtla uyumlu bir şekilde nasıl kullanılacağı JS gösterilmektedir.

Aşağıdaki scrollElementIntoView işlev:

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

İşlevi IJSRuntime.InvokeAsync bileşen kodunda çağırdığı durumlardaJS, bileşen işleninceye ElementReference kadar HTML DOM öğesi olmadığından yalnızca içinde kullanılır OnAfterRenderAsync ve önceki yaşam döngüsü yöntemlerinde kullanılmaz.

StateHasChanged (başvuru kaynağı) birlikte çalışma çağrısından JS alınan yeni durumla bileşeni yeniden sıralamak için çağrılır (daha fazla bilgi için bkz . ASP.NET Core Razor bileşeni işleme). Sonsuz döngü oluşturulmaz çünkü StateHasChanged yalnızca olduğunda scrollPosition çağrılır null.

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

Yukarıdaki örnek, istemciyi genel bir işlevle kirletir. Üretim uygulamalarında daha iyi bir yaklaşım için bkz . JavaScript modüllerinde JavaScript yalıtımı.

ve ile IDisposable bileşen bertarafı IAsyncDisposable

Bir bileşen veya IDisposableuygularsaIAsyncDisposable, bileşen kullanıcı arabiriminden kaldırıldığında çerçeve kaynak atılması için çağrıda bulunur. Bu yöntemlerin yürütülürken tam zamanlamasına güvenmeyin. Örneğin, IAsyncDisposable içinde beklenen Task bir zaman uyumsuz OnInitalizedAsync çağrılmadan veya tamamlandıktan önce veya sonra tetiklenebilir. Ayrıca, nesne atma kodu başlatma sırasında oluşturulan nesnelerin veya diğer yaşam döngüsü yöntemlerinin mevcut olduğunu varsaymamalıdır.

Bileşenlerin aynı anda ve IDisposable uygulaması IAsyncDisposable gerekmez. Her ikisi de uygulanırsa, çerçeve yalnızca zaman uyumsuz aşırı yüklemeyi yürütür.

Geliştirici kodu, uygulamaların tamamlanmasının IAsyncDisposable uzun sürmediğinden emin olmalıdır.

JavaScript birlikte çalışma nesnesi başvurularının elden çıkarılması

JavaScript (JS) birlikte çalışma makalelerinin tüm örnekleri tipik nesne atma desenlerini gösterir:

  • .NET'ten çağırırkenJS, ASP.NET Core'daki Blazor.NET yöntemlerinden JavaScript işlevlerini çağırma bölümünde açıklandığı gibi, bellek sızıntısını IJSObjectReference önlemek için .NET'ten veya kaynağından / oluşturulanlarıIJSInProcessObjectReference/JSObjectReferenceJSJSatın.

  • .NET JSçağrısı yaparken, ASP.NET Core'daki BlazorJavaScript işlevlerinden .NET yöntemlerini çağırma bölümünde açıklandığı gibi , .NET belleğinin sızmasını önlemek için .NET'ten veya kaynağından DotNetObjectReference oluşturulan JS bir öğesini atın.

JS birlikte çalışma nesne başvuruları, birlikte çalışma çağrısının JS yanında başvuruyu oluşturan bir tanımlayıcı tarafından anahtarlanan bir eşleme olarak uygulanır. Nesne atma işlemi .NET'ten veya JS taraftan başlatıldığında, Blazor girdiyi eşlemeden kaldırır ve nesneye başka güçlü bir başvuru olmadığı sürece nesne çöp olarak toplanabilir.

.NET yönetilen belleğinin sızmasını önlemek için en azından .NET tarafında oluşturulan nesneleri her zaman atın.

Bileşen atma sırasında DOM temizleme görevleri

Daha fazla bilgi için bkz. ASP.NET Core Blazor JavaScript birlikte çalışabilirliği (JSbirlikte çalışma).

Bağlantı hattının JSDisconnectedException bağlantısının kesildiğinde yönergeler için bkz . ASP.NET Core Blazor JavaScript birlikte çalışabilirliği (JS birlikte çalışma). Genel JavaScript birlikte çalışma hatası işleme yönergeleri için ASP.NET Core uygulamalarında hataları işleme bölümündeki JavaScript birlikte çalışmaBlazor.

Eşzamanlı IDisposable

Zaman uyumlu atma görevleri için kullanın IDisposable.Dispose.

Aşağıdaki bileşen:

  • IDisposable yönergesi @implementsRazor ile uygular.
  • objuygulayan bir tür olan öğesini atılırIDisposable.
  • Bir yaşam döngüsü yönteminde oluşturulduğundan obj (gösterilmediğinden) null denetim gerçekleştirilir.
@implements IDisposable

...

@code {
    ...

    public void Dispose()
    {
        obj?.Dispose();
    }
}

Tek bir nesnenin atılması gerekiyorsa, çağrıldığında Dispose nesnenin atılması için bir lambda kullanılabilir. Aşağıdaki örnek, ASP.NET Core Razor bileşeni işleme makalesinde gösterilir ve bir öğesinin atılması için lambda ifadesinin Timerkullanımını gösterir.

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

Not

Yukarıdaki örnekte, geri çağırma'nın StateHasChangedComponentBase.InvokeAsync eşitleme bağlamının Blazordışında çağrıldığından çağrısı çağrısı ile sarmalanır. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşenini işleme.

Nesnesi gibi OnInitialized{Async}bir yaşam döngüsü yönteminde oluşturulduysa çağrısından nullönce öğesini Dispose denetleyin.

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

Daha fazla bilgi için bkz.

Eşzamansız IAsyncDisposable

Zaman uyumsuz elden çıkarma görevleri için kullanın IAsyncDisposable.DisposeAsync.

Aşağıdaki bileşen:

  • IAsyncDisposable yönergesi @implementsRazor ile uygular.
  • objuygulayan yönetilmeyen bir tür olan öğesini atılırIAsyncDisposable.
  • Bir yaşam döngüsü yönteminde oluşturulduğundan obj (gösterilmediğinden) null denetim gerçekleştirilir.
@implements IAsyncDisposable

...

@code {
    ...

    public async ValueTask DisposeAsync()
    {
        if (obj is not null)
        {
            await obj.DisposeAsync();
        }
    }
}

Daha fazla bilgi için bkz.

null Atılan nesnelere atama

Genellikle, çağrısı nullDispose/yaptıktan sonra atılan nesnelere atamanız DisposeAsync gerekmez. Nadir atama null örnekleri şunlardır:

  • Nesnenin türü kötü uygulandıysa ve öğesine yapılan yineleme çağrılarını Dispose/DisposeAsynctolere etmiyorsa, öğesine yapılan diğer çağrılarınullDispose/ düzgün bir şekilde atlamak için elden çıkarmadan sonra atlayın.DisposeAsync
  • Uzun süreli bir işlem, atılan bir nesneye başvuruyu tutmaya devam ederse, atama null işlemi, atık toplayıcının uzun ömürlü bir işlem başvuruyu tutmasına rağmen nesneyi serbest bırakmasını sağlar.

Bunlar olağan dışı senaryolardır. Doğru uygulanan ve normal davranan nesneler için, atılan nesnelere atamanın null bir anlamı yoktur. Bir nesnenin atanması nullgereken nadir durumlarda nedenini belgelemenizi ve atama nullgereksinimini önleyen bir çözüm aramanızı öneririz.

StateHasChanged

Not

ve StateHasChangedDispose çağrısı DisposeAsync desteklenmez. StateHasChanged işleyiciyi yok etme işleminin bir parçası olarak çağrılabilir, bu nedenle bu noktada kullanıcı arabirimi güncelleştirmeleri istenmesi desteklenmez.

Olay işleyicileri

.NET olaylarından olay işleyicilerinin aboneliğini her zaman kaldırın. Aşağıdaki Blazor form örneklerinde yöntemindeki bir olay işleyicisinin aboneliğinin nasıl kaldırılacağı gösterilmektedir Dispose :

  • Özel alan ve lambda yaklaşımı

    @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;
        }
    }
    
  • Özel yöntem yaklaşımı

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

Daha fazla bilgi için ve IDisposable ile IAsyncDisposable bileşen elden çıkarma bölümüne bakın.

Bileşen ve formlar hakkında EditForm daha fazla bilgi için bkz. ASP.NET Çekirdek Blazor formlarına genel bakış ve Formlar düğümündeki diğer form makaleleri.

Anonim işlevler, yöntemler ve ifadeler

Anonim işlevler, yöntemler veya ifadeler kullanıldığında, temsilcilerin uygulanması IDisposable ve aboneliğinin iptal edilmesi gerekmez. Ancak, bir temsilcinin aboneliğinin kaldırılamaması, olayı ortaya çıkartan nesnenin temsilciyi kaydeden bileşenin ömründen uzun süre geçtiği bir sorundur. Bu durum oluştuğunda, kayıtlı temsilci özgün nesneyi canlı tuttuğundan bellek sızıntısı oluşur. Bu nedenle, yalnızca olay temsilcisinin hızlı bir şekilde attığını bildiğinizde aşağıdaki yaklaşımları kullanın. Elden çıkarma gerektiren nesnelerin kullanım ömrü hakkında şüpheler olduğunda, bir temsilci yöntemine abone olun ve önceki örneklerde gösterildiği gibi temsilciyi düzgün bir şekilde atın.

  • Anonim lambda yöntemi yaklaşımı (açık elden çıkarma gerekli değildir):

    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);
    }
    
  • Anonim lambda ifade yaklaşımı (açık elden çıkarma gerekli değildir):

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

    Anonim lambda ifadeleri içeren önceki kodun tam örneği ASP.NET Core Blazor formları doğrulama makalesinde görünür.

Daha fazla bilgi için bkz. Yönetilmeyen kaynakları temizleme ve ve Dispose yöntemlerini uygulama DisposeAsync konusunda bunu izleyen konular.

Birlikte çalışma sırasında JS atma

Bağlantı hattı kaybının birlikte çalışma çağrılarını önlediği JSDisconnectedException ve işlenmeyen BlazorSignalRbir özel durumla sonuçlandığı olası durumlarda yakalamaJS.

Daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın:

İptal edilebilir arka plan çalışması

Bileşenler genellikle ağ çağrıları (HttpClient) yapma ve veritabanlarıyla etkileşim kurma gibi uzun süre çalışan arka plan işleri gerçekleştirir. Sistem kaynaklarını çeşitli durumlarda korumak için arka plan çalışmasını durdurmak tercih edilir. Örneğin, kullanıcı bir bileşenden uzaklaştığında arka plan zaman uyumsuz işlemleri otomatik olarak durmaz.

Arka plan iş öğelerinin iptal gerektirmesi için diğer nedenler şunlardır:

  • Hatalı giriş verileri veya işleme parametreleriyle bir yürütme arka plan görevi başlatıldı.
  • Geçerli yürütme arka plan iş öğeleri kümesi yeni bir iş öğeleri kümesiyle değiştirilmelidir.
  • Şu anda yürütülmekte olan görevlerin önceliği değiştirilmelidir.
  • Sunucu yeniden dağıtımı için uygulamanın kapatılması gerekir.
  • Sunucu kaynakları sınırlı hale gelir ve arka plan iş öğelerinin yeniden zamanlanması gerekir.

Bir bileşende iptal edilebilir bir arka plan çalışma deseni uygulamak için:

Aşağıdaki örnekte:

  • await Task.Delay(10000, cts.Token); uzun süre çalışan zaman uyumsuz arka plan çalışmasını temsil eder.
  • BackgroundResourceMethod , yöntemi çağrılmadan önce atılırsa Resource başlatılmaması gereken uzun süre çalışan bir arka plan yöntemini temsil eder.

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

Blazor Server yeniden bağlanma olayları

Bu makalede ele alınan bileşen yaşam döngüsü olayları, sunucu tarafı yeniden bağlantı olay işleyicilerinden ayrı olarak çalışır. İstemci bağlantısı SignalR kesildiğinde, yalnızca kullanıcı arabirimi güncelleştirmeleri kesilir. Bağlantı yeniden kurulduğunda kullanıcı arabirimi güncelleştirmeleri sürdürülür. Bağlantı hattı işleyicisi olayları ve yapılandırması hakkında daha fazla bilgi için bkz . ASP.NET Core BlazorSignalR kılavuzu.

Ek kaynaklar

Bir bileşenin Razor yaşam döngüsü dışında yakalanan özel durumları işleme