我有一个转发器,显示各种股票的财务数据和价格。
在这个页面上,我还有一个“导出”按钮,需要在屏幕上显示数据〜并将其转换为用户的CSV。
问题是,在我对“Stock”实体列表进行了数据绑定之后:
List<Stock> stocks = GetStocks()
rptStockList.DataSource = stocks;
rptStockList.DataBind();
数据不会在回发中保留。
此外,此页面上的数据通过UpdatePanel和Timer控件(每次都重新数据绑定)不断更新。每隔30秒,转发器控件中各种股票显示的价格会发生变化。
现在,我有一个链接按钮,它在代码隐藏中有一个单击事件方法,可以在屏幕上为用户导出〜数据。我需要获取最后数据绑定到转发器的股票列表的当前值。我不能简单地从数据库中获取最新值,因为这些值将在上次刷新之间的时间内更改。
protected void lbtnExportStocks_Click(object sender, EventArgs e)
{
// No longer have the stock data used in the repeater control
ExportStocksToExcel();
}
我知道ASP.NET不会在post-back上保留转发器的数据源,但是我仍然需要重新构建这个Stock实体列表,这样我就可以发送CSV或者我需要持久化它在某种程度上。
我不想做任何在性能方面过于繁重的事情,因为在一周的某些日子里,这个应用程序可能会有大量使用。
这种情况的正确解决方案是什么?我应该遍历Repeater的“Items”集合并重建Stock实体吗?
答案 0 :(得分:1)
您可以将stocks
存储在Viewstate或Session中吗? e.g。
List<Stock> stocks = GetStocks()
rptStockList.DataSource = stocks;
rptStockList.DataBind();
ViewState.Remove("stocks");
ViewState.Add("stocks", stocks);
private void ExportStocksToExcel
{
List<Stock> persistedStocks;
persistedStocks = (List<Stock>)Page.ViewState["stocks"];
...
}
会话状态实际上可能是存储Stocks
的更好选择,因为它不会传输到页面中的客户端(可能需要“创造性编辑”的所有可能性) - 这可能非常重要在这样的应用程序中。 (是的,您可以加密Viewstate,但要关注那些您可能不想要的高峰时间。)
答案 1 :(得分:1)
一种简单的方法是将值呈现为输入控件(而不是<span>
或裸<td>
元素) - 浏览器在用户发布时将输入值发送回服务器。
例如:
<ItemTemplate>
Symbol: <input type="text" readonly="readonly" name="Symbol" value="<%# Container.DataItem("Symbol") %> />
Quote: <input type="text" readonly="readonly" name="Quote" value="<%# Container.DataItem("Quote") %> />
</ItemTemplate>
客户端在数组中发送名为“Symbol”的每个输入值(以及名为“Quote”的输入值),您可以在代码隐藏中访问,如下所示:
protected void lbtnExportStocks_Click(object sender, EventArgs e) {
// They come out as comma-delimited strings
string[] symbols = Request.Form["Symbol"].Split(',');
string[] quotes = Request.Form["Quote"].Split(',');
// ... continue exporting stocks to Excel
}
当然,在底部,这种技术基本上是编写客户端发送给Excel文件的任何内容,因此您可能希望以某种方式保护或限制输入。这可能涉及对用户进行身份验证和/或限制方法将导出的数据量。如果这是您环境中的一个严重问题,或者您无法给予太多关注,请考虑在用户会话中序列化原始数据。
同样,如果您故意传输大量数据,则出于性能原因应考虑使用其他方法。您可以使用会话,或者传输可用于重建用于构建转发器的数据的小键(例如,如果转发器绑定到查询的结果,而该查询的结果不会因为其输入而改变,则可以在调用之间序列化输入。)
答案 2 :(得分:0)
听起来像在你的Page_Load方法中,你正在对你的转发器进行某种绑定。出于您的目的,这很糟糕,正如您所看到的,它将在每次回发时将您的数据分开。你能确定你的Page_Load是这样的吗? :
Page_Load(...){
if (! Page.IsPostBack){
//first time page loads do this block
//stuff
//databinding stuff
}
}
答案 3 :(得分:0)
我要么接受Phil的答案并序列化整个数据集,要么创建某种标准对象,传递给GetStocks()以指定要获取的数据。然后在ViewState中序列化并存储条件对象,因此当用户单击“导出”时,您可以提取条件并检索相同的数据。
即,
[Serializable]
public class StockCriteria
{
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public string[] Symbols { get; set; }
}
然后GetStocks()将StockCriteria作为参数并基于它创建查询。