You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET C# Razor Pages实现PostgreSQL数据无刷新实时更新

实现ASP.NET Razor Pages + PostgreSQL实时数据更新(无需页面刷新)

嘿,我明白你现在的困境——PostgreSQL的LISTEN/NOTIFY确实是实现实时更新的核心,但把它和Razor Pages结合起来的完整示例确实不多。下面我会一步步帮你把现有代码改成支持实时更新的版本,用SignalR处理前端实时推送,配合PostgreSQL的通知机制搞定这个需求。

第一步:配置PostgreSQL的NOTIFY触发器

首先得让PostgreSQL在notification表有新数据插入时主动发通知。你可以在数据库里执行以下SQL:

-- 创建发送通知的函数
CREATE OR REPLACE FUNCTION notify_new_notification()
RETURNS TRIGGER AS $$
BEGIN
  -- 把新插入的数据转为JSON作为通知内容,方便后端直接使用
  PERFORM pg_notify('new_notification', row_to_json(NEW)::text);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 创建触发器,插入新数据时自动触发上面的函数
CREATE TRIGGER trigger_new_notification
AFTER INSERT ON notification
FOR EACH ROW EXECUTE FUNCTION notify_new_notification();

这样每次有新数据插入notification表,PostgreSQL就会向new_notification频道发送包含新数据的JSON消息。

第二步:给Razor Pages项目添加SignalR

SignalR是ASP.NET里处理实时双向通信的最佳工具,我们用它把PostgreSQL的通知推送到前端。

  1. 先安装SignalR的NuGet包:
Install-Package Microsoft.AspNetCore.SignalR
  1. 创建一个SignalR Hub类(比如NotificationHub.cs):
using Microsoft.AspNetCore.SignalR;

public class NotificationHub : Hub
{
    // 这里暂时留空,主要用来管理客户端连接和推送消息
}
  1. 在Program.cs里注册SignalR服务并配置端点:
var builder = WebApplication.CreateBuilder(args);

// 注册SignalR服务
builder.Services.AddSignalR();

// 保留你原有的其他服务注册代码...

var app = builder.Build();

// 保留你原有的中间件配置代码...

// 配置SignalR的访问端点
app.MapHub<NotificationHub>("/notificationHub");

app.Run();

第三步:后端监听PostgreSQL通知并推送消息

我们需要一个后台服务持续监听PostgreSQL的通知,收到通知后通过SignalR推送给所有在线客户端。

创建后台服务类PostgresNotificationListener.cs:

using Microsoft.AspNetCore.SignalR;
using Npgsql;

public class PostgresNotificationListener : BackgroundService
{
    private readonly IHubContext<NotificationHub> _hubContext;
    private readonly string _connectionString;

    public PostgresNotificationListener(IHubContext<NotificationHub> hubContext, IConfiguration configuration)
    {
        _hubContext = hubContext;
        // 这里可以用你原有的Database.Connector()获取连接字符串,或者从配置文件读取
        _connectionString = configuration.GetConnectionString("PostgresConnection") ?? Database.Database.Connector();
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using var conn = new NpgsqlConnection(_connectionString);
        await conn.OpenAsync(stoppingToken);

        // 监听我们之前创建的PostgreSQL通知频道
        await conn.ExecuteAsync("LISTEN new_notification;", cancellationToken: stoppingToken);

        // 绑定通知接收事件
        conn.Notification += async (sender, e) =>
        {
            if (!stoppingToken.IsCancellationRequested)
            {
                // 把收到的新数据推送给所有连接的客户端
                await _hubContext.Clients.All.SendAsync("ReceiveNewNotification", e.Payload, stoppingToken);
            }
        };

        // 保持连接,直到服务停止
        while (!stoppingToken.IsCancellationRequested)
        {
            await conn.WaitAsync(stoppingToken);
        }
    }
}

然后在Program.cs里注册这个后台服务:

builder.Services.AddHostedService<PostgresNotificationListener>();

第四步:修改Razor Page代码实现实时更新

