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 8 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 8 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 8 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 ComponentBase yaşam döngüsü olay işleme ile Blazortümleştirmek için başvuru kaynağına 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

Bir bileşen işlenmeden önce yaşam döngüsü olaylarında gerçekleştirilen zaman uyumsuz eylemler tamamlanmayabilir. Daha fazla bilgi için bu makalenin devamında İşlemede tamamlanmamış zaman uyumsuz eylemleri işleme bölümüne 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.

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 SetParametersAsync bileşen için bileşen parametre değerleri kümesini iç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[CascadingParameter] özniteliğiyle [Parameter] 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 SetParametersAsyncsırasında temel sınıf yöntemini (await base.SetParametersAsync(parameters);) ç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ğına başvurmanız ComponentBase 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 IAsyncDisposable ile IDisposable 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 Param değerini value atar. olmadığında value null, 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 TryGetValue/{param?}almak 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 SignalRyeniden bağlanmaya odaklanırBlazor Web App. Ö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 yeniden bağlanmaya odaklansa Blazor Server 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. Hazırlama sırasında başlatma kodunun yürütülmesi sırasında durumu korumak için bkz . Prerender ve ASP.NET Core Razor bileşenlerini 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 OnInitializedAsync 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ış işlemeyi kullanın. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşenini işleme.

Parametreler ayarlandıktan sonra (OnParametersSet{Async})

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

  • bileşen veya OnInitializedAsynciçinde OnInitialized 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 OnAfterRenderAsyncparametresiOnAfterRender:

  • 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 OnAfterRenderAsyncdöndürseniz Task 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 OnAfterRenderAsync sunucudaki ö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 OnAfterRender OnAfterRenderAsync ç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 bkz. ASP.NET Temel Razor bileşen işleme.ComponentBase.InvokeAsync

İşleme sırasında tamamlanmamış zaman uyumsuz eylemleri işleme

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 bileşende, OnInitializedAsync film derecelendirme verilerinimovies () zaman uyumsuz olarak sağlamak için geçersiz kılınmış. olduğunda movies null, kullanıcıya bir yükleme iletisi görüntülenir. Task tarafından döndürülen OnInitializedAsync tamamlandıktan sonra bileşen güncelleştirilmiş durumla yeniden oluşturulur.

<h1>Sci-Fi Movie Ratings</h1>

@if (movies == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <ul>
        @foreach (var movie in movies)
        {
            <li>@movie.Title &mdash; @movie.Rating</li>
        }
    </ul>
}

@code {
    private Movies[]? movies;

    protected override async Task OnInitializedAsync()
    {
        movies = await GetMovieRatings(DateTime.Now);
    }
}

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 Program dosyasındaki hizmet koleksiyonunda ile hizmetlerini AddMemoryCache ekleyinIMemoryCache:

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 SignalRyeniden bağlanmaya odaklanırBlazor Web App. Ö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 yeniden bağlanmaya odaklansa Blazor Server 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. Hazırlama sırasında başlatma kodunun yürütülmesi sırasında durumu korumak için bkz . Prerender ve ASP.NET Core Razor bileşenlerini 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 ele alınmıştır.Razor

Not

'de Blazor Web Appetkileşimli yönlendirme için iç 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 Razor oluşturan barındırılan Blazor WebAssembly uygulamalar için geçerlidir. Prerendering, Prerender kapsamındadır ve ASP.NET Core Razor bileşenlerini tümleştirir.

Ö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 JS bileşen kodunda çağırdığı durumlardaIJSRuntime.InvokeAsync, 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 IAsyncDisposableuygularsaIDisposable, 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 OnInitalizedAsync bir zaman uyumsuz Task ç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 IAsyncDisposable uygulaması IDisposable 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ı JS önlemek için .NET'ten veya kaynağından JS oluşturulanlarıJSObjectReference IJSObjectReference/IJSInProcessObjectReference/atı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 JS oluşturulan DotNetObjectReference 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ışma bölümüne bakın.Blazor

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 StateHasChanged ComponentBase.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 Disposeönce öğesini null 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ı Dispose/DisposeAsyncyaptıktan sonra atılan nesnelere atamanız null gerekmez. Nadir atama null örnekleri şunlardır:

  • Nesnenin türü kötü uygulandıysa ve öğesine yapılan yineleme çağrılarını DisposeDisposeAsync/tolere etmiyorsa, öğesine yapılan diğer çağrıları/DisposeAsyncDispose düzgün bir şekilde atlamak için elden çıkarmadan sonra atlayın.null
  • 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 StateHasChanged DisposeAsync çağrısı Dispose 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 IAsyncDisposable ile IDisposable 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 DisposeAsync yöntemlerini uygulama Dispose konusunda bunu izleyen konular.

İ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(5000, 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