1
votes

I'm close to going live with this web app but still have one glaring problem, which is wrong data in gridviews after the user uses the back button. This is another mastersearch/detail type page. Users search for items, which show in a gridview on page search.aspx. Users can click on items to go to the detail page, itemdetails.aspx. All works fine until users use the back button.

Example, search for dog, get a list of dogs in gridview on search.aspx. Click dog records and see their details on itemdetails.aspx. Search for cats, get a list of cats on gridview in search.aspx. Click cats to see details, use back to go back to the search.aspx with list of cats, click another cat to see details. All is fine so far. Problems start when users go back a few times, from cat detail to cat search resutlts, back to dog detail, then back to dog search results. Now if user clicks the dog in search results row 3, the detail page that is displayed is the cat from row 3 in the most recent search.

I've tried clearing the cache, this forces the grid to reload but the user always sees the page expired page and has to resubmit the data. I've tried Server.Transfer and Response.Redirect to the search page to try to reload the grid, but this makes the user have to click the record twice(once to reload the expired grid, then again to go to the details.) Also tried rebinding grid, and so many other things over 4-5 or so days, I don't remember them all. Nothing has fixed the problem without creating and unexpected side effect. At this point I just want a solution, even if I have to rewrite the whole thing. Thanks for any suggestions!

public partial class Search : System.Web.UI.Page { public string searchString;//for info typed in search box public string searchISBN;//to hold clicked item in gridview ISBN

private void GetProducts()
{
    try
    {
        DataSet ds = DataAccess.GetProductsPerCategory(searchString);
        GridView1.DataSource = ds;
        GridView1.DataBind();
    }
    catch (SqlException ex)
    {

        lblSearch.Text = "Cannot get product data." + ex.Message;
    }
}


protected void Button2_Click(object sender, EventArgs e)
    //button in gridview, sends to item detail page
{
    LinkButton btn = (LinkButton)(sender);
    searchISBN = btn.CommandArgument;
    //call product detail page, pass ISBN
    Global.SetISBNData = searchISBN;
    Server.Transfer("ItemDetail.aspx");
}

//when this search page is called from site.master page,
//search criteria passed to GetProducts
protected void Page_Load(object sender, EventArgs e)
{
     if (IsExpired())
    {
        Response.Redirect("Expired.aspx");
    }
    else
    {
       this.SaveTimeStamps();
        searchString = Global.GetSearchData;
        GetProducts();
    }
}

private bool IsExpired()
{
    if (Session["Search_SearchStamp"] == null)
        return false;
    else if (ViewState["SearchStamp"] == null)
        return false;
    else if (ViewState["SearchStamp"].ToString() ==
            Session["Search_SearchStamp"].ToString())
        return false;
    else
        return true;

}

private void SaveTimeStamps()
{
    DateTime dtm = DateTime.Now;
    ViewState.Add("SearchStamp", dtm);
    Session.Add("Search_SearchStamp", dtm);
 }

}

2
how are you storing data between pages? Are you using cookies or coding search parameters in the URL? I'd recommend URL as cookies can expire or be overwritten.Benjamin Danger Johnson
The search criteria are stored in global variables. The search term is put into a global variable Global.Searchdata. on pageload of search.aspx the variable is retrieved and passed as a parameter to a sql statement that in the end fills the grid. Similar with the itemdetail criteria. When the link button for the item is clicked the command arqument of the control is put into global variable ISBNData. ItemDetail.aspx retrieves the value and displays that record.user1706348

2 Answers

0
votes

The answer had been right in front of me the whole time, just needed to put 2 and 2 together.

I moved statements in page_load to protected override void OnInit(EventArgs e) and it has cleared things up.

I tested through 5 levels of searches then used the back button to go back to the original search. Clicking the items in the original gridview(or anywhere in between)goes to the correct detail record. Thanks to all the info and tips on stack overflow, this one is solved!

0
votes

Taking from Danger's advice I've come up with a more dependable solution. Apparently things have changed greatly since I took asp.net in college way back in 07(imagine that!) Anyway I found that if you use url parameters, things work much better in this scenario. Just the right sequence of events would cause glitches when using global variables and statements in On Init. Now with parameterized urls, on back button use, apparently the grids are always refreshed. From my Murach's book - pages for which coded hyperlinks are used are always processed as if it's being requested for the first time. Updated code below. An added bonus is this approach allows for direct linking to my products or search result sets.

//masterpage search button click
protected void btnMasterSearch_Click(object sender, EventArgs e)
    {
        //input is from the user's entry in text box
        string input = txtMasterSearch.Text;
        //result is filtered by regex then added to url for search
        string result = Regex.Replace(input, @"[^\w\.@-]", "");
        try
    {
        if (String.IsNullOrEmpty(result))
        {
            throw new ArgumentException("Null is not allowed");
        }
        else
        {
            Response.Redirect("Search.aspx?search=" + result);
        }
//search.aspx
public partial class Search : System.Web.UI.Page
{
    public string productparam;//product parameter to add to url
    public string searchparam;//search parameter from url
protected void Page_Load(object sender, EventArgs e)
    {
              searchparam = Request.QueryString["search"];
              GetProducts();
    }
private void GetProducts()
    {
        try
        {
            DataSet ds = DataAccess.GetProductsPerCategory(searchparam);
            GridView1.DataSource = ds;
            GridView1.DataBind();
        }
        catch (SqlException ex)
        {
        lblSearch.Text = "Cannot get product data." + ex.Message;
        }
    }
protected void Button2_Click(object sender, EventArgs e)
        //button in gridview, sends to item detail page
    {
        LinkButton btn = (LinkButton)(sender);
        productparam = btn.CommandArgument;
        Server.Transfer("ItemDetail.aspx?product=" + productparam);
    }
//item detail page
public partial class ItemDetail : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            lblISBN.Text = Request.QueryString["product"];
        }
        catch (Exception ex)
        {
        lblISBN.Text = "Cannot get product data." + ex.Message;
        }
    }
 }