页面刷新与IsPostBack区别

5
我有一个索引页面,可以将用户发送到单独的浏览器选项卡上的编辑产品页面。
对于每个被编辑的产品,索引页面都会重写Session["ProductID"]。
编辑页面然后具有以下代码,以获得此选项卡和产品的唯一标识符:
if (!IsPostBack) //first time page load
{
    Random R = new Random(DateTime.Now.Millisecond + DateTime.Now.Second * 1000 + DateTime.Now.Minute * 60000 + DateTime.Now.Minute * 3600000);
    PageID.Value = R.Next().ToString();

    Session[PageID.Value + "ProductID"] = Session["ProductID"];
}

这个方法能够正常工作,而且当同一个用户打开多个标签页时,我只用引用Session[PageID.Value + "ProductID"]来获取正确的ID,(由于这是内部网站,我不会太在意安全级别)。
我的问题出现在用户按下F5键进行页面刷新时。此时,Session[PageID.Value + "ProductID"]将获取他最后打开的产品的Session["ProductID"]。
例如:
用户1在标签页1中打开产品1
用户1在标签页2中打开产品2
在正常使用工具时,一切都正常。但是如果:
用户1在产品1页面上点击刷新按钮(F5),产品1页面会变成产品2页面。
有没有办法识别“从其他页面首次加载/重定向”的页面刷新,以便我可以告诉我的页面不要更新Session[PageID.Value + "ProductID"]?

值得快速测试一下,测试 Request.Headers["HttpReferer"] 是否存在。 - Peter Taylor
我尝试使用Request.UrlReferrer.ToString(),当我第一次加载页面时,我得到了Index页面作为引用页。不幸的是,如果我使用F5刷新页面,我仍然会得到Index页面。唯一改变引用页的方法是在Edit页面上进行postback,然后引用页变成了Edit页面。 - LanFeusT
3个回答

4

个人而言,我会选择使用URL参数。例如,将产品ID作为URL参数传递。

如果您需要没有参数的页面,您可以:

  1. 将参数传递到页面。
  2. 如果参数存在,则页面重新加载并删除参数

这样,您就可以区分第一次调用(=参数存在)和第二次及以后的调用(参数不存在)。


我明白了,但是如果我重新加载页面,我的Session[PageID.Value + "ProductID"]将会消失。如果我检查查询字符串以获取ID并且字符串不存在,我该怎么办?如果我保留字符串,任何人都可以更改查询字符串的ID并访问他们不应该访问的内容。或者我理解你的意思有误吗? - LanFeusT
关于您的“访问不应访问的内容”问题:我通常会在数据库中实现这样的场景,使用权限表(例如,“是否有权访问产品1”),并检查已登录用户对所请求产品页面的页面权限。 - Uwe Keim

3

我曾经通过存储两个版本的状态标识参数(一个在Session中,另一个在ViewState或URL(QueryString)中)解决了一个非常相似的问题。

如果在Page_Load中比较这两个值,那么就可以判断自页面第一次加载以来会话变量是否已更改。这应该正是你需要的。

编辑:代码草图(警告-自三年前编写以来未看到实际代码):

protected string currentProductID
{
    get
    {
        return Request.QueryString["ProductID"];
        //or: 
        //return (string)ViewState["ProductID"];
        //or:
        //return HiddenField1.Value;
    }
    set
    {
        Response.Redirect(ResolveUrl("~/MyPage.aspx?ProductID=" + value));
        //or:
        //ViewState.Add("ProductID", value);
        //or: 
        //HiddenField1.Value = value;
    }
}

protected void Page_Load(object sender, EventArgs e)
{
    //If the problem only occurs when not posting back, wrap the below in
    // an if(!IsPostBack) block. My past issue occurred on both postbacks
    // and page refreshes.

    //Note: I'm assuming Session["ProductID"] should never be null.

    if (currentProductID == null)
    {
        //Loading page for the first time.
        currentProductID = (string)Session["ProductID"];
    }
    else if (currentProductID != Session["ProductID"])
    {
        //ProductID has changed since the page was first loaded, so react accordingly. 
        //You can use the original ProductID from the first load, or reset it to match the one in the Session.
        //If you use the earlier one, you may or may not want to reset the one in Session to match.
    }
}

在上面的代码中,请注意ViewState的更改(包括Hidden控件的值)只会在下一次PostBack时生效。刷新后,它们会恢复到最近的值。在我的情况下,那正是我想要的,但听起来对于你的情况不太合适。不过,根据您实现此操作的方式,这些信息可能对您有用。
我没有讨论比较currentProductID和Session [PageID.Value +“ProductID”]的细节,因为我已经发布了很多代码,我也不知道您试图做什么。但是,您可以使用Session、ViewState和QueryString等各种方法来获取有关页面状态和历史记录的信息。
希望这应该能给你一个大概的想法。如果这还不足以让您开始,请告诉我。

1
我有点明白你的意思,但不确定如何实现。你有一些代码或其他东西可以供我参考吗?谢谢! - LanFeusT
感谢您的代码。不幸的是,它似乎没有捕捉到刷新。当前的ProductID在页面第一次加载时为null,然后获取ProductID会话的值。但是当我按下F5或重新加载页面时,该值被重置为null,总是返回第一个if语句。 - LanFeusT
@LanFeusT:你是使用ViewState还是URL查询字符串?无论在URL中的内容应该在刷新时可用。有没有可能在代码中重置它? - Justin Morgan
我正在尝试使用ViewState,因为我不想在URL中看到产品ID。 - LanFeusT
@LanFeusT 不好意思我花了一些时间才注意到你的最后一条评论。如果是我,我会重新考虑将其放在URL中 - 可以放在查询字符串中或者路径的某个地方,也可以使用URL重写。这似乎是最好的方法,而且在我看来GET参数的使用是合适的。亚马逊也是这样做的,这让我很有信心。否则,我可能会选择mjw06d的链接。 - Justin Morgan
我正在研究URL重写,是的,我可能会选择这种方式。非常感谢你的所有帮助! - LanFeusT

2
您可能想看一下this。我认为它接近您所要寻找的内容。

那可能会起作用,尽管我想找到一个C#的解决方案。最坏的情况下,我会回到这个,谢谢! - LanFeusT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接