首先调整你的PageModel,把数据查询改成异步方法,方便复用:

public class YourPageModel : PageModel
{
    // 保留你原有的其他代码...

    public async Task<List<NotificationModel>> ShowNotificationAsync()
    {
        var cs = Database.Database.Connector();
        List<NotificationModel> not = new List<NotificationModel>();
        using var con = new NpgsqlConnection(cs);
        await con.OpenAsync();
        string query = "Select datumnu, bericht FROM notification ORDER BY datumnu DESC OFFSET 1";
        using NpgsqlCommand cmd = new NpgsqlCommand(query, con);
        using (NpgsqlDataReader dr = await cmd.ExecuteReaderAsync())
        {
            while (await dr.ReadAsync())
            {
                not.Add(new NotificationModel
                {
                    Datenow = ((DateTime)dr["datumnu"]).ToString("yyyy/MM/dd"),
                    Bericht = dr["bericht"].ToString()
                });
            }
        }
        return not;
    }

    public async Task OnGetAsync()
    {
        // 页面初始加载时获取数据
        ViewData["Notifications"] = await ShowNotificationAsync();
    }
}

然后修改HTML页面,添加SignalR的JS逻辑,实现实时更新表格:

<div class="container-fluid">
    <p id="output"></p>
    <div class="col-3 bg-light">
        <h5 class="font-italic text-left">Old Messages</h5>
        <hr>
        <table id="notificationTable">
            @foreach(var n in (List<NotificationModel>)ViewData["Notifications"])
            {
                <tr>
                    <td><img class="img-fluid" src="/Images/Reservation.png"/></td>
                    <td>@Html.DisplayFor(m => n.Datenow)</td>
                    <td>@Html.DisplayFor(m => n.Bericht)</td>
                </tr>
            }
        </table>
        <hr>
    </div>
</div>

<!-- 引入SignalR的JS库 -->
<script src="~/lib/microsoft/signalr/dist/browser/signalr.min.js"></script>
<script>
    // 创建SignalR连接实例
    const connection = new signalR.HubConnectionBuilder()
        .withUrl("/notificationHub")
        .build();

    // 接收后端推送的新通知
    connection.on("ReceiveNewNotification", function (payload) {
        // 解析PostgreSQL发来的JSON数据
        const newNotification = JSON.parse(payload);
        // 格式化日期为yyyy/MM/dd格式
        const formattedDate = new Date(newNotification.datumnu).toLocaleDateString('en-US', { 
            year: 'numeric', 
            month: '2-digit', 
            day: '2-digit' 
        }).replace(/\//g, '/');
        
        // 往表格最前面插入新行(和你的查询排序逻辑一致)
        const table = document.getElementById("notificationTable");
        const newRow = table.insertRow(0);
        const cell1 = newRow.insertCell(0);
        const cell2 = newRow.insertCell(1);
        const cell3 = newRow.insertCell(2);
        
        cell1.innerHTML = '<img class="img-fluid" src="/Images/Reservation.png"/>';
        cell2.textContent = formattedDate;
        cell3.textContent = newNotification.bericht;
    });

    // 启动SignalR连接,失败自动重试
    async function startConnection() {
        try {
            await connection.start();
            console.log("SignalR连接成功");
        } catch (err) {
            console.error(err);
            setTimeout(startConnection, 5000);
        }
    }

    // 页面加载时启动连接
    startConnection();

    // 页面关闭时断开连接
    window.addEventListener("beforeunload", function () {
        connection.stop();
    });
</script>

一些注意事项

  • 确保你的NotificationModel类属性和PostgreSQL表字段对应,避免解析数据时出错。
  • 如果不想推送完整数据,也可以让PostgreSQL只发一个"更新信号",前端收到后调用API拉取最新列表,这种方式更简单但实时性稍弱。
  • 后台服务里已经处理了基本的连接重连逻辑,你可以根据需要添加更多异常处理。

内容的提问来源于stack exchange,提问作者anonD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:37:21