无需Ajax且不刷新页面,如何更新交易列表GridView的新增/修改数据?
Got it, let's tackle your problem. You want your GridView to update in real-time without relying on traditional Ajax polling, supporting both incremental (new/modified records only) and full-load updates. Here are two solid approaches that fit your needs:
Instead of client-initiated Ajax calls, we’ll use server-push technologies to send database changes directly to the client as they happen. This ensures instant updates while avoiding repetitive polling. Below are practical implementations tailored for ASP.NET (since you mentioned GridView):
Approach 1: Using SignalR (Recommended)
SignalR is a mature library that simplifies real-time web communication, using WebSockets (or fallbacks like Server-Sent Events) to push updates from server to client. It’s perfect for your use case because it handles connection management and reconnections automatically.
Step 1: Set Up SignalR
- Install the SignalR NuGet package:
Install-Package Microsoft.AspNet.SignalR - Create a Hub class to manage communication:
using Microsoft.AspNet.SignalR; public class TransactionHub : Hub { // Server-side method to broadcast updates to all clients public void BroadcastTransactionUpdates(object transactionData, bool isFullLoad) { Clients.All.ReceiveTransactionUpdates(transactionData, isFullLoad); } } - Configure SignalR in your startup class:
using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(YourApp.Startup))] namespace YourApp { public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
Step 2: Trigger Updates on Database Changes
You need to notify SignalR whenever transactions are added or modified. Choose one of these methods:
- Business Logic Hooks: Call the SignalR hub from your service layer right after saving a transaction:
var hubContext = GlobalHost.ConnectionManager.GetHubContext<TransactionHub>(); // Send incremental update (only new/modified records) hubContext.Clients.All.ReceiveTransactionUpdates(newOrModifiedTransactions, isFullLoad: false); // Send full load (all top 100 records) when needed hubContext.Clients.All.ReceiveTransactionUpdates(fullTransactionList, isFullLoad: true); - Database Triggers: Create SQL triggers that call a stored procedure to notify your application of changes (good if updates happen outside your app).
- SQL Change Tracking: Use SQL Server’s built-in change tracking to periodically fetch modified records.
Step 3: Update GridView on the Client
Add SignalR scripts to your page and write JavaScript to handle incoming updates:
<script src="~/Scripts/jquery.signalR-2.4.3.min.js"></script> <script src="~/signalr/hubs"></script> <script> $(function () { var transactionHub = $.connection.transactionHub; // Client-side method to receive updates transactionHub.client.ReceiveTransactionUpdates = function (updatedData, isFullLoad) { var grid = $('#<%= YourGridView.ClientID %>'); if (isFullLoad) { // Replace entire GridView content grid.empty(); let tableHtml = '<thead><tr><th>ID</th><th>Amount</th><th>Date</th></tr></thead><tbody>'; updatedData.forEach(item => { tableHtml += `<tr data-id="${item.Id}"><td>${item.Id}</td><td>${item.Amount}</td><td>${item.TransactionDate}</td></tr>`; }); tableHtml += '</tbody>'; grid.html(tableHtml); } else { // Incremental update: add new rows or modify existing ones updatedData.forEach(item => { const existingRow = grid.find(`tr[data-id="${item.Id}"]`); if (existingRow.length) { // Update existing row values existingRow.find('td:eq(1)').text(item.Amount); existingRow.find('td:eq(2)').text(item.TransactionDate); } else { // Add new row to the top (keep latest records first) const newRow = `<tr data-id="${item.Id}"><td>${item.Id}</td><td>${item.Amount}</td><td>${item.TransactionDate}</td></tr>`; grid.find('tbody').prepend(newRow); // Trim to keep only top 100 records if (grid.find('tbody tr').length > 100) { grid.find('tbody tr:last').remove(); } } }); } }; // Start the SignalR connection $.connection.hub.start().done(() => { console.log('Real-time connection established'); }); }); </script>
Approach 2: Server-Sent Events (SSE)
If you prefer a lighter-weight, standards-based option without SignalR, SSE uses a persistent HTTP connection to push updates from server to client. It’s simpler to set up for basic use cases.
Step 1: Create an SSE Endpoint
Add an action method in your controller to send SSE events:
using Newtonsoft.Json; using System.Threading; public ActionResult TransactionStream() { Response.ContentType = "text/event-stream"; Response.CacheControl = "no-cache"; Response.BufferOutput = false; while (true) { // Check for new/modified transactions var updates = GetRecentTransactionChanges(); // Your custom method if (updates.Any()) { var payload = JsonConvert.SerializeObject(new { Data = updates, IsFullLoad = false }); Response.Write($"data: {payload}\n\n"); Response.Flush(); } // Periodically send full load (e.g., every 10 minutes) if (ShouldSendFullLoad()) // Your logic to trigger full load { var fullData = GetTop100Transactions(); var fullPayload = JsonConvert.SerializeObject(new { Data = fullData, IsFullLoad = true }); Response.Write($"data: {fullPayload}\n\n"); Response.Flush(); } Thread.Sleep(1000); // Wait 1 second before checking again } }
Step 2: Client-Side SSE Handling
Add JavaScript to listen for SSE events and update the GridView:
<script> const eventSource = new EventSource('@Url.Action("TransactionStream")'); eventSource.onmessage = function(event) { const update = JSON.parse(event.data); const grid = $('#<%= YourGridView.ClientID %>'); if (update.IsFullLoad) { // Replace entire GridView grid.empty(); let tableHtml = '<thead><tr><th>ID</th><th>Amount</th><th>Date</th></tr></thead><tbody>'; update.Data.forEach(item => { tableHtml += `<tr data-id="${item.Id}"><td>${item.Id}</td><td>${item.Amount}</td><td>${item.TransactionDate}</td></tr>`; }); tableHtml += '</tbody>'; grid.html(tableHtml); } else { // Incremental update logic (same as SignalR example) update.Data.forEach(item => { const existingRow = grid.find(`tr[data-id="${item.Id}"]`); if (existingRow.length) { existingRow.find('td:eq(1)').text(item.Amount); existingRow.find('td:eq(2)').text(item.TransactionDate); } else { const newRow = `<tr data-id="${item.Id}"><td>${item.Id}</td><td>${item.Amount}</td><td>${item.TransactionDate}</td></tr>`; grid.find('tbody').prepend(newRow); if (grid.find('tbody tr').length > 100) { grid.find('tbody tr:last').remove(); } } }); } }; // Handle connection errors and reconnection eventSource.onerror = function(error) { console.error('SSE connection failed:', error); eventSource.close(); // Reconnect after 5 seconds setTimeout(() => { eventSource = new EventSource('@Url.Action("TransactionStream")'); }, 5000); }; </script>
Key Tips for Success
- Performance: For incremental updates, only fetch records modified since the last update (use a timestamp or max ID filter to avoid full table scans).
- Security: Ensure only authorized users can receive updates. SignalR supports authentication, and SSE uses your app’s existing auth system.
- Initial Load: Load the first 100 transactions when the page renders, then rely on server-push for updates.
内容的提问来源于stack exchange,提问作者Balu Sidhartha

