【问题标题】:How to refresh web page after database update in ASP.NET CORE with Blazor如何在使用 Blazor 的 ASP.NET CORE 中更新数据库后刷新网页
【发布时间】:2020-05-21 08:35:31
【问题描述】:

我正在制作一个小型房间预订网络应用程序,我希望在给定的时间间隔内刷新网页;即给定的分钟或对数据库进行更改的时间。我找到了StateHasChanged();,但我真的不知道如何实现它(Newbie One Kenobi here!) 我试图把它放在向日程表中添加约会的函数中:

var result = Service.CreateSchedule(nextSchedule);
    if (result)
    {
        StateHasChanged();
        NavigationManager.NavigateTo("/roomzfront/1");
    }

但我可能需要更多的东西,或者在代码的其他地方。

【问题讨论】:

  • 如果有任何变化就调用它。没有什么可实施的。但是,如果您想导航到其他页面,则没有理由更新当前页面
  • 我的计时器解决方案基于this blog posting。这是我的BlazorTimer component

标签: c# asp.net blazor


【解决方案1】:

其实,你并不需要为了获取更新版本的数据库内容而刷新页面。

相反,我们需要做的就是从您的数据库中重新获取数据,因为您浏览器中显示的内容与您在页面首次加载时获取的数据绑定。

例如,如果您有一个页面List.razor 显示您的数据,您也可以在那里创建新的数据行。所以你可能有这些代码:

@page "/list"
@inject DbService DbService

<h2>All Data Lines<h2>
<table>
    <thead>
        <tr>
            <th>Title</th>
            <th>Content</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var line in dataLines)
        {
            <tr>
                <td>@line.Title</td>
                <td>@line.Content</td>
            </tr>
        }
    </tbody>
</table>

<h2>Add A New Data Line</h2>
<input type="text" placeholder="Title" @bind="newLine.Title"/>
<input type="text" placeholder="Content" @bind="newLine.Content"/>
<button @onclick="AddNewLine">Add</button>

@code 
{
    List<DataLine> dataLines = new List<DataLine>();
    protected override void OnInitialized()
    {
        dataLines = DbService.GetAllData();
    }

    DataLine newLine = new DataLine();
    void AddNewLine()
    {
        DbService.CreateLine(newLine);
    }
}

