2012-03-21 305 views
5

我有一個ASP.NET MVC 3應用程序,它有一個名爲Create後的行動:防止重複表單提交

[HttpPost] 
public virtual ActionResult Create(Issues issues) 
{ 
    if (ModelState.IsValid) 
    { 
     context.Issues.Add(issues); 
     context.SaveChanges(); 
     return RedirectToAction("Index"); 
    } 
    return View(issues); 
} 

如果我雙擊提交按鈕錯誤,它會創建2個問題。有沒有一種方法來防止這種情況,沒有使用javascript和禁用按鈕,我認爲使用RedirectToAction的整個使用是通過使用Post/Redirect/Get設計模式來防止這種情況?

+1

你能簡單地添加一些像if(!context.Issues.Exists(logic))嗎? – 2012-03-21 11:10:07

+1

只需單擊時禁用提交按鈕! – gdoron 2012-03-21 11:19:08

+0

有沒有這種方法稱爲存在? – CallumVass 2012-03-21 11:19:25

回答

4

你提到的(郵政/重定向/獲取設計模式)的圖案防止頁面雙重張貼刷新,因爲最後一個動作是GET,而不是POST。

如果要防止雙重張貼雙擊,你可以:

1. Disable the button after click 
2. Maintain a unique index on 'Issues' and look for duplicates 
3. Maintain something in session that gives you an indication of a double post 

而且有可能是幾個方面......我想禁用按鈕可能是最容易的,因爲你無論如何,它都會重定向到另一個頁面。

+0

對於上面的例子來說,這很好,但是我所關心的是更高級的例子,例如Ajax.BeginForm,它只會更新頁面的一部分 – CallumVass 2012-03-21 11:33:58

+0

@BiffBaffBoff - 爲了防止雙擊客戶端(AJAX POST),您可以直接阻止UI直到響應返回(同步),或者禁用按鈕(異步),或者實現一些服務器端來檢測它。 – 2012-03-21 11:43:01

+0

嗨克里斯,這正是我現在所做的。我已禁用該按鈕,直到響應恢復。再次感謝 – CallumVass 2012-04-04 10:46:16

1

當您向用戶展示表單時,您可以生成IssueId,然後檢查您在Create方法中是否對此類標識沒有問題,例如跳過此類請求。

+0

那麼它只會創建繼續追加ID的問題是IssueId是我的PK領域,因此對於每個新創建的問題,它都會有一個新的Id(2,3,4,5等)。 – CallumVass 2012-03-21 11:20:39

2

最簡單的辦法我能想到的是使用Session:

if (ModelState.IsValid) 
{ 
    DateTime now = DateTime.Now; 
    if (Session["LastAdd"] == null || (now - (DateTime)Session["LastAdd"]).TotalMilliseconds > 1000) 
    { 
     //first time, or more than a second passed since last addition 
     context.Issues.Add(issues); 
     context.SaveChanges(); 
     Session["LastAdd"] = now; 
    } 
    return RedirectToAction("Index"); 
} 
+0

對不起,我不使用會話作爲其Windows身份驗證應用程序 – CallumVass 2012-03-21 11:18:09

+0

@BiffBaffBoff - 開始使用「會話」變量。 – 2012-03-21 11:21:56

+0

@Biff會話變量與認證無關。是什麼讓你以這種方式思考? – 2012-03-21 12:40:52

5

簡單的解決方案!

點擊時禁用提交按鈕。 結束。

$('submitButtonId').click(function(){ 
    $(this).prop('disabled', true); 
    $(this).attr('disabled', 'disabled'); // for jQuery versions < 1.6. 
}); 
+1

使用此解決方案,如果用戶在點擊和上傳信息到服務器之間存在網絡問題,那麼無法挽救表單中的信息。如果用戶花了5分鐘時間填寫表單,他們會感到不安。更好的方法可能只是在網絡成功或失敗之前將其禁用。 – 2014-05-01 17:53:03

+0

這不適用於JavaScript禁用? – 2016-02-29 04:32:36

+0

@AlexAngas,JavaScript禁用時沒有任何工作。我認爲沒有js就沒有好的方法。 (_Shadow Wizard_下面的回答是硬編碼1000毫秒,這遠非理想情況,如果用戶網絡連接速度很慢,該怎麼辦?) – gdoron 2016-02-29 13:24:00

0

PRG模式不會阻止這種情況,因爲其中的P動作需要時間(通常是這種情況),用戶可以再次提交表單(通過點擊或瀏覽器刷新),這會導致PRG模式「失敗」。

請注意,惡意用戶也可以通過快速連續運行多個http帖子來繞過所有客戶端措施。

以上所有的解決方案是使用以下方法檢查服務器端的重複提交,如我所述,here

爲方便起見,我引述:

「如果你使用一個隱藏的防僞標記在你的形式(如你 應該),你可以標記上緩存防僞先提交和 從緩存中,如果需要刪除標記,或到期後的時間設定量的緩存項 。

然後,您將能夠檢查與對緩存 每個請求的具體形式是否已經提交併拒絕如果有的話。「