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

目录

介绍

背景

使用代码


介绍

在这个简单的示例中,我们将看到发生在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组件会负责在由于insertupdatedelete而更改表内容时SQL Server数据库获取通知:

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

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

PM> Install-Package SqlTableDependency

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

CREATE TABLE [dbo].[Stocks](
    [Code] [nvarchar](50) NULL,
    [Name] [nvarchar](50) NULL,
    [Price] [decimal](18, 0) NULL
) ON [PRIMARY]

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

namespace BlazorApp1.Models
{
    public class Stock
    {
        public decimal Price { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
    }
}

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

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

然后它实现:

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视图:

@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视图内容,我们不需要向浏览器发送任何通知,也不需要从浏览器向服务器发出任何轮询请求。

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

namespace BlazorApp1
{
    public class Startup
    {
        …
        …
        public void ConfigureServices(IServiceCollection services)
        {
            …
            services.AddSingleton<ITableChangeBroadcastService, TableChangeBroadcastService>();
            …
        }
}

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

{
    "ConnectionString": "Data Source=***; initial catalog=***; User ID=sa;Password=***"
}

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Blazor是一个用C#构建Web应用程序的框架,因此它的登陆页面可以使用ASP.NET Identity或其他身份验证库来实现。 在Blazor应用程序中,可以使用Blazor Server或Blazor WebAssembly(WASM)来实现登陆页面Blazor Server是将C#代码运行在服务器上,并使用SignalR协议来与客户端交互;Blazor WebAssembly是将C#代码编译为WebAssembly二进制文件,并直接在客户端运行。 无论使用哪种模式,通常都需要在登陆页面中实现以下功能: 1. 输入用户名和密码,并在点击“登录”按钮时进行身份验证。 2. 显示错误消息,如果输入的用户名或密码不正确。 3. 如果身份验证成功,则将用户重定向到应用程序的主页。 以下是一个基本的Blazor登陆页面示例: ```html @page "/login" <h1>Login</h1> @if (errorMessage != null) { <div class="alert alert-danger">@errorMessage</div> } <form> <div class="form-group"> <label for="username">Username:</label> <input type="text" class="form-control" id="username" @bind-value="username"> </div> <div class="form-group"> <label for="password">Password:</label> <input type="password" class="form-control" id="password" @bind-value="password"> </div> <button type="submit" class="btn btn-primary" @onclick="Login">Login</button> </form> @code { private string username; private string password; private string errorMessage; private void Login() { // TODO: perform authentication // if authentication fails, set errorMessage to display error message // if authentication succeeds, redirect to main page // NavigationManager.NavigateTo("/main"); } } ``` 在这个示例中,我们定义了一个包含输入框和“登录”按钮的表单。当用户点击“登录”按钮时,我们调用Login方法来执行身份验证。如果身份验证失败,则设置errorMessage以显示错误消息。如果身份验证成功,则使用NavigationManager将用户重定向到应用程序的主页。 请注意,这只是一个基本示例,实际的Blazor登陆页面可能需要包含更多的功能和安全措施,例如防止跨站点请求伪造(CSRF)攻击,使用SSL加密通信,使用复杂密码策略等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值