Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I persist the data from a repeater after postback?

I have a repeater that displays financial data and prices for various stocks.

On this page, I also have an "export" button that needs to take the data ~on the screen~ and convert it into a CSV for the user.

The problem is, after I databind my list of "Stock" entities:

List<Stock> stocks = GetStocks()
rptStockList.DataSource = stocks;
rptStockList.DataBind();

The data is not persisted on postback.

Also, the data on this page is constantly being updated via an UpdatePanel and a Timer control (being re-databound each time). Every 30 seconds the prices displayed for the various stocks in the repeater control change.

Now, I have a linkbutton that has a click event method in the code-behind that is supposed to export the ~data on the screen~ for the user. I need to grab the current values for the list of stocks last databound to the repeater. I can't simply go grab the latest values from the database because those will have been changed in the time between the last refresh.

protected void lbtnExportStocks_Click(object sender, EventArgs e)
{
    // No longer have the stock data used in the repeater control
    ExportStocksToExcel();
}

I know that ASP.NET doesn't persist the datasource for the repeater on post-back but I need to still be able to either re-construct this list of Stock entities so I can send them the CSV or I need persist it in some way.

I don't want to do anything that is too heavy handed in terms of performance because during certain days of the week this application can have some heavy usage.

What is the proper solution to this type of situation? Should I iterate through the Repeater's "Items" collection and reconstruct the Stock entities?

like image 971
Darwin Avatar asked Jul 01 '10 18:07

Darwin


2 Answers

Could you store stocks in Viewstate, or in 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"];
    ...
}

Session state may actually be the better choice for storing Stocks since that won't get transmitted to the client in the page (with all the possibilities for 'creative editing' that could entail) - that's probably quite important in an application like this. (Yes, you could encrypt the Viewstate but with an eye on those peak times that's an overhead you might not want.)

like image 83
PhilPursglove Avatar answered Nov 13 '22 01:11

PhilPursglove


A simple method is to render the values as input controls (as opposed to, say, <span> or bare <td> elements) - the browser sends input values back to the server when the user posts.

For example:

<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>

The client sends every input value named "Symbol" in an array (and likewise the input values named "Quote"), which you can access in your code-behind like this:

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
}

Of course, at the bottom, this technique is basically writing whatever the client sends you to an Excel file, so you might want to secure or limit the input in some way. That might involve authenticating users and/or throttling the amount of data your method will export. If this is a serious concern in your environment or you can't afford to give it much attention, consider serializing the original data in the user's session instead.

Similarly, if you're intentionally transmitting a large amount of data, you should consider using other approaches for performance reasons. You might use session instead, or or transmit a small key that you can use to reconstruct the data used to build the repeater (for example, if the repeater was bound to the results of a query that doesn't change given its inputs, you can just serialize the input(s) between calls).

like image 37
Jeff Sternal Avatar answered Nov 12 '22 23:11

Jeff Sternal