使用Blazor在ASP.NET CORE中更新数据库后如何刷新网页

时间:2020-02-05 12:14:57

标签: c# asp.net blazor

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

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

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

4 个答案:

答案 0 :(得分:6)

实际上,您无需刷新页面即可获取新版本的数据库内容。

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

例如,如果您有一个页面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。您的网站现在开始向您的数据库提交“添加”请求。此后,直到刷新,您才能在上表中看到任何更改。这是因为在第一次加载页面时会获取表中当前显示的数据。刷新页面时,它将再次获取数据。但是,如果您不这样做,则数据已经过时,但是我们要做的就是在您的网站对数据库进行一些更改后手动更新(获取)数据。这意味着您可以像这样在函数dataLines = DbService.GetAllData();的末尾添加一行void AddNewLine()

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

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

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

答案 1 :(得分:2)

您需要使用SignalR或WebSockets(这些天已经受到开箱即用的支持)来获取数据库更新通知,尽管坦率地说,除非是Firebase或SapphireDb,否则实际上从数据库获取通知可能会很痛苦。

您可以使用Notifications API,但是您需要编写Javascript Interop才能与Service Worker聊天,并且这些天大多数理智的人默认情况下会关闭通知。或者我想这里有Server Push协议,但是并没有得到普遍支持,服务工作者也是这样。

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

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

答案 2 :(得分:0)

您可以在下面尝试-

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

}

答案 3 :(得分:0)

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

作为Sprite组件的一部分,我有一个按时间间隔调度的Timer,为您提供了执行该操作的示例:

Sprite具有一个名为“订户”的属性

[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:

Sprite Properties

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

在我的Sprite组件的设置器中,我要做的第一件事是调用向父级注册:

[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事件,调用订阅服务器以刷新:

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

如果要查看完整的示例,请克隆该项目,并在samples文件夹中查找ProgressBarSample。

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

如果您想观看以下视频: https://youtu.be/frtetHgfdIo

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

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