[转]使用Blazor和SqlTableDependency进行实时HTML页面内容更新

2021-02-03 10:16:21 浏览数 (1)

原文:https://blog.csdn.net/mzl87/article/details/104264781

介绍

在这个简单的示例中,我们将看到发生在SQL Server数据库表更改时如何更新HTML页面,而无需重新加载页面或从客户端到服务器进行异步调用,而是从客户端获取此HTML刷新内容。服务器使用Blazor服务器端(.NET CORE 3.0)。

背景

之前,我发表了一篇有关“使用SignalR和SQLTableDependency进行记录更改的SQL Server通知”的文章。

上一篇文章使用了SignalR,以获取实时更改页面内容的通知。尽管功能正常,在我看来,SignalR不是那么直接和容易使用。

在Blazor的帮助下,从服务器到HTML页面的通知得到了极大的简化,从而获得了极好的抽象水平:使用Blazor——实际上——我们的代码只是C#和Razor语法。

使用代码

假设您有一个报告库存清单的页面,并且其中任何一种价格发生变化时,都需要刷新HTML页面。

SignalR之前,通常有一个使用Ajax 的JavaScript代码来定期(例如,每5秒一次)向服务器执行一个GET请求,以便检索可能的新价格并将其显示在HTML页面中。

如今,借助Blazor及其嵌入式SignalR功能,我们可以扭转这一趋势,并让服务器有责任仅在显示一些新价格时才更新HTML页面。

在下面的例子中,Blazor会负责更新HTML页面,而SqlTableDependency组件会负责在由于insert,update或delete而更改表内容时从SQL Server数据库获取通知:

我们必须使用Visual Studio 2019中的适当模板创建.NET CORE 3.0 Blazor Web应用程序。

然后,我们安装SqlTableDependency NuGet软件包,该软件包将负责获取有关记录表更改的通知:

代码语言:javascript复制
PM> Install-Package SqlTableDependency

现在,对于此示例,让我们考虑要监视以下SQL Server表的值:

代码语言:javascript复制
CREATE TABLE [dbo].[Stocks](
    [Code] [nvarchar](50) NULL,
    [Name] [nvarchar](50) NULL,
    [Price] [decimal](18, 0) NULL
) ON [PRIMARY]

因此,我们定义了一个C#模型类,该类映射了我们感兴趣的属性:

代码语言:javascript复制
namespace BlazorApp1.Models
{
    public class Stock
    {
        public decimal Price { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
    }
}

现在,我们创建一个SqlTableDependency单例实例,将记录表更改包装并转发到Blazor页面。我们开始创建其接口:

代码语言:javascript复制
using BlazorApp1.Models;
using System;
using System.Collections.Generic;
 
namespace BlazorApp1.Service
{
    public delegate void StockChangeDelegate(object sender, StockChangeEventArgs args);
 
    public class StockChangeEventArgs : EventArgs
    {
        public Stock NewValue { get; }
        public Stock OldValue { get; }
 
        public StockChangeEventArgs(Stock newValue, Stock oldValue)
        {
            this.NewValue = newValue;
            this.OldValue = oldValue;
        }
    }
 
    public interface ITableChangeBroadcastService : IDisposable
    {
        event StockChangeDelegate OnStockChanged;
        IList<Stock> GetCurrentValues();
    }
}

然后它实现:

代码语言:javascript复制
using BlazorApp1.Models;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using TableDependency.SqlClient;
using TableDependency.SqlClient.Base.EventArgs;
 
namespace BlazorApp1.Service
{
    public class TableChangeBroadcastService : ITableChangeBroadcastService
    {
        private const string TableName = "Stocks";
        private SqlTableDependency<Stock> _notifier;
        private IConfiguration _configuration;
 
        public event StockChangeDelegate OnStockChanged;
 
