Aracılığıyla paylaş


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

Notlar

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 10 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.

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ı

Razor bileşeni, Razor bileşen yaşam döngüsü olaylarını 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'nin yaşam döngüsü olayı işlemesiyle entegre etmek için 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.

Notlar

.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 için etiketi seçmek üzere Dalları veya etiketleri değiştir açılır listesini kullanabilirsiniz. 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 gösteriliyorsa:
    • Bileşenin örneğini oluşturun.
    • Özellik ekleme işlemi gerçekleştirin.
    • OnInitialized{Async} çağrısı yapın. Tamamlanmamış bir Task döndürülürse, Task beklenir 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ış bir Task döndürülürse, Task beklenir ve ardından bileşen yeniden oluşturulur. Zaman uyumlu yöntem, zaman uyumsuz yöntemden önce çağrılır.
  3. Tüm eşzamanlı işleri ve tamamlamaları yürütün Task.

Notlar

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.

Bir üst bileşen, alt bileşenlerin hangilerinin mevcut olduğunu belirleyen işleme olduğu için, alt bileşenlerden önce işlenir. Eşzamanlı üst bileşen başlatması kullanıldığında, üst bileşen başlatmasının önce tamamlanması garanti edilir. Eşzamansız üst bileşen başlatma kullanıldığında, başlatma kodunun çalışmasına bağlı olarak üst ve alt bileşen başlatmanın tamamlanma sırası belirlenemez.

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

DOM olay işleme:

  1. Olay işleyicisi çalıştırılır.
  2. Tamamlanmamış bir Task döndürülürse, Task beklenir ve ardından bileşen yeniden oluşturulur.
  3. Tüm eşzamanlı işleri ve tamamlamaları yürütün Task.

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. Render ağacı farkını (difference) oluşturun ve bileşeni renderlayın.
  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ü

StateHasChanged çağrılarına yapılan geliştirici çağrıları, bir yeniden çizimle sonuçlanır. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşenini işleme.

İşleme öncesi sessizlik durumu

Sunucu tarafı Blazor uygulamalarında, ön işleme tüm bileşenler sessiz hale gelene kadar bekler, yani işleme ağacındaki tüm bileşenlerin işlenmesi tamamlanana kadar bir bileşen işlenmez. 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 ilerleyen bölümlerinde bulunan Tamamlanmamış zaman uyumsuz eylemleri işleme konusuna 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şenin bileşeni için parametre değerleri setini içerir. SetParametersAsync yöntemini geçersiz kılarak geliştirici kodu, ParameterView'nin parametreleriyle doğrudan etkileşimde bulunabilir.

Varsayılan uygulama , içinde karşılık gelen bir değere sahip olan her özelliğin değerini veya özniteliğiyle ayarlar. içinde ParameterView karşılık gelen bir değere sahip olmayan parametreler değişmeden bırakılır.

Genellikle, kodunuz await base.SetParametersAsync(parameters);'ı geçersiz kılarken 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, kodunuzu yapılandırırken temel sınıf yöntemini çağırmadan ComponentBase başvuru kaynağına başvurmanız gerekir çünkü diğer yaşam döngüsü yöntemlerini çağırır ve karmaşık bir şekilde rendering'i (işlemeyi) tetikler.

Notlar

