c# - 从任意线程调用 StateHasChanged() 是否安全?

标签 c# blazor blazor-server-side

从任意线程调用 StateHasChanged() 是否安全?

让我给你一些背景。想象一个服务器端 Blazor/Razor Components 应用程序,您有:

  • 从任意线程引发 BreakingNews 事件的单例服务 NewsProvider
  • 组件 News.cshtml 获取服务注入(inject)并订阅 BreakingNews 事件。引发事件时,组件更新模型并调用 StateHashChanged()

NewsProvider.cs

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

新闻.cshtml

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

启动.cs

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 的东西?我应该使用 SyncrhonizationContext.Post 吗?

最佳答案

不,从任意线程调用 StateHasChanged() 是不安全的。

调用 StateHasChanged() 的正确方法是使用 InvokeAsync()

void OnBreakingNews(object sender, BreakingNewsEventArgs e)
{
    InvokeAsync(() => {
        news.Add(e.News);
        StateHasChanged();
    });
}

关于c# - 从任意线程调用 StateHasChanged() 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54496040/

相关文章:

c# - 在 Multi-Tenancy .net 项目中实现角色的最佳方式是什么?

Blazor:从布局访问参数

c# - 如何在 @code block 中编写 Blazor HTML 代码?

c# - 使用带有 Windows 身份验证的 Blazor 客户端使用 Web API

c# - 如何在单个网站中运行多个 Blazor 应用程序

c# - Blazor 获取两个属性的验证消息

c# - 为什么Dapper在执行查询时需要对事务的引用?

c# - 具有长json字符串参数的Wcf post方法

azure - 如何修复 "Destination URL, which is treated as Reply URL for enabling Microsoft Azure Authentication, is missing"

c# - UWP 网格过渡