        public TableChangeBroadcastService(IConfiguration configuration)
        {
            _configuration = configuration;
 
            // SqlTableDependency will trigger an event 
            // for any record change on monitored table  
            _notifier = new SqlTableDependency<Stock>(
                 _configuration["ConnectionString"], 
                 TableName);
            _notifier.OnChanged  = this.TableDependency_Changed;
            _notifier.Start();
        }
 
        // This method will notify the Blazor component about the stock price change stock
        private void TableDependency_Changed(object sender, RecordChangedEventArgs<Stock> e)
        {
            this. OnStockChanged(this, new StockChangeEventArgs(e.Entity, e.EntityOldValues));
        }
 
        // This method is used to populate the HTML view 
        // when it is rendered for the first time
        public IList<Stock> GetCurrentValues()
        {
            var result = new List<Stock>();
 
            using (var sqlConnection = new SqlConnection(_configuration["ConnectionString"]))
            {
                sqlConnection.Open();
 
                using (var command = sqlConnection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM "   TableName;
                    command.CommandType = CommandType.Text;
 
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            while (reader.Read())
                            {
                                result.Add(new Stock
                                {
                                    Code = reader.GetString(reader.GetOrdinal("Code")),
                                    Name = reader.GetString(reader.GetOrdinal("Name")),
                                    Price = reader.GetDecimal(reader.GetOrdinal("Price"))
                                });
                            }
                        }
                    }
                }
            }
 
            return result;
        }
 
        public void Dispose()
        {
            _notifier.Stop();
            _notifier.Dispose();
        }
    }
}

现在我们已经设置了数据库记录更改通知,是时候实现Blazor组件了。第一步,我们检索OnInitialized()方法中的所有当前股价,然后我们订阅有关表记录更改的事件通知,以刷新HTML视图:

代码语言:javascript复制
@page "/"
@using BlazorApp1.Models
@using BlazorApp1.Service
 
@inject ITableChangeBroadcastService StockService
@implements IDisposable
 
<h1>Stock prices</h1>
 
<p>Immediate client notification on record table change with Blazor</p>
 
<table class="table">
    <thead>
        <tr>
            <th>Code</th>
            <th>Name</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var stock in stocks)
        {
            <tr>
                <td>@stock.Code</td>
                <td>@stock.Name</td>
                <td>@stock.Price</td>
            </tr>
        }
    </tbody>
</table>
 
@code {
    IList<Stock> stocks;
 
    protected override void OnInitialized()
    {
        // Subscription to table record change events
        this.StockService.OnStockChanged  = this.StockChanged;
        this.stocks = this.StockService.GetCurrentValues();
    }
 
    // The event handler, will update the HTML view according to new stock value
    private async void StockChanged(object sender, StockChangeEventArgs args)
    {
        var recordToupdate = this.stocks.FirstOrDefault(x => x.Code == args.NewValue.Code);
 
        if (recordToupdate == null)
        {
            this.stocks.Add(args.NewValue);
        }
        else
        {
            recordToupdate.Price = args.NewValue.Price;
        }
 
        await InvokeAsync(() =>
        {
            base.StateHasChanged();
        });
    }
 
    public void Dispose()
    {
        this.StockService.OnStockChanged -= this.StockChanged;
    }
}

表格记录更改事件处理程序仅检查库存是否在显示的列表中,然后插入或更新其Price值。请注意,HTML将从Blazor自动刷新。为了更新HTML视图内容,我们不需要向浏览器发送任何通知,也不需要从浏览器向服务器发出任何轮询请求。

总而言之,我们将依赖性解析定义为单例:

代码语言:javascript复制
namespace BlazorApp1
{
    public class Startup
    {
        …
        …
        public void ConfigureServices(IServiceCollection services)
        {
            …
            services.AddSingleton<ITableChangeBroadcastService, TableChangeBroadcastService>();
            …
        }
}

而且…别忘了设置数据库连接字符串!

代码语言:javascript复制
{
    "ConnectionString": "Data Source=***; initial catalog=***; User ID=sa;Password=***"
}

0 人点赞