.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 için etiketi seçmek üzere Dalları veya etiketleri değiştir açılır listesini kullanabilirsiniz. Daha fazla bilgi için bkz. ASP.NET Core kaynak kodunun sürüm etiketini seçme (dotnet/AspNetCore.Docs #26205).

ComponentBase.SetParametersAsync'nin başlatma ve render etme mantığına güvenmek, ama gelen parametreleri işlememek istiyorsanız, temel sınıf yöntemine boş bir ParameterView geçirme seçeneğiniz vardır.

await base.SetParametersAsync(ParameterView.Empty);

Geliştirici kodunda olay işleyicileri sağlanıyorsa, elden çıkarılma sırasında bağlantılarını kesin. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşen imhası.

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

Yol parametresi eşleştirme büyük/küçük harfe duyarsızdır, ancak TryGetValue yalnızca yol şablonundaki büyük/küçük harfe duyarlı parametre adlarını eşleştirir. Aşağıdaki örnek, /{Param?} değerini TryGetValue yerine almak için /{param?} öğesinin yol şablonunda kullanılmasını gerektirir. Eğer /{param?} bu senaryoda kullanılırsa, TryGetValuefalse döndürür ve message herhangi bir message dizisine ayarlanmaz.

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

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

Eşzamanlı ebeveyn bileşen başlatılması kullanılırsa, çocuk bileşen başlatılmadan önce ebeveyn bileşeninin başlatılmasının tamamlanması garanti edilir. Eşzamansız üst bileşen başlatma kullanıldığında, başlatma kodunun çalışmasına bağlı olarak üst ve alt bileşen başlatmanın tamamlanma sırası belirlenemez.

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

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, OnInitializedAsync'yı geçersiz kılın ve await operatörünü 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 üzerinde OnInitializedAsync fonksiyonunu çağırın.

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.

Bir bileşen, muhtemelen eksik olabilecek OnInitializedAsync öğesini beklerken Task işleme sürecine uygun bir durumda olduğundan emin olmalıdır. Yöntem tamamlanmamış bir Taskdöndürürse, yöntemin zaman uyumlu bir şekilde tamamlanan bölümü, bileşeni işleme için geçerli bir durumda bırakmalıdır. Daha fazla bilgi için, ASP.NET Core Blazor eşitleme bağlamı ve ASP.NET Core Razor bileşen elden çıkarmasıhakkındaki giriş açıklamalarına bakın.

Blazor sunucudaki içeriklerini önceden oluşturan uygulamalar OnInitializedAsynciki kez çağırır:

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

Geliştirici kodunun OnInitializedAsync içinde ön işleme sırasında iki kez çalışmasını önlemek için, Ön işlemden sonra durum bilgisi olan yeniden bağlanma bölümüne bakın. Bölümdeki içerik, Blazor Web App'ler ve durum bilgisi olan SignalRyeniden bağlanma üzerine odaklanır. Ön kayıt sırasında başlatma kodunun yürütülmesi sırasında durumu korumak için bkz. ASP.NET Core Blazor önceden yüklenmiş durum kalıcılığı.

Geliştirici kodunun OnInitializedAsync içinde ön işleme sırasında iki kez çalışmasını önlemek için, Ön işlemden sonra durum bilgisi olan yeniden bağlanma bölümüne bakın. Bölümdeki içerik, Blazor Server ve durumlu SignalRyeniden bağlantıya odaklansa da, barındırılan Blazor WebAssembly çözümlerde (WebAssemblyPrerendered) ön işleme 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 işleme 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 render edilirken, JavaScript'e geçiş yapmak (JS birlikte çalışma) gibi bazı eylemler mümkün değildir. Bileşenler ön işleme sırasında farklı şekilde görüntülenebilir. Daha fazla bilgi için JavaScript birlikte çalışmasıyla önceden oluşturma bölümüne bakın.

Geliştirici kodunda olay işleyicileri sağlanıyorsa, elden çıkarılma sırasında bağlantılarını kesin. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşen imhası.

Akışlı işlemeyi, OnInitializedAsync içinde tam olarak işlenmesi için uzun süreli zaman uyumsuz görevler gerçekleştiren bileşenler için kullanıcı deneyimini geliştirmek amacıyla statik sunucu tarafı işlemeyi veya ön işlemeyi kullanın. 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:

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

  • Üst bileşen yeniden render yapı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 değişip değişmediğini bilemez, bu nedenle çerçeve her zaman bir veya daha fazla karmaşık türde parametre mevcut olduğunda parametre kümesini değiştirilmiş olarak kabul eder.

    İş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:

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

Notlar

Bileşen rotasında, bir DateTime parametresini datetime yol kısıtlaması ile sınırlamak ve parametreyi isteğe bağlı yapmak 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, OnParametersSetAsync yaşam döngüsü olayı sırasında gerçekleştirilmelidir.

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

Özel bir temel sınıf özel başlatma mantığıyla kullanılıyorsa, temel sınıf üzerinde OnParametersSetAsync fonksiyonunu çağırın.

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.

Bir bileşen, muhtemelen eksik olabilecek OnParametersSetAsync öğesini beklerken Task işleme sürecine uygun bir durumda olduğundan emin olmalıdır. Yöntem tamamlanmamış bir Taskdöndürürse, yöntemin zaman uyumlu bir şekilde tamamlanan bölümü, bileşeni işleme için geçerli bir durumda bırakmalıdır. Daha fazla bilgi için, ASP.NET Core Blazor eşitleme bağlamı ve ASP.NET Core Razor bileşen elden çıkarmasıhakkındaki giriş açıklamalarına bakın.

Geliştirici kodunda olay işleyicileri sağlanıyorsa, elden çıkarılma sırasında bağlantılarını kesin. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşen imhası.

Bir atılabilir bileşen CancellationTokenkullanmıyorsa, OnParametersSet ve OnParametersSetAsync bileşenin atılmış olup olmadığını denetlemelidir. OnParametersSetAsync eksik bir Taskdöndürürse, bileşen, yöntemin senkronize olarak tamamlanan kısmının bileşeni işleme hazır ve geçerli bir durumda bıraktığını sağlamalıdır. Daha fazla bilgi için, ASP.NET Core Blazor eşitleme bağlamı ve ASP.NET Core Razor bileşen elden çıkarmasıhakkındaki giriş açıklamalarına 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 Çekirdek Blazor işleme performansı en iyi yöntemleri.

Bileşen oluşturulduktan 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 referansları 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.

OnAfterRenderAsync durumunda, döndürülen herhangi bir Task tamamlandıktan sonra, bileşen otomatik olarak yeniden işleme alınmaz, bu yüzden sonsuz bir işleme döngüsünden kaçınılır.

OnAfterRender ve OnAfterRenderAsync bir bileşenin işlenmesi tamamlandıktan sonra çağrılır. Öğe ve bileşen referansları 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.

OnAfterRenderAsync durumunda, döndürülen herhangi bir Task tamamlandıktan sonra, bileşen otomatik olarak yeniden işleme alınmaz, bu yüzden sonsuz bir işleme döngüsünden kaçınılır.

firstRender ve OnAfterRender için OnAfterRenderAsync parametresi:

  • Bileşen örneği ilk kez işlendiğinde true olarak ayarlanır.
  • 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

OnAfterRenderAsync yaşam döngüsü olayı sırasında, işlemeden hemen sonra zaman uyumsuz çalışma 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 üzerinde OnAfterRenderAsync fonksiyonunu çağırın.

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.

Task'i OnAfterRenderAsync'den döndürseniz bile, görev tamamlandıktan sonra çatı, bileşeniniz için başka bir render döngüsü zamanlamaz. Bu, sonsuz bir işleme döngüsünden kaçınmaktır. Bu, döndürülen Task tamamlandığında başka bir render 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. Metotlar, ön işleme sonrasında bileşen etkileşimli olarak işlendiği zaman çağrılır. Uygulama önceden renderlandığında:

  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 çalıştırıldığında, bileşen etkileşimli işleme modunda yeniden başlatılır. Bir bileşen yeniden başlatıldıktan sonra, uygulama artık ön kayıt aşamasında olmadığından ve çağrılır.

Geliştirici kodunda olay işleyicileri sağlanıyorsa, elden çıkarılma sırasında bağlantılarını kesin. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşen imhası.

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

Blazor'nin yaşam döngüsü yöntemlerini geçersiz kılarken, ComponentBase için temel sınıf yaşam döngüsü yöntemlerini çağırmak gerekli değildir. 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.SetParametersAsync, await 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ği için ç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, StateHasChanged işlevini çağırmak, uygulamanın ana iş parçacığı boş olduğunda gerçekleşen bir yeniden render etme işlemini sıraya alır.

StateHasChanged otomatik olarak EventCallback yöntemler için ç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 StateHasChanged ile ne zaman çağrılacağı, ComponentBase.InvokeAsync ile başlatma dahil, hakkında daha fazla bilgi için ASP.NET Core Razor bileşen işleme konusuna bakın.

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

Bileşen işlendiğinde, yaşam döngüsü olaylarında gerçekleştirilen asenkron eylemler tamamlanmamış olabilir. Nesneler, yaşam döngüsü yöntemi yürütülürken verilerle doldurulmuş veya tamamlanmamış olabilir null. Nesnelerin başlatıldığını doğrulamak için görüntüleme mantığı sağlayın. Yer tutucu kullanıcı arabirimi öğelerini (örneğin, bir yükleme iletisini) nesneler null durumundayken işleyin.

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ınır. isLoading truesüresince kullanıcıya bir yükleme mesajı gösterilir. Task tarafından döndürülen OnInitializedAsync 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.

<Slow />

Notlar

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]

<h2>Slow Component</h2>

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

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

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

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

<h2>Slow Component</h2>

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

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

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

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

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

        return Task.CompletedTask;
    }

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

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

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:

:::moniker-end

Ö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 .NET 8'den ö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.

Hatalarla başa çıkma

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 durumlu bağlantı

Sunucuda önceden işleme yapılırken, bir bileşen başlangıçta sayfanın parçası olarak statik olarak işlenir. Tarayıcı sunucuyla SignalR bağlantıyı kurduktan sonra, bileşen tekrar işlenir ve etkileşimli hale gelir. 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 işlendiğ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 işleme sırasında durumu önbelleğe almak ve ön işleme sonrasında durumu almak üzere 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(...)), GetForecastAsync yönteminden veri döndürmeden önce kısa bir gecikme oluşturmaktadır.

Uygulamanın IMemoryCache dosyasındaki hizmet koleksiyonuna AddMemoryCache ile Program hizmetlerini ekleyin:

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, Blazor Web App'ler ve durum bilgili SignalRyeniden bağlanma'ya odaklanır. Ön kayıt sırasında başlatma kodunun yürütülmesi sırasında durumu korumak için bkz. ASP.NET Core Blazor önceden yüklenmiş durum kalıcılığı.

Bu bölümdeki içerik, Blazor Server ve durum bilgisi olan SignalRyeniden bağlanmaya odaklanmakla birlikte, barındırılan Blazor WebAssembly çözümlerindeki (WebAssemblyPrerendered) önceden oluşturma 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 işleme 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 entegrasyonu ile önceden render etme

