(这是一个Q /A风格的问题,是提出类似问题的人们的首选资源。很多人似乎迷失了最佳方法,因为他们不知道所有选择许多答案将特定于ASP.NET,但是AJAX和其他技术在其他框架中确实具有等效功能,例如socket.io和SignalR。)
我有一个在ASP.NET中实现的数据表。我想在页面上实时或接近实时显示对此基础数据的更改。我该怎么办?
我的模特:
public class BoardGame { public int Id { get; set;} public string Name { get; set;} public string Description { get; set;} public int Quantity { get; set;} public double Price { get; set;} public BoardGame() { } public BoardGame(int id, string name, string description, int quantity, double price) { Id=id; Name=name; Description=description; Quantity=quantity; Price=price; } }
代替此示例的实际数据库,我将把数据存储在Application变量中。我将其Application_Start植入我的Global.asax.cs函数中。
Application_Start
var SeedData = new List<BoardGame>(){ new BoardGame(1, "Monopoly","Make your opponents go bankrupt!", 76, 15), new BoardGame(2, "Life", "Win at the game of life.", 55, 13), new BoardGame(3, "Candyland", "Make it through gumdrop forrest.", 97, 11) }; Application["BoardGameDatabase"] = SeedData;
如果使用的是Web窗体,则将使用中继器显示数据。
<h1>Board Games</h1> <asp:Repeater runat="server" ID="BoardGameRepeater" ItemType="RealTimeDemo.Models.BoardGame"> <HeaderTemplate> <table border="1"> <tr> <th>Id</th> <th>Name</th> <th>Description</th> <th>Quantity</th> <th>Price</th> </tr> </HeaderTemplate> <ItemTemplate> <tr> <td><%#: Item.Id %></td> <td><%#: Item.Name %></td> <td><%#: Item.Description %></td> <td><%#: Item.Quantity %></td> <td><%#: Item.Price %></td> </tr> </ItemTemplate> <FooterTemplate></table></FooterTemplate> </asp:Repeater>
并在后面的代码中加载该数据:
protected void Page_Load(object sender, EventArgs e) { BoardGameRepeater.DataSource = Application["BoardGameDatabase"]; BoardGameRepeater.DataBind(); }
如果这是使用Razor的MVC,那只是对模型的简单介绍:
@model IEnumerable<RealTimeDemo.Models.BoardGame> <h1>Board Games</h1> <table border="1"> <tr> <th> @Html.DisplayNameFor(model => model.Id) </th> <th> @Html.DisplayNameFor(model => model.Name) </th> <th> @Html.DisplayNameFor(model => model.Description) </th> <th> @Html.DisplayNameFor(model => model.Quantity) </th> <th> @Html.DisplayNameFor(model => model.Price) </th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.Id) </td> <td> @Html.DisplayFor(modelItem => item.Name) </td> <td> @Html.DisplayFor(modelItem => item.Description) </td> <td> @Html.DisplayFor(modelItem => item.Quantity) </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> </tr> } </table>
让我们使用Web窗体有一个小页面来添加数据,这样我们就可以实时查看数据更新。我建议您创建两个浏览器窗口,以便可以同时看到表单和表格。
<h1>Create</h1> <asp:Label runat="server" ID="Status_Lbl" /><br /> Id: <asp:TextBox runat="server" ID="Id_Tb" /><br /> Name: <asp:TextBox runat="server" ID="Name_Tb" /><br /> Description: <asp:TextBox runat="server" ID="Description_Tb" /><br /> Quantity: <asp:TextBox runat="server" ID="Quantity_Tb" /><br /> Price: <asp:TextBox runat="server" ID="Price_Tb" /><br /> <asp:Button runat="server" ID="SubmitBtn" OnClick="SubmitBtn_Click" Text="Submit" />
以及后面的代码:
protected void SubmitBtn_Click(object sender, EventArgs e) { var game = new BoardGame(); game.Id = Int32.Parse(Id_Tb.Text); game.Name = Name_Tb.Text; game.Description = Description_Tb.Text; game.Quantity = Int32.Parse(Quantity_Tb.Text); game.Price = Int32.Parse(Price_Tb.Text); var db = (List<BoardGame>)Application["BoardGameDatabase"]; db.Add(game); Application["BoardGameDatabase"] = db; //only for SignalR /*var context = GlobalHost.ConnectionManager.GetHubContext<GameHub>(); context.Clients.All.addGame(game); */ }
这是我最高兴分享的答案,因为它代表了一种更简洁的实现,它是轻量级的,并且在当今的移动(数据受限)环境中运行良好。
多年来,已经有几种方法可以提供从服务器到客户端的“实时”数据推送(或推送数据的外观)。快速短轮询(类似于基于AJAX的答案),长轮询,永远帧,服务器发送事件和WebSocket是用于实现此目的的不同传输机制。SignalR是一个抽象层,能够根据客户端和服务器的能力选择适当的传输机制。使用SignalR最好的部分是它很简单。您不必担心传输机制,并且编程模型易于理解。
我将定义一个SignalR集线器,但将其保留为空。
public class GameHub : Hub { }
当我将数据添加到“数据库”时,我将运行以下代码。如果您阅读了该问题,您会看到我在“创建”表单中将其注释掉了。您将无需对此发表评论。
var context = GlobalHost.ConnectionManager.GetHubContext<GameHub>(); context.Clients.All.addGame(game);
这是我的页面代码:
<h1>SignalR</h1> <asp:Repeater runat="server" ID="BoardGameRepeater" ItemType="RealTimeDemo.Models.BoardGame"> <HeaderTemplate> <table border="1"> <thead> <tr> <th>Id</th> <th>Name</th> <th>Description</th> <th>Quantity</th> <th>Price</th> </tr> </thead> <tbody id="BoardGameTblBody"> </HeaderTemplate> <ItemTemplate> <tr> <td><%#: Item.Id %></td> <td><%#: Item.Name %></td> <td><%#: Item.Description %></td> <td><%#: Item.Quantity %></td> <td><%#: Item.Price %></td> </tr> </ItemTemplate> <FooterTemplate></tbody></table></FooterTemplate> </asp:Repeater> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="Scripts/jQuery-1.6.4.min.js"></script> <script src="Scripts/jquery.signalR-2.1.1.min.js"></script> <script src="signalr/hubs"></script> <script type="text/javascript"> var hub = $.connection.gameHub; hub.client.addGame = function (game) { $("#BoardGameTblBody").append("<tr><td>" + game.Id + "</td><td>" + game.Name + "</td><td>" + game.Description + "</td><td>" + game.Quantity + "</td><td>" + game.Price + "</td></tr>"); }; $.connection.hub.start(); </script>
注意这里发生了什么。当服务器调用时,context.Clients.All.addGame(game);它正在执行hub.client.addGame为连接到GameHub的每个客户端分配的功能。SignalR负责为我整理事件,并自动将game服务器上的game对象转换为客户端上的对象。最重要的是,每隔几秒钟就没有来回的网络流量,因此它的重量非常轻。
context.Clients.All.addGame(game);
hub.client.addGame
game
优点:
请注意,您可以在客户端上添加一个功能,editedGame用于轻松将更改的数据推送到客户端(与删除相同)。
editedGame