Category Archives: Development

Detailní ASP.NET Request + WebForm Page LifeCycle diagram

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“:

ASP.NET LifeCycle 2

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.

Viz též

SQL Transakce + mýty – Slides, dema, záznam [SQL DevCon 2008]

Slides a dema z přednášky na konferenci SQL DevCon 2008:

Z přednášky byl pořizován záznam, který najdete na našem YouTube Channelu:

Výjimky „The I/O operation has been aborted…“ na IIS7

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“.

Nekonzistence vlastnosti Visible třídy System.Web.UI.Control

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ě.

Příklad

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;
  • Na řádku 1 nastavíme první panel k zobrazení.
  • Na řádku 2 přečteme property PrvniPanel.Visible. Ačkoliv jsme ji na řádku 1 nastavili na true, vrací false, neboť rodič VnejsiPanel ve stromu controlů je skrytý. I druhému panelu tedy nastavíme Visible na true.
  • Na řádku 3 nastavíme vnější panel k zobrazení.
  • Postupně jsme všem panelům nastavili Visible na true a bude tedy vidět vše, ačkoliv to tak na první pohled nevypadá.

Nekonzistence vlastnosti Visible třídy System.Web.UI.Control

 

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ě.

Příklad

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;
  • Na řádku 1 nastavíme první panel k zobrazení.
  • Na řádku 2 přečteme property PrvniPanel.Visible. Ačkoliv jsme ji na řádku 1 nastavili na true, vrací false, neboť rodič VnejsiPanel ve stromu controlů je skrytý. I druhému panelu tedy nastavíme Visible na true.
  • Na řádku 3 nastavíme vnější panel k zobrazení.
  • Postupně jsme všem panelům nastavili Visible na true a bude tedy vidět vše, ačkoliv to tak na první pohled nevypadá.
  • AjaxControlToolkit HoverMenuExtender – dočítání vyskakovacího obsahu AJAXem

    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:

    &lt;asp:Label ID=&quot;TargetLb&quot; Text=&quot;Ukažte sem, já se dočtu a vyskočím!&quot; runat=&quot;server&quot; /&gt;
    &lt;asp:Panel ID=&quot;PopupPanel&quot; Style=&quot;display: none;&quot; runat=&quot;server&quot;&gt; &lt;%-- display:none - aby se při načítání nepřesýpala obrazovka --%&gt;
        Statický obsah pop-upu.
        &lt;asp:Panel ID=&quot;DynamicPopupContent&quot; runat=&quot;server&quot; /&gt;
    &lt;/asp:Panel&gt;
    &lt;ajaxToolkit:HoverMenuExtender
        TargetControlID=&quot;TargetLb&quot;
        PopupControlID=&quot;PopupPanel&quot;
        DynamicServicePath=&quot;~/AjaxServices/MyService.asmx&quot;
        DynamicServiceMethod=&quot;GetPopupContent&quot;
        DynamicContextKey=&quot;Kontext, např. ID záznamu&quot;
        DynamicControlID=&quot;DynamicPopupContent&quot;
        runat=&quot;server&quot;
    /&gt;
    

    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 &quot;Hello World &quot; + 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.

    Registrace klientských skriptů: ClientScriptManager vs. ScriptManager

    ClientScriptManager

    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.

    ScriptManager

    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:

    • RegisterClientScriptBlock(Page, Type, String, String, Boolean)
      Skripty registrované touto metodou jsou do browseru předány v každém asynchronním postbacku.
    • RegisterClientScriptBlock(Control, Type, String, String, Boolean)
      Skripty registrované touto metodou v asynchronním postbacku jsou renderovány do stránky jen tehdy, pokud je renderován předaný control. Pokud tedy při asnychronním postbacku není control v update panelu nebo je v update panelu, který není renderován, potom není renderován ani registrovaný skript.

    Další metody pro registraci klientských skriptů jsou:

    • RegisterClientScriptBlock – registruje blok kódu
    • RegisterClientScriptInclude – registruje externí soubor s klienských skriptem
    • RegisterClientScriptResource – registruje soubor s klienských skriptem z resources
    • RegisterOnSubmitStatement – registruje kód vykonaný před postbackem
    • RegisterStartupScript – registruje kód vykonaný během načtení stránky

    Vytvoření loginu pro doménovou skupinu

    V management nástrojích pro SQL Server 2005 nelze založit login pro doménovou skupinu.
    Login se mi podařilo založit pomocí příkazu

    create login [HAVIT\Development] from windows
    

    kde v našem případě je Development doménovou skupinou.
    Další pozorování je, že login doménové skupiny není možné pomocí management studia zakázat:

    • při nastavení Login na Disabled je zobrazena chyba,
    • nastavení Permissions to connect to database engine na Deny je ignorováno.

    Vytvoření loginu pro doménovou skupinu

    V management nástrojích pro SQL Server 2005 nelze založit login pro doménovou skupinu.
    Login se mi podařilo založit pomocí příkazu

    create login [HAVIT\Development] from windows
    

    kde v našem případě je Development doménovou skupinou.
    Další pozorování je, že login doménové skupiny není možné pomocí management studia zakázat:

    • při nastavení Login na Disabled je zobrazena chyba,
    • nastavení Permissions to connect to database engine na Deny je ignorováno.

    Uložení schématu databáze do SQL skriptu, z GUI i příkazové řádky

    Občas se Vám může hodit možnost vyskriptovat kompletní databázové schéma do SQL skriptu. Spuštěním takového skriptu pak můžete úplné DB schema zpětně reakonstruovat. Pokud jste si (ne)oblíbili schopnosti databázové edice Visual Studia stejně jako já, pak Vás potěším, že to jde i mnohem jednodušeji pomocí tzv. SQL Publishing Wizzardu přímo ze sady standardních management  nástrojů SQL Serveru 2005:

    Vyskriptování schématu DB z GUI

    1. Spusťte si SQL Server 2005 Management Studio
    2. V Object Exploreru pravým tlačítkem na dotčenou databázi a zvolte Tasks ~ Generate Scripts…
    3. Dole zaškrtněte „Script all objects in the selected database“ (v horní části okna máte předvolenu dotčenou DB), pokračujte Next,
    4. Options – Podle své potřeby můžete upravit nastavení generátoru a ovlivnit podobu výsledného skriptu, např. zvolit jinou cílovou verzi SQL Serveru, pokračujte Next,
    5. Script Mode – zvolte, kam chcete skript vygenerovat – obvykle do souboru, pokračujte Next,
    6. Review nastavení + Finish

    …a je hotovo.

    Vyskriptování schématu DB z příkazové řádky

    …není nic jednoduššího:

    "C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\1.2\sqlpubwiz" script -d DbName -S ServerName -U UserName -P Password TargetScriptFile.sql -schemaonly -f
    

    U nás tímto způsobem průběžně ukládáme ke každé solution aktuální schéma DB, tak, aby bylo v Subversion (source-control) vždy uložena příslušná verze schématu DB, s kterou aplikace pracuje.

    Pro úplnost dodávám, že pro synchronizaci databázových schémat a generování rozdílových skriptů používám RedGate SQL Compare.

    Update pro MSSQL 2012 (1.10.2013)

    Poslední mně známá verze SqlPubWiz je 1.4 s podporou MSSQL 2008. Je tuším navíc součástí Visual Studia 2010, možná dokonce SP1. Každopádně součástí MSSQL 2012 již nic takového není, resp. z GUI je stále volba „Generate Scripts…“, která však otevře úplně nový „Generate and Publish Scripts“ wizzard. Z příkazové řádky přímá alternativa není a je potřeba použít příslušných SMO objektů (nejspíš není problém to vyskriptovat pomocí PowerShellu, nebo jednoduchou utilitou, jejíž zdrojový kód je naznačen třeba zde: http://social.msdn.microsoft.com/Forums/sqlserver/en-US/afc5dd35-0c4d-496a-a0a0-7b6aa3ef2941/command-line-database-scripting-in-2012).

    Na druhou stranu, pokud jsou vaše databáze strukturálně zpětně kompatibilní s SQL 2008 (nejde o fyzický přepínač Compatibility Level, ale o skutečné použití), pak není důvod SqlPubWiz nepoužívat. My to tak stále děláme…