为了帮助你理解它的样子,让我们在脑海中运行代码;这是您的浏览器:

 (<-)  (->)  (https://contoso.com/list                           )

所有数据线

|---------------------|------------------|
|        Title        |      Content     |
|=====================|==================|
|        Data1        |      Content1    |
|---------------------|------------------|
|        Data2        |      Content2    |
|---------------------|------------------|

添加新数据线

[          Title          ]
[         Content         ]
(Add)

=================浏览器结束=================

现在让我们在TitleContent 中输入一些内容,然后单击Add。您的网站现在开始向您的数据库提交“添加”请求。之后,在刷新之前,您看不到上表中的任何更改。这是因为当前显示在表中的数据是在页面首次加载时获取的。当您刷新页面时,它将再次获取数据。但是,如果您不这样做,则数据已经过时,但我们需要做的就是在您的网站对数据库进行一些更改时手动更新(获取)数据。这意味着您可以简单地在函数 void AddNewLine() 的末尾添加一行 dataLines = DbService.GetAllData();,如下所示:

void AddNewLine()
{
    DbService.CreateLine(newLine);
    DbService.GetAllData();
}

现在,由于数据已重新获取,您的表现在正在显示数据库的最新数据。

希望对你有所帮助,如果有任何问题,请随时告诉我!

【讨论】:

  • 我喜欢这个答案。这实际上可能是正确的。
  • 谢谢。由于这解决了仅更新数据库表的问题,因此它不会刷新整个页面。该页面包含一个显示空闲时间段的组件(或不显示空闲时间段,如果它们已被预订),当您单击其中一个按钮时,所有组件都应刷新,而不仅仅是数据表。
  • 14 个月后。这现在更有意义了。
【解决方案2】:

您需要使用 SignalR 或 WebSockets——它们现在支持开箱即用——来获取数据库更新通知,但坦率地说,实际上从数据库获取通知可能会很痛苦,除非它是 Firebase 或 SapphireDb。

您可以使用 Notifications API,但您需要编写 Javascript Interop 才能与 Service Worker 聊天,而且现在大多数理智的人会默认关闭通知。或者我想有服务器推送协议,但它并没有得到普遍支持,同样,服务工作者。

关于实际的更改通知,最好的办法是在中间层触发它们,作为成功写入数据操作的一部分(除非 Firebase 或 Sapphire,如上所述),但请注意,如果数据来自任何其他来源,而不是只是您的 WebAPI 层,这是不准确的。

TL;DR - 你选择了一个非常艰难的。听起来微不足道,尤其是对管理类型而言,但绝对不是。

【讨论】:

  • 我很想知道为什么这个(标记为正确的)答案被否决了。
  • 如果您能更深入地了解这一点,我将不胜感激
【解决方案3】:
// To refresh data on your page simply add the StateHasChanged() opcode.

private async void GetEmployeesFromCache()
    {
        var stopWatch = new Stopwatch();
        stopWatch.Start();

        CacheStatus = "Processing";
        Employees = await _employeeManager.GetEmployeesFromCache();
        CacheStatus = $"Completed in { stopWatch.ElapsedMilliseconds} ms";

        StateHasChanged();
    }

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
【解决方案4】:

你可以试试下面-

<ul>
    @foreach (var booking in Bookings)
    {
        <li>@booking.BookedRoomNumber</li>
    }
</ul>

@functions{

var timer = new Timer(new TimerCallback(_ =>
        {
            // Code to fetch the data and bind it to the page level variable
            // Ex : Bookings = GetBookingsData();

            // This line is necessary
            this.StateHasChanged();
        }), null, 1000, 1000);

}

【讨论】:

    【解决方案5】:

    如果您不想使用 SignalR 或 WebSockets,这是另一种方法。

    我有一个 Timer 作为我的 Sprite 组件的一部分按间隔调度,给你一个例子来说明如何做到这一点:

    Sprite 有一个名为 Subscriber 的属性

    [Parameter]
    public ISpriteSubscriber { get; set; }
    

    宿主组件或页面是一个 ISpriteSubscriber 接口。

    namespace DataJuggler.Blazor.Components.Interfaces
    {
    
        #region interface ISpriteSubscriber
        /// <summary>
        /// This interface is used by the AnimationManager to notifiy callers that a refresh occurred.
        /// </summary>
        public interface ISpriteSubscriber
        {
    
            #region Methods
    
                #region Refresh()
                /// <summary>
                /// This method will call StateHasChanged to refresh the UI
                /// </summary>
                void Refresh();
                #endregion
    
                #region Register(Sprite sprite)
                /// <summary>
                /// This method is called by the Sprite to a subscriber so it can register with the subscriber, and 
                /// receiver events after that.
                /// </summary>
                void Register(Sprite sprite);
    
            #endregion
    
            #endregion
    
            #region Properties
    
                #region ProgressBar
                /// <summary>
                /// This is used so the ProgressBar is stored and available to the Subscriber after Registering
                /// </summary>
                ProgressBar ProgressBar { get; set; }
                #endregion
    
            #endregion
    
        }
        #endregion
    
    }
    

    比在你的剃刀代码中设置父级,你设置 Subscriber=this:

    注意间隔=50。这会将计时器设置为每 50 毫秒刷新一次。

    在我的 Sprite 组件的 setter 中,我做的第一件事是向父级调用 Register:

    [Parameter]
    public ISpriteSubscriber Subscriber
    {
        get { return subscriber; }
        set 
        {   
            // set the value
            subscriber = value;
    
            // if the value for HasSubscriber is true
            if (HasSubscriber)
            {
                // Register with the Subscriber so they can talk to each other
                Subscriber.Register(this);
            }
        }
    }
    

    这里的代码在托管精灵的索引页面上,并将精灵注册到父级:

    public void Register(Sprite sprite)
    {
        // If the sprite object exists
        if (NullHelper.Exists(sprite))
        {
            // if this is the RedCar
            if (sprite.Name == "RedCar")
            {
                // Set the RedCar
                RedCar = sprite;
            }
            else 
            {
                // Set the WhiteCar
                WhiteCar = sprite;
            }
        }
    }
    

    现在,当我点击开始比赛按钮时,我只启动了 1 个计时器,即使我有两辆车,我也不希望两个计时器运行:

    public void StartRace()
    {
        // if both cars exist
        if (NullHelper.Exists(RedCar, WhiteCar))
        {
            // Create a new instance of a 'RandomShuffler' object.
            Shuffler = new RandomShuffler(2, 12, 100, 3);
    
            // Start the timer on the RedCar
            RedCar.Start();
        }
    }
    

    这里是 Sprite 的 Start 方法:

    public void Start()
    {
        this.Timer = new Timer();
        this.Timer.Interval = this.interval;
        this.Timer.Elapsed += Timer_Elapsed;
        this.Timer.Start();
    }
    

    然后Timer_Elapsed事件,调用Subscriber刷新:

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // if a subscriber exists
        if (HasSubscriber)
        {
           // Notify Subscriber
           Subscriber.Refresh();
        }
    }
    

    现在在这种情况下,我的刷新方法每 50 毫秒调用一次,然后我更新我的 UI:

    public void Refresh()
    {
        // do your updates
    
        // Update the UI
        InvokeAsync(() =>
        {
            StateHasChanged();
        });
    }
    

    如果您想查看完整的工作示例,请克隆此项目并在示例文件夹中查找 ProgressBarSample。

    https://github.com/DataJuggler/DataJuggler.Blazor.Components

    如果您想观看,这里还有一个视频: https://youtu.be/frtetHgfdIo

    我已经在一些事情上使用了这种父/子方法,并且效果很好,我写了一篇关于它的博客文章:Using Interfaces To Communicate Between Blazor Components

    我发现这是与其他组件通信或发送数据的好方法。

    【讨论】:

    • ew,轮询。如果你必须,我想。
    • 发布后我意识到我读错了问题。有时我对某事的最初理解是错误的。
    • 我认为我 50 毫秒的轮询不是一个好习惯,应该尽可能避免
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    相关资源
    最近更新 更多