Zamezení vícenásobného odeslání formuláře pomocí server control v ASP.NET
O tom, že v řadě webových aplikací je nežádoucí, aby uživatel odesílal údaje z formuláře vícekrát, a jak tomu alespoň klientským skriptem zamezit, jsme již psali. V tomto článku popsaný způsob zapouzdříme do serverového ovládacího prvku, který je pak možné ihned použít jako náhradu původního HtmlFormu.
Je zřejmé, že vícenásobné odeslání těch samých údajů uživatelem je nežádoucí. Lékem proti „syndromu F5“, kdy uživatel opakovaně odesílá formulář obnovováním stránky, je prostá úprava aplikace tak, aby po zpracování údajů provedla přesměrování pomocí Response.Redirect()
. Tento princip však řeší situaci až po odeslání. Jak jsme již psali, kritickým momentem je však také stav těsně po kliknutí na odesílací tlačítko – pokud není ze serveru dostatečně rychlá odezva, uživatel klidně na odesílací tlačítko klikne v tento okamžik opakovaně i několikrát a problém je na světě, do naší aplikace nakonec dorazí několik požadavků s těmi samými údaji. Ukázka (zdrojový kód) je také tentokrát spíše symbolická, pokud máte rychlé připojení, pravděpodobně se vám nepodaří nasimulovat tak rychlé opakované kliknutí, aby aplikace zareagovala upozorňujícím alertem. Pokud budete ale ukázku testovat na vlastním počítači, mám pro vás jeden trik. Po prvním zobrazení stránky přeuložte soubor Web.config, pokud následně kliknete na odesílací tlačítko, bude nejprve probíhat kompilace a ta vytvoří dostatek času pro ozkoušení vícenásobné odeslání.
V přechozím článku popsaný skript zapíšeme do kódu třídy, kterou zdědíme ze základní třídy HtmlForm v prostoru názvů System.Web.UI.HtmlControls
. Jak vyrobit serverový ovládací prvek jsme si již vyzkoušeli na příkladu s Flash Playerem, postup je analogický. Připravený klientský skript zakomponujeme do přepsané metody Render()
a pro pohodlné používání zveřejníme potřebné vlastnosti. V našem případě budou dvě, AllowMultipleSubmit
typu „Boolean“ prostě umožní vypnout náš doplněk zamezující možnost vícenásobného odeslání (může se hodit například při ladění aplikace), MultipleSubmitMessage
je typu „String“ a umožní nastavit případné hlášení uživateli, pokud se pokouší formulář odeslat opakovaně.
using System;
using System.Web.UI;
namespace Interval.CZ.Web.UI.HtmlControls
{
[System.Web.UI.ToolboxData(„<{0}:HtmlForm RunAt=\“Server\“></{0}:HtmlForm>“)]
public class HtmlForm : System.Web.UI.HtmlControls.HtmlForm
{
private String _multipleSubmitMessage = String.Empty;
private Boolean _allowMultipleSubmit = false;
public Boolean AllowMultilpleSubmit
{
get
{
object o = this.ViewState[„AllowMultilpleSubmit“];
if (o != null)
return (Boolean) o;
else
return false;
}
set
{
this.ViewState[„AllowMultilpleSubmit“] = value;
_allowMultipleSubmit = value;
}
}
public String MultipleSubmitMessage
{
get
{
object o = this.ViewState[„MultipleSubmitMessage“];
if (o != null)
return (String) o;
else
return String.Empty;
}
set
{
this.ViewState[„MultipleSubmitMessage“] = value;
_multipleSubmitMessage = value;
}
}
protected override void Render (HtmlTextWriter writer)
{
if (!_allowMultipleSubmit)
{
base.Attributes.Add(„onsubmit“,“__formDisMultipleClick(document.getElementById(‚“ + base.ClientID + „‚));“);
writer.WriteLine();
writer.WriteBeginTag(„script“);
writer.WriteAttribute(„type“,“text/javascript“);
writer.WriteLine(HtmlTextWriter.TagRightChar);
writer.WriteLine(„<!– <![CDATA[„);
writer.WriteLine(„function __formIsSending()“);
writer.WriteLine(„{„);
if (_multipleSubmitMessage != null && _multipleSubmitMessage.Length > 0)
writer.WriteLine(“ alert(‚“ + _multipleSubmitMessage + „‚);“);
writer.WriteLine(“ return false;“);
writer.WriteLine(„}“);
writer.WriteLine(„function __formDisMultipleClick(formObj)“);
writer.WriteLine(„{„);
writer.WriteLine(“ for (var i=0; i<formObj.length; i++ )“);
writer.WriteLine(“ {„);
writer.WriteLine(“ if (formObj.elements[i].type == ‚submit‘ && formObj.elements[i].type == ‚image‘)“);
writer.WriteLine(“ {„);
writer.WriteLine(“ formObj.elements[i].onclick = __formIsSending;“);
writer.WriteLine(“ }“);
writer.WriteLine(“ }“);
writer.WriteLine(„}“);
writer.WriteLine(„//]]> –>“);
writer.WriteEndTag(„script“);
writer.WriteLine();
}
base.Render(writer);
}
} }
V kódu vidíme „poctivé“ vytvoření vnitřních private proměnných, abychom vyhověli zásadám OOP (zjednodušeně řečeno, uvnitř prvku pracujeme s vnitřními proměnnými, které „vnější“ aplikace nevidí – na tyto vnitřní proměnné pouze mapujeme veřejné neboli public vlastnosti, se kterými se pak zvnějšku pracuje). V přepsané (override) metodě Render()
si nejprve necháme vykreslit část klientského skriptu (v aplikaci se potom skript objeví ještě před otevírací značkou form
) a následně zavoláme výkonnou část původní metody Render()
zápisem klíčového slova base
. Třídu nakonec zkompilujeme a uložíme do složky Bin v kořeni virtuální aplikace na serveru.
Zde bych chtěl jen upozornit na drobný rozdíl oproti původnímu JavaScriptu v předchozím článku. Jak vidíte, do atributu onsubmit
nepředáváme funkci __formDisMultipleClick()
odkaz na formulář klíčovým slovem this
. Důvodem je nový způsob renderování klientských skriptů v ASP.NET 2.0. Když se totiž pokusíme cokoli přidat do atributu onsubmit
formuláře, ASP.NET to rozpozná a místo renderování přímo do atributu onsubmit
zakomponuje naše příkazy do těla vlastní funkce obsluhující událost odeslání formuláře. Zde by nám pochopitelně odkaz this
nezafungoval, proto je „poctivě“ vypsáno získání přístupu k objektu pomocí document.getElementById('" + base.ClientID + "')
, kde prostřednictvím ClientID získáme id, se kterým je formulář renderován do stránky.
Ukázka použití nového prvku ve stránce:
<%@ Page Language=“C#“ EnableSessionState=“False“ Debug=“False“ %>
<%@ Register TagPrefix=“Sc“ Namespace=“Interval.CZ.Web.UI.HtmlControls“ Assembly=“Interval.CZ.Web.UI.HtmlControls.HtmlForm“ %><?xml version=“1.0″ encoding=“utf-8″
?>
<!DOCTYPE html PUBLIC „-//W3C//DTD XHTML 1.0 Transitional//EN“ „http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“>
<html xmlns=“http://www.w3.org/1999/xhtml“ xml:lang=“cs“ lang=“cs“ dir=“ltr“>
<head>
<meta http-equiv=“Content-type“ content=“text/html; charset=utf-8″ />
<title>Vlastní HtmlForm povolí odeslání pouze 1x</title>
</head>
<body>
<Sc:HtmlForm MultipleSubmitMessage=“Již se odesílá…“ runat=“server“>
<asp:TextBox Id=“txt1″ RunAt=“Server“ />
<asp:RequiredFieldValidator ControlToValidate=“txt1″ Display=“Dynamic“ ErrorMessage=“Chyba“ RunAt=“Server“ />
<asp:Button RunAt=“server“ Text=“Odeslat 1″ />
<asp:Button RunAt=“server“ Text=“Odeslat 2″ />
<asp:Button RunAt=“server“ Text=“Odeslat 3″ />
</Sc:HtmlForm>
</body>
</html>
V direktivách stránky vidíme zaregistrování ovládacího prvku, kde jsme nadefinovali předponu elementu „Sc“, která je potom skutečně použita i v elementu našeho nového prvku. V elementu našeho prvku jsme pak nastavili ještě text hlášení (atributem MultipleSubmitMessage
), které se zobrazí, pokud uživatel „kliká více než je zdrávo“. Pro ukázku je přidán i schvalovací prvek RequiredFieldValidator
, aby bylo zřejmé, že klientský skript přidaný do nového HtmlFormu
nekoliduje se skripty, které schvalovací prvky navazují na obsluhu události onsubmit
formuláře.
Jak vidíte, libovolnou aplikaci můžeme jednoduše upravit tak, že původní element formuláře nahradíme za tento náš nový, který podporuje všechny vlastnosti původního a navíc se brání vícenásobnému odeslání.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Členská sekce: 4 důvody proč ji mít na svém webu
12. března 2024 -
Thunderbolt 4 vs. OCuLink: Přišel čas na upgrade?
27. května 2024 -
Nepodceňte UX na vašem webu: Proč na něm záleží?
10. dubna 2024 -
9 nejzajímavějších doménových koncovek
19. srpna 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024