Screencast, který jsem svého času vytvořil pro MSTV.cz
Slides a dema ke screencastu:
Viz též:
Screencast, který jsem svého času vytvořil pro MSTV.cz
Slides a dema ke screencastu:
Viz též:
Slides a dema z přednášky na konferenci TechEd Praha 2009:
Z přednášky nebyl pořizován záznam, část tématiky o web.config transformacích lze najít ve v podobě screencastu, který jsem svého času dělal pro MSTV.cz.
AJAXový UpdatePanel se chová zvláštně vůči logice naming-containerů, pokud se tedy potkáte s názvy (ID) controlů, nepůjde Vaše stránka zkompilovat. Stačí zkusit následujících jednoduchý snippet:
<asp:TextBox ID="SomethingTB" runat="server" />
<asp:Repeater ID="MyRepeater" runat="server">
<ItemTemplate>
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:TextBox ID="SomethingTB" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</ItemTemplate>
</asp:Repeater>
…při kompilaci budete obšťastněni chybovými hláškami
D:\Development\UpdatePanelCompiler\Default.aspx(18,57): error CS0102: The type '_Default' already contains a definition for 'SomethingTB' c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\updatepanelcompiler\1c44388f\ad38e94\App_Web_r7xfjqxf.0.cs(231,59): error CS0111: Type 'ASP.default_aspx' already defines a member called '__BuildControlSomethingTB' with the same parameter types
Po prázdninové odmlce jsem tu zpět s další čerstvou zkušeností, kterou jsme udělali na jednom z našich projektů.
Společné uživatelské rozhraní pro vytváření nových a editaci stávajících záznamů mělo části, které byly použitelné jen pro existující objekty, mj. i možnost připojení souborů pres control FileUpload. Části použitelné jen u existujících objektů byly skryty pomocí Visible=“fase“ a zobrazovány pomocí UpdatePanelu, který je zobrazil po uložení nového objektu.
Problém byl v tom, že u nově vytvořených objektů nebylo možné připojit soubory, zatímco u existujících objektů to bez problémů šlo. Ukázalo se, ze control FileUpload v postbacku žádný soubor nedostane (HasFile bylo false), přestože uživatel soubor do formuláře zadal. Stejně se to chovalo ve všech prohlížečích a Fiddler potvrdil, že se z klienta žádný soubor nepřenesl.
Primitivní testovací kód by mohl vypadat třeba takto:
<form id="form1" runat="server">
<asp:ScriptManager EnablePartialRendering="false" runat="server" />
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:FileUpload ID="FileFU" Visible="false" runat="server" />
<asp:Label ID="HasFileLb" runat="server" />
<asp:Button ID="SaveBt" Text="Save" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
void SaveBt_Click(object sender, EventArgs e)
{
FileFU.Visible = true;
HasFileLb.Text = FileFU.HasFile.ToString();
}
Po chvilce ladění se ukázala příčina problému. V režimu editace existujícího objektu formulář již od prvního requestu renderoval control FileUpload, který si sám do elementu form doplňuje potřebný atribut enctype=“multipart/form-data“, zatímco v režimu založení nového objektu se control FileUpload renderoval až AJAXem z UpdatePanelu po uložení nového objektu. UpdatePanel však v DOM stránky vymění jen svoji část a element form zůstává nedotčen, bez atributu enctype.
Pozor na to, ze AJAXovy partial rendering pomoci UpdatePaneliu vymění pouze určitou část DOM stránky a nesmi se zapomínat na vztahy teto části se zbytkem stránky. Většinou jsou tyto vztahy zřejmé, záludnost s FileUpload a atributem enctype vsak může pozlobit.
Možným řešením je například nastavování hodnoty atributu z kódu už při prvním requestu, přestože control FileUpload ještě na stránce není:
this.Page.Form.Enctype = "multipart/form-data"
Pokud se zabýváte technologií ASP.NET do hloubky, může se Vám hodit můj „ASP.NET 2.0/3.5 Request + Page LifeCycle Diagram“:
Jedná se o první verzi mého diagramu, který hodlám dále graficky vylepšovat a zpřehledňovat. Až mi zbyde chvilka, dám sem i PDF verzi k tisku. Stejnětak je možné, že jsem v něm někde udělal chybu. Pokud tedy nějakou nesrovnalost objevíte, dejte mi prosím vědět.
Červeně jsou označena místa, kde se lze zapojit s vlastní invencí, jde buď o události, virtuální metody, nebo adapter. Modře jsou vyznačeny interface pro implementaci dané funkčnosti a šedě jsou interní implementace ASP.NET.
Nedávno se nám v IIS7 na serveru (Windows Server 2008 Standard x64 EN) začaly množit výjimky:
Exception information:
Exception type: System.Runtime.InteropServices.COMException
Exception message: The I/O operation has been aborted because of either a thread exit or
an application request. (Exception from HRESULT: 0x800703E3)
Nejdřív k výjimkám docházelo jen tak občas, ale vzestup počtu byl doslova raketový a naše aplikace se staly nepoužitelnými. Proč chyby vznikly nevíme, máme malé podezření na aktualizaci kb947562, ale situace se po jejím odinstalování nezlepšila.
Zdá se, že vyřešit popsaný problém pomohla změna nastavení Managed pipeline mode aplikačního poolu z „Integrated“ na „Classic“.
Vlastnost Visible třídy Control používáme k zobrazení a skrytí controlu ve stránce. Dokumentace říká něco mírně komplikovanějšího: Gets or sets a value that indicates whether a server control is rendered as UI on the page. Tato zdánlivá komplikovanost má zásadní význam. Getter property totiž vrací false, pokud je skrytý control nebo některý z jeho rodičů ve stromu controlů.
Z mého pohledu jde o dosti nezvyklé a vůči ostatním vlastnostem nekonzistentní chování. Neočekával bych, že po nastavení vlastnosti na true budu číst false. Doporučuji tedy s vlastností Visible pracovat náležitě opatrně.
Mějme dva panely (PrvniPanel a DruhyPanel), přičemž chceme, aby byl vidět právě jeden z nich. Oba panely jsou obaleny vnějším panelem.
<asp:Panel ID="VnejsiPanel" Visible="false" runat="server">
<asp:Panel ID="PrvniPanel" runat="server">
...
</asp:Panel>
<asp:Panel ID="DruhyPanel" runat="server">
...
</asp:Panel>
</asp:Panel>
PrvniPanel.Visible = true; // nějaký výraz, který tentokrát vrací true DruhyPanel.Visible = !PrvniPanel.Visible VnejsiPanel.Visible = true;
Vlastnost Visible třídy Control používáme k zobrazení a skrytí controlu ve stránce. Dokumentace říká něco mírně komplikovanějšího: Gets or sets a value that indicates whether a server control is rendered as UI on the page. Tato zdánlivá komplikovanost má zásadní význam. Getter property totiž vrací false, pokud je skrytý control nebo některý z jeho rodičů ve stromu controlů.
Z mého pohledu jde o dosti nezvyklé a vůči ostatním vlastnostem nekonzistentní chování. Neočekával bych, že po nastavení vlastnosti na true budu číst false. Doporučuji tedy s vlastností Visible pracovat náležitě opatrně.
Mějme dva panely (PrvniPanel a DruhyPanel), přičemž chceme, aby byl vidět právě jeden z nich. Oba panely jsou obaleny vnějším panelem.
<asp:Panel ID="VnejsiPanel" Visible="false" runat="server">
<asp:Panel ID="PrvniPanel" runat="server">
...
</asp:Panel>
<asp:Panel ID="DruhyPanel" runat="server">
...
</asp:Panel>
</asp:Panel>
PrvniPanel.Visible = true; // nějaký výraz, který tentokrát vrací true DruhyPanel.Visible = !PrvniPanel.Visible VnejsiPanel.Visible = true;
Objevil jsem jednu nepříliš dokumentovanou vlastnost HoverMenuExtenderu z AjaxControlToolkitu – že umí „vyskakovací“ obsah dočítat pomocí AJAXového callbacku na server. Nastavení je snadné, použijí se property DynamicXyz a jen je potřeba vědět (což se ukázalo jako největší kámen úrazu), jak je to vlastně celé zamýšleno a jak má vypadat serverová metoda (WebService), která má dynamický content vracet:
<asp:Label ID="TargetLb" Text="Ukažte sem, já se dočtu a vyskočím!" runat="server" />
<asp:Panel ID="PopupPanel" Style="display: none;" runat="server"> <%-- display:none - aby se při načítání nepřesýpala obrazovka --%>
Statický obsah pop-upu.
<asp:Panel ID="DynamicPopupContent" runat="server" />
</asp:Panel>
<ajaxToolkit:HoverMenuExtender
TargetControlID="TargetLb"
PopupControlID="PopupPanel"
DynamicServicePath="~/AjaxServices/MyService.asmx"
DynamicServiceMethod="GetPopupContent"
DynamicContextKey="Kontext, např. ID záznamu"
DynamicControlID="DynamicPopupContent"
runat="server"
/>
a služba musím mít signaturu „string DoSomething(string contextKey)“:
[WebService]
[ScriptService]
public class Sluzby : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod]
public string GetPopupContext(string contextKey)
{
return "Hello World " + contextKey;
}
}
Tip 1: Pokud má být celý pop-up tvořen jen dynamickým obsahem, můžete DynamicControlID nastavit na stejný control jako PopupControlID a nemusíte pak vnořovat žádný další Panel (nebo jiný control).
Tip 2: DynamicControlID nemusí být uvnitř PopupControlID, dynamický obsah můžete dočítat i do jiného místa stránky, i když to asi není moc běžné.
Tip 3: Metodu vracející dynamický obsah můžete umístit i přímo do stránky jako PageMethod, musí být pak statická a HoverMenuExtenderu se pak nenastavuje vlastnost DynamicServicePath.
Třída ClientScriptManager je součástí .NET Frameworku od jeho vzniku. Její instance je běžně přístupná přes Page.ClientScript. Třída slouží k registraci klientských skriptů, které mají být ve stránce renderovány, a k další práci s klienskými skripty.
Tato třída neví nic o AJAXu a asynchronním postbacku, pokud zaregistrujeme do stránky nějaký klientský skript, bude vyrenderován pouze v případě prvního načtení stránky (GET) nebo v klasickém postbacku (POST). Pokud je skript registrován v asynchronním postbacku, do browseru se nedostane.
Třída ScriptManager je součástí ASP.NET Ajax 1.0 rozšířující .NET Framework 2.0 nebo .NET Frameworku 3.5. Tato třída rovněž slouží k registaci klientských skriptů do stránky.
Metody pro registraci klienských skriptů jsou statické a disponují rozhaním pro pohodlnější použití. Skripty registrované při prvním načítání stránky (GET) a v klasickém postbacku (POST) jsou stejně jako v předchozím případě renderovány do stránky, skripty registrované v asynchronním postbacku MOHOU být předány do browseru uživatele.
Každá z registračních metod existuje ve dvou přetíženích, které se liší typem prvního parametru – Control vs. Page.
Například:
Další metody pro registraci klientských skriptů jsou: