Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Not
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.
Blazor, tek bir mantıksal yürütme iş akışını zorlayan bir eşitleme bağlamı (SynchronizationContext) kullanır. Bileşenin yaşam döngüsü yöntemleri ve Blazor tarafından oluşturulan olay geri çağırmaları eşitleme bağlamında yürütülür.
Blazor'nin sunucu tarafı eşitleme bağlamı, tarayıcıdaki tek iş parçacıklı WebAssembly modeliyle yakından eşleşmesi için tek iş parçacıklı bir ortamı taklit etmeye çalışır. Bu öykünme yalnızca tek bir bağlantı hattıyla sınırlıdır, yani iki farklı devre paralel olarak çalıştırılabilir. Bir devrede belirli bir zamanda, iş tam olarak bir iş parçacığı üzerinde gerçekleştirilir ve bu da tek bir mantıksal iş parçacığının izlenimi verir. İki işlem aynı devre içinde eşzamanlı olarak yürütülmez.
Tek bir mantıksal işlem, tek bir asenkron kontrol akışı anlamına gelmez. Bir bileşen, tamamlanmamış bir Taskbeklediği herhangi bir noktada yeniden giriş yapabilir. Yaşam Döngüsü yöntemleri veya bileşen atma yöntemleri, Task tamamlanmasını bekledikten sonra zaman uyumsuz denetim akışı devam etmeden önce çağrılabilir. Bu nedenle, bir bileşenin, potansiyel olarak eksik olabilecek bir Task'ı beklemeden önce geçerli bir durumda olduğundan emin olması gerekir. Özellikle, bir bileşenin OnInitializedAsync veya OnParametersSetAsync döndürdüğünüzde işleme için geçerli bir durumda olduğundan emin olması gerekir. Bu yöntemlerden biri tamamlanmamış bir Taskdöndürürse, yöntemin senkronize olarak tamamlanan bölümünün bileşeni işleme için geçerli bir durumda bırakmasını sağlamalıdır.
Tekrar giriş yapan bileşenlerin diğer bir etkisi, bir yöntemin, Task öğesini ComponentBase.InvokeAsync'e geçirdikten sonra döndürmeden erteleyememesidir. Çağrı ComponentBase.InvokeAsync, yalnızca sonraki Task ulaşılana kadar await'i erteleyebilir.
Bileşenler, bileşen atıldığında iptal edilen bir IDisposable'ten bir IAsyncDisposable kullanarak zamansız yöntemleri çağırmak için CancellationToken veya CancellationTokenSource'i uygulayabilirler. Ancak, bu gerçekten senaryoya bağlıdır. Bunun doğru davranış olup olmadığını belirlemek bileşen yazarına bağlıdır. Örneğin, kaydet düğmesi seçildiğinde bazı yerel verileri veritabanında kalıcı hale getiren bir SaveButton bileşeni uygularsanız, kullanıcı düğmeyi seçip başka bir sayfaya hızlı bir şekilde giderse bileşen yazarı değişiklikleri atmayı planlayabilir ve bu da zaman uyumsuz kaydetme tamamlanmadan önce bileşeni atabilir.
Atılabilir bir bileşen, bileşenin Taskalmadığı CancellationToken'ı bekledikten sonra elden çıkarma işlemini kontrol edebilir. Eksik Task'lar, bertaraf edilmiş bir bileşenin çöp toplanmasını da engelleyebilir.
ComponentBase, Task iptali tarafından neden olunan özel durumları görmezden gelir (daha kesin olarak, beklenen iptal edilirse Task özel durumlarını görmezden gelir), bu nedenle bileşen yöntemlerinin TaskCanceledException ve OperationCanceledExceptionişlemesi gerekmez.
ComponentBase, türetilmiş bir bileşen için geçerli bir durum oluşturan durumu kavramsallaştırmadığından ve kendisi IDisposable veya IAsyncDisposableuygulamadığından önceki yönergeleri uygulayamaz. OnInitializedAsync, Task kullanılmayan eksik bir CancellationToken döndürürse ve Task tamamlanmadan bileşen atılırsa, ComponentBase yine de OnParametersSet çağırır ve OnParametersSetAsyncbekler. Bir atılabilir bileşen CancellationTokenkullanmıyorsa, OnParametersSet ve OnParametersSetAsync bileşenin atılmış olup olmadığını denetlemelidir.
İş parçacığı engelleme çağrılarından kaçının
Genel olarak bileşenlerde aşağıdaki yöntemleri çağırmayın. Aşağıdaki yöntemler yürütme iş parçacığını engeller ve dolayısıyla temel Task tamamlanana kadar uygulamanın çalışmayı sürdürmesini de engeller:
Not
Blazor belgelerinde yer alan ve bu bölümde açıklanan iş parçacığı engelleme yöntemlerini kullanan örnekler, yöntemleri önerilen kodlama rehberi olarak değil yalnızca tanıtım amaçlı kullanmaktadır. Örneğin, birkaç bileşen kodu tanıtımı Thread.Sleep yöntemini çağırarak uzun süren bir süreci simule eder.
Durumu güncelleştirmek için bileşen yöntemlerini dışarıdan çağırma
Bileşenin bir dış olay (zamanlayıcı veya başka bir bildirim gibi) temelinde güncelleştirilmesi gereken durumlarda, kod yürütmeyi InvokeAsync'ın eşitleme bağlamına dağıtan Blazor yöntemini kullanın. Örneğin dinleyen tüm bileşenlere güncelleştirilmiş durumu bildirebilecek aşağıdaki bildirimci hizmetini inceleyin.
Update yöntemi uygulamanın herhangi bir yerinden çağrılabilir.
TimerService.cs:
namespace BlazorSample;
public class TimerService(NotifierService notifier,
ILogger<TimerService> logger) : IDisposable
{
private int elapsedCount;
private static readonly TimeSpan heartbeatTickRate = TimeSpan.FromSeconds(5);
private readonly ILogger<TimerService> logger = logger;
private readonly NotifierService notifier = notifier;
private PeriodicTimer? timer;
public async Task Start()
{
if (timer is null)
{
timer = new(heartbeatTickRate);
logger.LogInformation("Started");
using (timer)
{
while (await timer.WaitForNextTickAsync())
{
elapsedCount += 1;
await notifier.Update("elapsedCount", elapsedCount);
logger.LogInformation("ElapsedCount {Count}", elapsedCount);
}
}
}
}
public void Stop()
{
if (timer is not null)
{
timer.Dispose();
timer = null;
logger.LogInformation("Stopped");
}
}
public void Dispose()
{
timer?.Dispose();
// The following prevents derived types that introduce a
// finalizer from needing to re-implement IDisposable.
GC.SuppressFinalize(this);
}
}
namespace BlazorSample;
public class TimerService(NotifierService notifier,
ILogger<TimerService> logger) : IDisposable
{
private int elapsedCount;
private static readonly TimeSpan heartbeatTickRate = TimeSpan.FromSeconds(5);
private readonly ILogger<TimerService> logger = logger;
private readonly NotifierService notifier = notifier;
private PeriodicTimer? timer;
public async Task Start()
{
if (timer is null)
{
timer = new(heartbeatTickRate);
logger.LogInformation("Started");
using (timer)
{
while (await timer.WaitForNextTickAsync())
{
elapsedCount += 1;
await notifier.Update("elapsedCount", elapsedCount);
logger.LogInformation("ElapsedCount {Count}", elapsedCount);
}
}
}
}
public void Dispose()
{
timer?.Dispose();
// The following prevents derived types that introduce a
// finalizer from needing to re-implement IDisposable.
GC.SuppressFinalize(this);
}
}
public class TimerService : IDisposable
{
private int elapsedCount;
private static readonly TimeSpan heartbeatTickRate = TimeSpan.FromSeconds(5);
private readonly ILogger<TimerService> logger;
private readonly NotifierService notifier;
private PeriodicTimer? timer;
public TimerService(NotifierService notifier,
ILogger<TimerService> logger)
{
this.notifier = notifier;
this.logger = logger;
}
public async Task Start()
{
if (timer is null)
{
timer = new(heartbeatTickRate);
logger.LogInformation("Started");
using (timer)
{
while (await timer.WaitForNextTickAsync())
{
elapsedCount += 1;
await notifier.Update("elapsedCount", elapsedCount);
logger.LogInformation("elapsedCount: {ElapsedCount}", elapsedCount);
}
}
}
}
public void Dispose()
{
timer?.Dispose();
}
}
public class TimerService : IDisposable
{
private int elapsedCount;
private static readonly TimeSpan heartbeatTickRate = TimeSpan.FromSeconds(5);
private readonly ILogger<TimerService> logger;
private readonly NotifierService notifier;
private PeriodicTimer? timer;
public TimerService(NotifierService notifier,
ILogger<TimerService> logger)
{
this.notifier = notifier;
this.logger = logger;
}
public async Task Start()
{
if (timer is null)
{
timer = new(heartbeatTickRate);
logger.LogInformation("Started");
using (timer)
{
while (await timer.WaitForNextTickAsync())
{
elapsedCount += 1;
await notifier.Update("elapsedCount", elapsedCount);
logger.LogInformation("elapsedCount: {ElapsedCount}", elapsedCount);
}
}
}
}
public void Dispose()
{
timer?.Dispose();
}
}
using System;
using System.Timers;
using Microsoft.Extensions.Logging;
public class TimerService : IDisposable
{
private int elapsedCount;
private readonly ILogger<TimerService> logger;
private readonly NotifierService notifier;
private Timer timer;
public TimerService(NotifierService notifier, ILogger<TimerService> logger)
{
this.notifier = notifier;
this.logger = logger;
}
public void Start()
{
if (timer is null)
{
timer = new();
timer.AutoReset = true;
timer.Interval = 10000;
timer.Elapsed += HandleTimer;
timer.Enabled = true;
logger.LogInformation("Started");
}
}
private async void HandleTimer(object source, ElapsedEventArgs e)
{
elapsedCount += 1;
await notifier.Update("elapsedCount", elapsedCount);
logger.LogInformation("elapsedCount: {ElapsedCount}", elapsedCount);
}
public void Dispose()
{
timer?.Dispose();
}
}
using System;
using System.Timers;
using Microsoft.Extensions.Logging;
public class TimerService : IDisposable
{
private int elapsedCount;
private readonly ILogger<TimerService> logger;
private readonly NotifierService notifier;
private Timer timer;
public TimerService(NotifierService notifier, ILogger<TimerService> logger)
{
this.notifier = notifier;
this.logger = logger;
}
public void Start()
{
if (timer is null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 10000;
timer.Elapsed += HandleTimer;
timer.Enabled = true;
logger.LogInformation("Started");
}
}
private async void HandleTimer(object source, ElapsedEventArgs e)
{
elapsedCount += 1;
await notifier.Update("elapsedCount", elapsedCount);
logger.LogInformation("elapsedCount: {ElapsedCount}", elapsedCount);
}
public void Dispose()
{
timer?.Dispose();
}
}
NotifierService.cs:
namespace BlazorSample;
public class NotifierService
{
public async Task Update(string key, int value)
{
if (Notify != null)
{
await Notify.Invoke(key, value);
}
}
public event Func<string, int, Task>? Notify;
}
namespace BlazorSample;
public class NotifierService
{
public async Task Update(string key, int value)
{
if (Notify != null)
{
await Notify.Invoke(key, value);
}
}
public event Func<string, int, Task>? Notify;
}
public class NotifierService
{
public async Task Update(string key, int value)
{
if (Notify != null)
{
await Notify.Invoke(key, value);
}
}
public event Func<string, int, Task>? Notify;
}
public class NotifierService
{
public async Task Update(string key, int value)
{
if (Notify != null)
{
await Notify.Invoke(key, value);
}
}
public event Func<string, int, Task>? Notify;
}
using System;
using System.Threading.Tasks;
public class NotifierService
{
public async Task Update(string key, int value)
{
if (Notify != null)
{
await Notify.Invoke(key, value);
}
}
public event Func<string, int, Task> Notify;
}
using System;
using System.Threading.Tasks;
public class NotifierService
{
public async Task Update(string key, int value)
{
if (Notify != null)
{
await Notify.Invoke(key, value);
}
}
public event Func<string, int, Task> Notify;
}
Hizmetleri kaydetme:
İstemci tarafı geliştirme için, hizmetleri istemci tarafı
Programdosyasına tekil olarak kaydedin:builder.Services.AddSingleton<NotifierService>(); builder.Services.AddSingleton<TimerService>();Sunucu tarafı geliştirme için, hizmetleri sunucu
Programdosyasında kapsamı belirlenmiş olarak kaydedin:builder.Services.AddScoped<NotifierService>(); builder.Services.AddScoped<TimerService>();
Bileşeni güncelleştirmek için NotifierService kullanın.
Notifications.razor:
@page "/notifications"
@implements IDisposable
@inject NotifierService Notifier
@inject TimerService Timer
<PageTitle>Notifications</PageTitle>
<h1>Notifications Example</h1>
<h2>Timer Service</h2>
<button @onclick="StartTimer">Start Timer</button>
<button @onclick="StopTimer">Stop Timer</button>
<h2>Notifications</h2>
<p>
Status:
@if (lastNotification.key is not null)
{
<span>@lastNotification.key = @lastNotification.value</span>
}
else
{
<span>Awaiting notification</span>
}
</p>
@code {
private (string key, int value) lastNotification;
protected override void OnInitialized() => Notifier.Notify += OnNotify;
public async Task OnNotify(string key, int value)
{
await InvokeAsync(() =>
{
lastNotification = (key, value);
StateHasChanged();
});
}
private void StartTimer() => _ = Task.Run(Timer.Start);
private void StopTimer() => Timer.Stop();
public void Dispose() => Notifier.Notify -= OnNotify;
}
Notifications.razor:
@page "/notifications"
@implements IDisposable
@inject NotifierService Notifier
@inject TimerService Timer
<PageTitle>Notifications</PageTitle>
<h1>Notifications Example</h1>
<h2>Timer Service</h2>
<button @onclick="StartTimer">Start Timer</button>
<h2>Notifications</h2>
<p>
Status:
@if (lastNotification.key is not null)
{
<span>@lastNotification.key = @lastNotification.value</span>
}
else
{
<span>Awaiting notification</span>
}
</p>
@code {
private (string key, int value) lastNotification;
protected override void OnInitialized() => Notifier.Notify += OnNotify;
public async Task OnNotify(string key, int value)
{
await InvokeAsync(() =>
{
lastNotification = (key, value);
StateHasChanged();
});
}
private void StartTimer() => _ = Task.Run(Timer.Start);
public void Dispose() => Notifier.Notify -= OnNotify;
}
ReceiveNotifications.razor:
@page "/receive-notifications"
@implements IDisposable
@inject NotifierService Notifier
@inject TimerService Timer
<h1>Receive Notifications</h1>
<h2>Timer Service</h2>
<button @onclick="StartTimer">Start Timer</button>
<h2>Notifications</h2>
<p>
Status:
@if (lastNotification.key is not null)
{
<span>@lastNotification.key = @lastNotification.value</span>
}
else
{
<span>Awaiting notification</span>
}
</p>
@code {
private (string key, int value) lastNotification;
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public async Task OnNotify(string key, int value)
{
await InvokeAsync(() =>
{
lastNotification = (key, value);
StateHasChanged();
});
}
private void StartTimer()
{
_ = Task.Run(Timer.Start);
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
ReceiveNotifications.razor:
@page "/receive-notifications"
@implements IDisposable
@inject NotifierService Notifier
@inject TimerService Timer
<h1>Receive Notifications</h1>
<h2>Timer Service</h2>
<button @onclick="StartTimer">Start Timer</button>
<h2>Notifications</h2>
<p>
Status:
@if (lastNotification.key is not null)
{
<span>@lastNotification.key = @lastNotification.value</span>
}
else
{
<span>Awaiting notification</span>
}
</p>
@code {
private (string key, int value) lastNotification;
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public async Task OnNotify(string key, int value)
{
await InvokeAsync(() =>
{
lastNotification = (key, value);
StateHasChanged();
});
}
private void StartTimer()
{
_ = Task.Run(Timer.Start);
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
ReceiveNotifications.razor:
@page "/receive-notifications"
@implements IDisposable
@inject NotifierService Notifier
@inject TimerService Timer
<h1>Receive Notifications</h1>
<h2>Timer Service</h2>
<button @onclick="StartTimer">Start Timer</button>
<h2>Notifications</h2>
<p>
Status:
@if (lastNotification.key is not null)
{
<span>@lastNotification.key = @lastNotification.value</span>
}
else
{
<span>Awaiting notification</span>
}
</p>
@code {
private (string key, int value) lastNotification;
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public async Task OnNotify(string key, int value)
{
await InvokeAsync(() =>
{
lastNotification = (key, value);
StateHasChanged();
});
}
private void StartTimer()
{
Timer.Start();
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
ReceiveNotifications.razor:
@page "/receive-notifications"
@implements IDisposable
@inject NotifierService Notifier
@inject TimerService Timer
<h1>Receive Notifications</h1>
<h2>Timer Service</h2>
<button @onclick="StartTimer">Start Timer</button>
<h2>Notifications</h2>
<p>
Status:
@if (lastNotification.key != null)
{
<span>@lastNotification.key = @lastNotification.value</span>
}
else
{
<span>Awaiting notification</span>
}
</p>
@code {
private (string key, int value) lastNotification;
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public async Task OnNotify(string key, int value)
{
await InvokeAsync(() =>
{
lastNotification = (key, value);
StateHasChanged();
});
}
private void StartTimer()
{
Timer.Start();
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
Yukarıdaki örnekte:
- Zamanlayıcı, Blazor'nun eşitleme bağlamı dışında
_ = Task.Run(Timer.Start)ile başlatılır. -
NotifierServicebileşeninOnNotifyyöntemini çağırır.InvokeAsync, doğru bağlama geçmek ve bir rerender'ı sıralamak için kullanılır. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşenini işleme. - Bileşen IDisposable uygular. Çerçeve tarafından, bileşen atıldığında çağrılan
OnNotifyyöntemindeDisposetemsilcisinin aboneliği kaldırılır. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşen imhası.
-
NotifierService, bileşeninOnNotifyyöntemini Blazor'ın eşitleme bağlamının dışından çağırır.InvokeAsync, doğru bağlama geçmek ve bir rerender'ı sıralamak için kullanılır. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşenini işleme. - Bileşen IDisposable uygular. Çerçeve tarafından, bileşen atıldığında çağrılan
OnNotifyyöntemindeDisposetemsilcisinin aboneliği kaldırılır. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşen imhası.
Önemli
Bir Razor bileşeni, arka plan iş parçacığından tetiklenen bir olayı tanımlıyorsa, işleyici kaydedildiği sırada yürütme bağlamını (ExecutionContext) yakalayıp geri yüklemesi gerekebilir. Daha fazla bilgi için bkz: Çağrı InvokeAsync(StateHasChanged) sayfanın varsayılan kültüre geri dönmesine neden oluyor (dotnet/aspnetcore #28521).
Arka plan TimerService bileşenindeki yakalanan özel durumları, normal yaşam döngüsü olayları gibi işlemeleri için bileşene iletmek amacıyla, Razor bileşeninin yaşam döngüsü dışındaki yakalanan özel durumları işleme bölümüne bakın.
Razor bileşeninin yaşam döngüsü dışında yakalanan özel durumları ele alın
Bileşenin yaşam döngüsü çağrı yığınının dışında atılan özel durumları işlemek için bir ComponentBase.DispatchExceptionAsync bileşeninde Razor kullanın. Bu, bileşenin kodunun özel durumları yaşam döngüsü yöntemi özel durumları gibi işlemesine izin verir. Bundan sonra Blazor‘ün hata sınırları gibi hata işleme mekanizmaları, istisnaları işleyebilir.
Not
ComponentBase.DispatchExceptionAsync, Razor öğesinden devralan .razor bileşen dosyalarında (ComponentBase) kullanılır. Bileşenleri oluştururken implement IComponent directly, RenderHandle.DispatchExceptionAsync kullanın.
Bir Razor bileşenin yaşam döngüsü dışında yakalanan özel durumları işlemek için özel durumu DispatchExceptionAsync'ye geçirin ve sonucu bekleyin.
try
{
...
}
catch (Exception ex)
{
await DispatchExceptionAsync(ex);
}
Önceki yaklaşım için yaygın bir senaryo, bir bileşenin zaman uyumsuz bir işlem başlatması ancak genellikle bir Task deseni beklememesidir. Çünkü yöntem tetiklenir (başlatılır) ve yöntemin sonucu unutulur (atılır). İşlem başarısız olursa, bileşenin aşağıdaki hedeflerden herhangi biri için hatayı bileşen yaşam döngüsü özel durumu olarak işlemesini isteyebilirsiniz:
- Bileşeni hata durumu gibi bir duruma, örneğin bir hata sınırını tetiklemek için yerleştirin.
- Hata sınırı yoksa devreyi sonlandırın.
- Yaşam döngüsü istisnaları için gerçekleşen aynı türdeki günlüğü tetikleyin.
Aşağıdaki örnekte kullanıcı Rapor gönder düğmesini seçerek rapor gönderen bir arka plan yöntemi ( ReportSender.SendAsync, ) tetikler. Çoğu durumda, bir bileşen zaman uyumsuz bir çağrı bekler Task ve işlemin tamamlandığını belirtmek için kullanıcı arabirimini güncelleştirir. Aşağıdaki örnekte SendReport yöntemi Task için beklemez ve sonucu kullanıcıya bildirmez. Bileşen, Task öğesini SendReport içinde kasıtlı olarak attığı için, zaman uyumsuz hatalar normal yaşam döngüsü çağrı yığınının dışında meydana gelir ve bu yüzden Blazor tarafından görülmez.
<button @onclick="SendReport">Send report</button>
@code {
private void SendReport()
{
_ = ReportSender.SendAsync();
}
}
Yaşam döngüsü yöntemlerinin özel durumlarına benzer hataları işlemek için, aşağıdaki örnekte gösterildiği gibi özel durumları bileşene DispatchExceptionAsync açıkça geri yönlendirin.
<button @onclick="SendReport">Send report</button>
@code {
private void SendReport()
{
_ = SendReportAsync();
}
private async Task SendReportAsync()
{
try
{
await ReportSender.SendAsync();
}
catch (Exception ex)
{
await DispatchExceptionAsync(ex);
}
}
}
Alternatif bir yaklaşımı kullanır: Task.Run
private void SendReport()
{
_ = Task.Run(async () =>
{
try
{
await ReportSender.SendAsync();
}
catch (Exception ex)
{
await DispatchExceptionAsync(ex);
}
});
}
Çalışan bir gösterim için, Durumu güncelleştirmek için bileşen yöntemlerini harici olarak çağırma bölümünde zamanlayıcı bildirimi örneğini uygulayın. Bir Blazor uygulamada zamanlayıcı bildirim örneğinden aşağıdaki dosyaları ekleyin ve bölümünde açıklandığı gibi hizmetleri Program dosyaya kaydedin:
TimerService.csNotifierService.csNotifications.razor
Örnek, bir Razor bileşeninin yaşam döngüsünün dışında bir zamanlayıcı kullanır ve burada işlenmeyen özel durumlar, normalde Blazor gibi hata sınırları içeren hata işleme mekanizmaları tarafından işlenmez.
İlk olarak, bileşenin yaşam döngüsünün dışında yapay bir özel durum oluşturmak için içindeki TimerService.cs kodu değiştirin.
while döngüsünde TimerService.cs, elapsedCount iki değerine ulaştığında bir özel durumu fırlat:
if (elapsedCount == 2)
{
throw new Exception("I threw an exception! Somebody help me!");
}
Uygulamanın ana düzenine bir hata sınırı yerleştirin. İşaretlemeyi <article>...</article> aşağıdaki işaretlemeyle değiştirin.
MainLayout.razor içinde:
<article class="content px-4">
<ErrorBoundary>
<ChildContent>
@Body
</ChildContent>
<ErrorContent>
<p class="alert alert-danger" role="alert">
Oh, dear! Oh, my! - George Takei
</p>
</ErrorContent>
</ErrorBoundary>
</article>
Blazor Web App ile yalnızca statik MainLayout bileşenine uygulanan hata sınırı, yalnızca statik sunucu tarafı işleme (statik SSR) aşamasında aktiftir. Sınır, yalnızca bileşen hiyerarşisinin daha aşağısındaki bir bileşen etkileşimli olduğundan etkinleştirilmez.
MainLayout bileşeni ve bileşen hiyerarşisinin daha aşağısındaki bileşenlerin geri kalanı için etkileşimi geniş bir şekilde etkinleştirmek için, HeadOutlet bileşenindeki (Routes) App ve Components/App.razor bileşen örnekleri için etkileşimli işlemeyi etkinleştirin. Aşağıdaki örnek Etkileşimli Sunucu (InteractiveServer) işleme modunu benimser:
<HeadOutlet @rendermode="InteractiveServer" />
...
<Routes @rendermode="InteractiveServer" />
Uygulamayı bu noktada çalıştırırsanız, geçen sayısı iki değerine ulaştığında istisna fırlatılır. Ancak kullanıcı arabirimi değişmez. Hata sınırı hata içeriğini göstermez.
Zamanlayıcı hizmetinden Notifications bileşenine istisnaları iletmek için, bileşende aşağıdaki değişiklikler yapılır:
- Bir
try-catchdeyiminde zamanlayıcıyı başlatın. Bloğuncatchyan tümcesinde,try-catchistisnalar Exception öğesine geçirilir ve sonucu beklenerek DispatchExceptionAsync bileşene geri gönderilir. -
StartTimeryönteminde, Action'nin Task.Run temsilcisi içinde zaman uyumsuz zamanlayıcı hizmetini başlatın ve döndürülen Task öğesini kasıtlı olarak atın.
StartTimer Bileşenin Notifications yöntemi (Notifications.razor):
private void StartTimer()
{
_ = Task.Run(async () =>
{
try
{
await Timer.Start();
}
catch (Exception ex)
{
await DispatchExceptionAsync(ex);
}
});
}
Zamanlayıcı hizmeti yürütüldüğünde ve iki sayısına ulaştığında, istisna Razor bileşenine gönderilir ve bu da <ErrorBoundary> bileşenindeki hata sınırını MainLayout hata içeriğini görüntülemek için tetikler.
Ah, canım! Aman! - George Takei
ASP.NET Core