从任意线程调用rewind
是否安全?
让我给您一些背景信息。想象一下您拥有的服务器端Blazor / Razor组件应用程序:
StateHasChanged()
,它从任意线程引发NewsProvider
个事件。BreakingNews
事件的组件News.cshtml
。引发事件时,组件将更新模型并调用BreakingNews
StateHashChanged()
using System;
using System.Threading;
namespace BlazorServer.App
{
public class BreakingNewsEventArgs: EventArgs
{
public readonly string News;
public BreakingNewsEventArgs(string news)
{
this.News = news;
}
}
public interface INewsProvider
{
event EventHandler<BreakingNewsEventArgs> BreakingNews;
}
public class NewsProvider : INewsProvider, IDisposable
{
private int n = 0;
public event EventHandler<BreakingNewsEventArgs> BreakingNews;
private Timer timer;
public NewsProvider()
{
timer = new Timer(BroadCastBreakingNews, null, 10, 2000);
}
void BroadCastBreakingNews(object state)
{
BreakingNews?.Invoke(this, new BreakingNewsEventArgs("Noticia " + ++n));
}
public void Dispose()
{
timer.Dispose();
}
}
}
@page "/news"
@inject INewsProvider NewsProvider
@implements IDisposable
<h1>News</h1>
@foreach (var n in this.news)
{
<p>@n</p>
}
@functions {
EventHandler<BreakingNewsEventArgs> breakingNewsEventHandler;
List<string> news = new List<string>();
protected override void OnInit()
{
base.OnInit();
breakingNewsEventHandler = new EventHandler<BreakingNewsEventArgs>(OnBreakingNews);
this.NewsProvider.BreakingNews += breakingNewsEventHandler;
}
void OnBreakingNews(object sender, BreakingNewsEventArgs e)
{
this.news.Add(e.News);
StateHasChanged();
}
public void Dispose()
{
this.NewsProvider.BreakingNews -= breakingNewsEventHandler;
}
}
它显然有效,但是我不知道using Microsoft.AspNetCore.Blazor.Builder;
using Microsoft.Extensions.DependencyInjection;
using BlazorServer.App.Services;
namespace BlazorServer.App
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Since Blazor is running on the server, we can use an application service
// to read the forecast data.
services.AddSingleton<WeatherForecastService>();
services.AddSingleton<INewsProvider, NewsProvider>();
}
public void Configure(IBlazorApplicationBuilder app)
{
app.AddComponent<App>("app");
}
}
}
是否是线程安全的。如果不是,如何安全地呼叫StateHasChanged()
?是否有类似于StateHashChanged()
的东西?我应该使用Control.BeginInvoke
吗?
答案 0 :(得分:5)
否,从任意线程调用StateHasChanged()
是不安全的。在ASP.NET Core 3.0预览版2上运行该代码将引发以下异常:
Microsoft.AspNetCore.Components.Browser.Rendering.RemoteRendererException: '当前线程未与渲染器的 同步上下文。使用Invoke()或InvokeAsync()进行切换 触发时执行渲染器的同步上下文 渲染或修改渲染期间访问的任何状态。”
调用StateHasChanged()
的正确方法如下:
void OnBreakingNews(object sender, BreakingNewsEventArgs e)
{
Invoke(() => {
news.Add(e.News);
StateHasChanged();
});
}
但是Invoke
已添加到ASP.NET NET Core 3.0预览剃刀组件中,在ASP.NET Core 2.1服务器端Blazor中不可用。
答案 1 :(得分:0)
也许这可以帮助您...
SteveSanderson:
现有的UI更新机制是围绕从.NET到JS的一批最小差异进行传输而设计的,因此,将这些差异表示为序列化数据而不是将指针表示为WASM内存空间并不难。我们必须要小心周围的事物,像事件处理,以保证异步不会导致行为与同步单线程模型的不一致性。例如,我们需要将迫使所有事件传递是异步至于JS侧而言,即使在非工作线程的情况下。