Sunucu tarafı uygulamalarında bileşenleri önceden Razor oluşturma işlemi için bu bölüm geçerlidir. Önceden işleme, Razor başlığında ele alınmıştır.

Sunucu tarafı uygulamalarında bileşenleri önceden Razor oluşturma işlemi için bu bölüm geçerlidir. Önceden işleme, Razor başlığında ele alınmıştır.

Notlar

İç gezinti için etkileşimli yönlendirmeBlazor Web App'de, sunucudan yeni sayfa içeriği istemeyi içermez. Bu nedenle, iç sayfa istekleri için önceden render yapılmaz. 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. ASP.NET Core Blazor önceden oluşturulmuş durum kalıcılığı.

Bu bölüm, sunucu tarafı uygulamalar ve önceden Blazor WebAssembly bileşenlerini 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 örnek, bir bileşenin başlatma mantığının bir parçası olarak JS interop'un ön işleme ile uyumlu bir şekilde nasıl kullanılabileceğini göstermektedir.

Aşağıdaki scrollElementIntoView işlev:

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

Bileşen kodunda IJSRuntime.InvokeAsync işlevi çağrıldığında, bileşen işlendikten sonra HTML DOM öğesi var olduğu için JS yalnızca ElementReference içinde kullanılır ve önceki yaşam döngüsü yöntemlerinde kullanılmaz.

StateHasChanged (başvuru kaynağı), interop çağrısından JS elde edilen yeni durum ile bileşenin yeniden işlenmesi için kuyruğa alınması amacıyla çağrılır (daha fazla bilgi için bkz. ASP.NET Core Razor bileşen işleme). Sonsuz döngü oluşturulmaz çünkü StateHasChanged, yalnızca scrollPositionnull olduğunda çağrılır.

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 küresel bir fonksiyonla kirletir. Üretim uygulamalarında daha iyi bir yaklaşım için bkz . JavaScript modüllerinde JavaScript yalıtımı.

İ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üreli asenkron arka plan çalışmasını temsil eder.
  • BackgroundResourceMethod, uzun süre çalışan ve Resource yöntem çağrılmadan önce atılırsa başlatılmaması gereken 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;
        }
    }
}

Arka plan çalışması yapılırken bir yükleme göstergesi görüntülemek için aşağıdaki yaklaşımı kullanın.

Loading parametresi ile RenderFragment içinde alt içeriği görüntüleyebilen bir yükleme göstergesi bileşeni oluşturun. parametresi için Loading :

  • true olduğunda, bir yükleme göstergesi görüntüleyin.
  • olduğunda false, bileşenin içeriğini ( ) işleyinChildContent. Daha fazla bilgi için bkz Alt içerik işleme parçaları.

ContentLoading.razor:

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

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

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

Göstergenin CSS stillerini yüklemek için, <head> bileşenini kullanarak HeadContent içeriğine stilleri ekleyin. Daha fazla bilgi için ASP.NET Core Blazor uygulamalarında baş içeriğini kontrol etme konusuna bakın.

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

...

Bileşenin Razor işaretlemesini ContentLoading bileşeniyle sarın ve bileşen tarafından başlatma çalışması yapılırken, C# alanındaki bir değeri Loading parametresine geçirin.

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

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

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

    ...
}

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. SignalR istemci bağlantısı kesildiğinde, yalnızca kullanıcı arabirimi güncellemeleri duraklatılır. 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