2017-04-24 149 views
1

在我的应用程序中,我将对象存储到会话中,该会话被传递给Web服务以返回数据以显示在表中。如果会话存在,则它不会要求用户输入新的数据。但是,如果用户选择一个名为“新列表”的链接,则会话数据将被清除,并且用户提示输入新数据。c#mvc:RedirectToAction()和浏览器导航按钮

在我的代码,我已经定义了以下这样一个锚:

<a href="@Url.Action("NewList", "Alert")"> New List</a> 

将触发此控制器操作:

public ActionResult NewList() 
{ 
    Session["new_list"] = "y"; 
    return RedirectToAction("List"); 
} 

然后继续执行这个动作:

public ActionResult List() 
    { 
     if ((string)Session["new_list"] == "y") 
     { 
      //clear session variables, load fresh data from API 
     }else{ 
      //display blank table. Ask user to input data to retrieve a list 
     } 
     .... 
    } 

现在,我遇到的问题是当用户导航离开列表页面,然后导航回wi th浏览器的后退按钮,它仍然呼吁newlist。在浏览器的历史中,不是存储List,而是存储newlist,这导致会话变量清除。我能做些什么来阻止这种情况的发生,或者是否有其他机制可以在c#mvc中使用,这可以帮助我实现预期的效果。

+0

把它放入cookie中。 – CodingYoshi

回答

1

你的主要这里的问题是,NewList操作使用GET时,它应该是一个POST

A GET请求永远不会改变资源的状态,而只是返回资源的当前状态;而POST请求允许改变资源。因为你允许用GET请求调用NewList动作,所以用户的浏览器假定(完全正确地),如果它仅仅在将来重复请求,就会发生没有不好的/不想要的事情,例如,当用户使用后退按钮时。

如果发出POST请求,用户浏览器将不会重新发出请求,而用户不确认它们实际上是否打算重新发出请求。

你的问题的解决方案则是修改此为标准PRG模式:POST /重定向/ GET;即发送POST请求以执行状态更改,将用户浏览器重定向到另一个页面,并获取结果页面。在这种方案中,按下后退按钮将有效地“跳过”状态改变操作并转到用户所在的上一页。

要在MVC实现这一点:

[HttpPost] 
public ActionResult NewList() 
{ 
    //clear session variables, load fresh data from API 
    return RedirectToAction("List"); 
} 

public ActionResult List() 
{ 
    // whatever needs to happen to display the state 
} 

这意味着你不能直接提供“新目录”行动,在页面的超链接,因为这些总会发出GET请求。您需要使用如下所示的最小表单:<form method="post" action="@Url.Action("NewList", "Alert")"><button type="submit">New List</button></form>。您可以根据需要设置按钮的样式,使其看起来像普通的超链接。

+0

这是一个很好的解决方案。感谢您花时间回答。尽管我认为我可能找到了一个较短的解决方案,即在动作定义上方使用'[HttpGet,OutputCache(NoStore = true,Duration = 1)]'。这将迫使浏览器从头开始加载页面,而不是从缓存中加载页面。这是目前正在发生的情况 – Notaras

+0

我不认为你的问题与缓存有什么关系,尤其是因为你注意到用户按下后退按钮将无意中清除他们的列表(表示浏览器发出请求到服务器,并没有从它的缓存服务它!) 也有安全方面的考虑因素,考虑到在你目前的方案下,我可以在另一个网站上放置一个

0

它存储NewList的原因是因为您正在重定向到“Alert/NewList”,并且它的URL中的字符串用于打到“NewList”操作,所以无论何时尝试返回按钮,浏览器都会获取此“Alert/NewList“的URL,因此它打击行动”新列表“。 但现在,我不明白为什么会话变得清晰。因为你在“NewList”本身初始化会话。不过,我建议你使用本地存储来为会话分配值。