ASP.NET pro začátečníky
6. Práce se soubory
MENU

Možnosti, které vám dnes představím, většinou najdete spíše na konci knih a kurzů informujících o ASP.NET. Já si však myslím, že by jsme se před započetím rozsáhlé problematiky databází měli poučit o tom, jak ovlivňovat běh aplikace a jak zvýšit její výkonnost.

web.config

Veledůležitý soubor. Je určen pro nastavení parametrů běhu aplikace, tj. například jaké chybové hlášky vyhazovat, jak dlouhý povolit skriptům běh atp. Nabízí ale i velmi pokročilé možnosti jako je například autentifikace.

Má několik zajímavých vlastností:

přísněUtajenáHesla.config
To je mimochodem velmi důležitá informace. Žádný soubor s příponou config na serveru s nainstalovaným ASP.NET nepůjde zobrazit klientovi. Proto doporučuji tuto příponu dávat například souborům s hesly... i když ty byste měli šifrovat tak jako tak. Přijde na to řada

Takže jak tento soubor vypadá? Hrubě takto:

<?xml version="1.0" encoding="utf-8"?>

<configuration>
  <configSections>

  </configSections>
  <system.web>

  </system.web>
  <system.net>

  </system.net>
</configuration>
XML formát

Poprvé se setkáváte s XML souborem. Takže bychom si měli i vysvětlit základy jeho využívání.

Základním prvkem XML souboru je element. Ten se uvozuje pomocí počátečního a koncového tagu například takto: <nazevTagu>obsah elementu</nazevTagu>. Obsah elementu může skrývat obyčejný text nebo další, vnořené, elementy. Ve výsledku vzniká stromová struktura.

Každý element může mít své parametry, které se zapisují k jeho počátečnímu tagu takto: <nazevTagu parametr1="hodnota1" parametr2="hodnota2">. Tyto hodnoty musí být vždy uzávorkované.

V tomto jazyce záleží na velikosti písmen. Tudíž nemůže element začít tagem Alfa a ukončit ALFA.

Hlavičku XML souboru vidíme na prvním řádku výpisu. Nese informaci o verzi a kódování.

Velmi primitivní ... se to jen zdá. Zatím to stačí k základnímu pochopení obsahu souboru web.config.

Tedy tři hlavní části:

Nyní si tedy postupně projdeme všechny možnosti z části system.web

appSettings

Velmi užitečná část. Umožňuje snadné ukládání konfiguračních dat pro celou aplikaci. Až se poznáme s databázemi, poznáme například, že k připojení k ní je potřeba řetězec, který definuje server, uživatelské jméno, heslo a několik dalších hodnot. Není zrovna nejlepší, pokud máme tento řetězec v několika souborech zadán "napevno", to poznáte při prvním stěhováním vaší aplikace na jiný server. Je třeba přepsat všechny údaje - a to je v tolika souborech strašná nuda. Navíc to postrádá jistou eleganci.

Proto si do části appSettings pomocí elementu add přidáme konfigurační nastavení, pojmenujeme ho třeba connString přidáním tohoto řetězce do parametru key. Vlastní hodnotu přidáme do parametru value.

<configuration>
  <system.web>
    <appSettings>
      <add key="connString" value="Data source=databaze.mojeDomena.cz;
  initial catalog=obchodSeZidlemi;user id=obchodSeZidlemi;password=qadw91874rres" />
    </appSettings>
  </system.web>
</configuration>

Hurá, parametr byl vytvořen. Jak se k němu ale můžeme dostat z vlastní aplikace? Samozřejmě nemusíme web.config procházet standardními .NET prostředky pro práci s XML soubory, to by jsme si pak takové nastavení mohli uložit kdekoliv. Toto místo přináší tu výhodu, že s ním pracují standardní funkce:

Dim connString As String = ConfigurationSettings.AppSettings("connString")

Jasné? Do místa appSettings můžeme uložit libovolné množství vlastních informací, přistupovat k obsahu uloženém v parametru value budeme pomocí parametru key.

browserCaps

Když browser požádá server o stránku, zašle v HTTP hlavičce požadavku informace o klientovi označené jako UserAgent. Je tam hlavně verze operačního systému a prohlížeče. ASP.NET toho nadšeně využívá a vlastnosti kódu generovaného ze serverových ovládacích prvků je přizpůsobeno zařízení, na kterém má stránka běžet. Nastavení uvedené ve větvi browserCaps umožňuje ovlivnit a přepsat standardní chování - takže Opeře můžete například zakázat tabulky atp. Na toto nastavení se blíže podíváme třeba někdy jindy, v současné chvíli nás příliš nezajímá.

customErrors

Zato tato část je velmi zajímavá. Snad každý webhosting už dnes umožňuje nastavení stránky, která se čtenáři zobrazí při chybě 404, která nastane při nenalezení daného zdroje. My si na tomto místě můžeme ošetřit všechny HTTP chyby. Úvodem je ale třeba říct, že se toto nastavení týká jen souborů v kompetenci ASP.NET, tedy většinou jen souborů s příponou aspx.

Ukázka použití této sekce:

<configuration>
  <system.web>
    <customErrors defaultRedirect="neznamaChyba.html" mode="on" />
      <error statusCode="404" redirect="strankaNenalezena.html" />
      <error statusCode="500" redirect="chybaNaServeru.html" />
    </customErrors>
  </system.web>
</configuration>

Parametrem mode elementu customErrors s hodnotou on celý mechanismus zapínáme. V parametru defaultRedirect určíme stránku, která bude klientovi odeslána pokud nebude číslo dané chyby nalezeno ve vnořených elementech error. V těch v parametru statusCode nejdříve určíme pro který chybový kód se má daná stránka použít a pak v parametru redirect vypíšeme její adresu.

Předchozí kód tedy znamená: Když nastane chyba 404, skoč na stránku stankaNenalezena.html. Když nastane chyba 500, skoč na stránku chybaNaServeru.html. a když nastane jiná chyba, skoč na stránku neznamaChyba.html.

Pro chybové strany je vhodné používat buď čistý HTML kód nebo velmi jednoduché ASP.NET stránky nezávislé na databázi atp. To proto, aby se na stránce informující o chybě žádná další chyba neobjevila.

Stránka, která je tímto mechanismem volána, dostane adresu strany, na které se vyskytnula chyba, v parametru aspxerrorpath (například tedy strankaNenalezena.aspx?aspxerrorpath=zidle/index.aspx). Takže si můžete například evidovat chyby k pozdější opravě.

location

Tato struktura nemusí být nutně umístěna v části system.web, může se nacházeti i o úroveň níže. Můžeme s pomocí ní definovat rozdílná pravidla pro různé části webu. Více se s touto částí seznámíme v části o autentifikaci.

pages

V této části můžete globálně ovlivňovat nastavení, která lze provést ve stránkové direktivě Page, uváděné na začátku každé ASPx stránky. Element pages neobsahje žádné elementy vnořené, má jenom parametry. Pojďme si některé důležité vyjmenovat:

sessionState

Mocné parametry ovlivňující funkčnost sessions. Až budeme popisovat tuto technologii, vysvětlíme i možnosti jejího konfigurování.

Autentizace a autorizace

Autentizace označuje proces, při kterém rozpoznáváme jednotlivé uživatele. Zkrátka přihlašování. Znáte to jistě z mnoha internetových služeb - zaregistrujete se, server si vás zařadí do databáze a od příště se přihlašujete za pomoci uživatelského jména a hesla. Většinou se při tomto postupu využívá služeb sessions, ale to je nevýhodné z toho hlediska, že musíte pro každou zabezpečenou stránky vkládat kód potřebný k zabezpečení. ASP.NET v tomto nabízí mnohá vylepšení - v souboru web.config totiž najdeme část authentication.

Ta má jeden zásadní parametr - mode. Ten má tři parametry:

Využíváme-li režimu Forms, musíme v souboru web.config nadefinovat uživatele nebo skupiny uživatelů a adresáře, do kterých budou nebo nebudou mít povolen přístup. Dále z konfiguračního souboru odkážete na stránku s přihlašovacím formulářem, kam budou přesměrování všichni odepření uživatelé.

Tato nastavení si ukážeme na příkladu:

<configuration>
  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="vstup.aspx" />
    </authentication>
    
    <location path="tajné">
      <authorization>
        <deny users="?" />
      </authorization>    
    </location>
  </system.web>
</configuration>

Tag Forms má několik atributů. Nejdůležitější je zřejmě loginUrl, která definuje místo, kam bude přesměrován uživatel nemající oprávnění prohlížet stránku. Pokud na jedné doméně provozujete více aplikací využívajících tuto technologii, je vhodné nastavit i atribut name. Ten určuje jméno cookie (defaultně ASPXAUTH). Pokud by uživatel navštívil obě vaše služby na jedné doméně se stejným názvem cookie, přihlášení do jedné z aplikací by zaniklo. Zajímavá je volba timeout - pomocí ní nastavíte, jak dlouho má přihlášení vydržet při nečinnosti uživatele. Osobně doporučuji nastavit více a nutit návštěvníka k důslednému odhlašování, ale je to možná jedno. Standardní hodnota je třicet minut.

Tagy allow (nebylo použito - vysvětlím) a deny souvisí s tzv. autorizací. To je postup, při kterém zjišťujeme, zda má daný uživatel právo na danou akci. To, že jsme se přihlásili neznamená, že máme v systému právo na všechno. Do jistých adresářů přístup mít můžeme, do jiných ne, při autorizaci toto právo ověřujeme.

V části authentification definujeme hlavně stránku s přihlašovacím formulářem, vstup.aspx. Zajímavější je část kódu uzavřená v elementu location. O tom jsme si řekli jen trošku - nyní si můžete vidět, jak v praxi funguje. Část v něm obsažená se bude vztahovat jen k podadresáři tajné. Zrovna tady to znamená, že do adresáře tajné nebudou mít přístup nepřihlášení uživatelé. To způsobil tag deny s parametrem users="?". Deny znamená odmítnout, otazník má v tomto případě význam "všichni nepřihlášení uživatelé". Takže: "Odmítni všechny nepřihlášené uživatele." Vedle deny je ještě tag allow, který uživatele pro změnu vpouští. Tento zápis:

<allow users="?">
<deny users="*" />

Znamená "Povol přístup všem nepřihlášeným uživatelům, přihlášené odmítni." To je vskutku originální řešení. Všimnout si můžete jedné vlastnosti - podmínky se vyhodnocují popořadě, pokud nějakou z nich uživatel splní, přestane se se zpracováváním dalších. Pokud bych výše zmíněné tagy obrátil, nefungovalo by to, protože by to nejdříve odmítlo všechny uživatele ... a dál by se tím server nezabýval.

Pořád něco chybí, že? Ano, nyní musíme navrhnout přihlašovací stránku. O tom, jestli uživatele známe nebo ne, tedy jestli přihlášen bude, rozhodujeme sami, autentifikačnímu mechanismu v .NETu jenom v případě úspěchu sdělíme, že tento uživatel je nyní považován za přihlášeného.

Automatické ověřování

No, měl bych vám povědět o tom, že se o rozhodování, jestli uživatel je či není vpuštěn, nemusí rozhodovat váš skript, ale že i to umí sám .NET. Do souboru web.config můžeme "natvrdo" zapsat uživatele a jejich hesla. To se může v některých případech hodit (velmi uzavřené skupinky lidi pracující na jednom projektu) a proto vám ukážu způsob práce s tím:

Využívá se k tomu tag vnořený do elementu forms, který se jmenuje credentials. Do něj vkládáme další elementy user u nichž definujeme uživatelská jména a hesla. Například tedy:

<forms loginUrl="vstup.aspx">
  <credentials>
    <user name="lukax" password="numeri" />
  </credentials>
</forms>

Uživatelů může být samozřejmě nadefinováno libovolné množství. Jakmile budete v kódu potřebovat ověřit, zda je uživatelské jméno a heslo správné, stačí zavolat metodu

FormsAuthentication.Authenticate(uzJmen, heslo)

která vrátí logickou hodnotu - true když jsou údaje správné, false pokus nikoli.

Když už víme, jestli uživatele známe (ať už díky porovnání s databází, XML či obyčejným textovým souborem), musíme systému sdělit, že má daného uživatele považovat za přihlášeného. K tomu máme dvě možnosti.

global.asax

Nejen serverové ovládací prvky mají své události. I postup zpracování HTTP požadavku ASP.NET runtimem můžeme ovlivňovat v soutoru zvaném global.asax. Ten neobsahuje žádné konfigurační nastavení, ale "pouze" kód. Ten je uložen v předem definovaných metodách, které se spouští v různých okamžicích zpracovávání stránky.

Takže například můžeme do tohoto souboru uložit následující kód:

<script language="VB" runat="server">
  Sub Application_BeginRequest(Object sender, EventArgs e)
    Response.Write("Byl jsem tu.")
  End Sub
</script>

Událost Application_BeginRequest nastane ještě před zpracováním vašich ASP.NET programů. Takže pokud ten glosal.asax soubor umístíte do adresáře s rootem vaší aplikace (soubory global.asax nejdou zanořovat a doplňovat se jako web.config - umisťovat je musíte do WWW rootu, na hostingu to je většinou adresář www), všechny volané stránky budou mít na počátku text "Byl jsem tu."

Tyto události jsou samozřejmě součástí objektového modelu Basic Class Library .NET Frameworku - najdete je ve třídě System.Web.HttpApplication.

Je jich poměrně dost, nám budou stačit podrobnosti o dvou nejčastěji používaných:

Cachování

Klasické vytváření stránek bez generování skrze ASP či PHP má jednu velkou výhodu - je to nesmírně nenáročná metoda co se zátěže serveru týče. Přijde požadavek, IIS vyzvedne požadovanou stránku na disku a pošle ji. Není s tím spojeno mnoho práce.

Pokud ovšem vytváříte komplikovanější aplikace a zvýší se vám návštěvnost, mohou nastat nesmírné problémy s výkonem. Ony jsou totiž takovéto aplikace dosti neefektivní - pro mnoho uživatelů znovu a znovu generují de facto stejný obsah. Proto byla zavedena možnost cachování obsahu, což je vlastně odeslání dříve vygenerovaného obsahu bez nutnosti jeho opětovného vytváření.

Musíme rozlišovat mezi tím, kde se budou uchovávat tyto vygenerované stránky, obyčejné HTML soubory. Často je to na klientovi, ten pak může například obrázky získávat z již načteného obsahu a šetří se tím linka směrem k uživateli. Cachovat se může i na proxy serveru - například pokud větší firma potřebuje omezit zátěž svých internetových linek, nasadí počítač mezi všechny uživatele a zbytek Sítě a ten bude archivovat často žádaný obsah. Nadále je možné uchovávat tyto vygenerované výsledky přímo na serveru. To zrychlí odezvu na požadavky pro uživatele, přestože to pro něj nebude znamenat žádné zrychlení natahování.

Cachování celé stránky

V ASP.NET se tento úkon provádí velmi jednoduše. Stačí přidat do stránky, kterou chceme cachovat novou stránkovou direktivu OutputCache. Její nejdůležitější parametr je Location. Ten určuje, kde se bude cahcovat. Možné hodnoty jsou Any (standardní hodnota - kdekoliv), Client (pouze na klientovi), Downstream (pouze na proxy serverehc), None (nikde - tímto můžeme cachování vypnout), Server (pouze na serveru).

Další zajímavou vlastností je Duration - určuje, po jak dlouhou dobu má server obsah cachovat a kdy vygenerovat nový. Čím vyšší hodnotu nastavíte, tím méně výkonu budete potřebovat, na druhou stranu bude obsah méně aktuální. Po vypršení zadaného počtu sekund od prvního požadavku, který se po tu dobu jako jediný skutečně generoval, se prohlásí obsah cache za neplatný a nový požadavek vyvolá nové generování. Příklad využití:

  <%@ OutputCache Location="Server" Duration="600" %> 
     ' Stránka bude cachovaná po dobu deseti minut na serveru.

Stojíme ale před problémem - co když máme stránku, jejíž funkčnost ovlivňují parametry? Například typický soubor clanek.aspx, který na základě QueryStringu id zasílá klientovi články z informační části webu by nebyl příliš funkční, pokud by se zacachovala podoba prvního vyžádaného článku.

To tato metoda řeší. Automaticky se při cachování bere ohled na všechny parametry. To ale nemusí být žádoucí vlastnost - někdy nemusí takovýto parametr ovlivňovat funkčnost stránky. Existuje parametr VaryByParam, do jehož hodnoty můžeme zadat názvy parametrů oddělené čárkou, na jejichž obsah se má brát při cachování ohled. Do hypotetického souboru clanek.aspx bychom tedy mohli vložit:

  <%@ OutputCache Location="Server" Duration="600" VaryByParam="id" %>

Pak by se do cache uložili soubory clanek.aspx?id=5, clanek.aspx?id=18, ale už ne clanek.aspx?id=18&zRss=1, protože na parametr zRss není brán ohled a stránka s id 18 už cachována je. Dále existují možnosti VaryByHeader (rozlišuje podle hodnoty v HTTP hlavičce žádosti) a VaryByCustom (vlastní nastavení), které zatím necháme být.

Cachování části stránky nebo objektu

Problém je v tom, že stránky se mohou uživatel od uživatele lišit. Jednotliví návštěvníci mohou vyžadovat možnost personalizace obsahu atp. Třeba takový diskusní server - z databáze se pro každého návštěvníka musí znovu a znovu natahovat podobné údaje, přestože si každý z nich nastavil jinou barvu pozadí. Pokud chceme cachovat na serveru nebo na proxy, nemůžeme každému z nich poslat stejnou stránku.

Řešení jsou dvě a obě se vztahují ke cachování na straně serveru: Můžeme společné úseky vložit do uživatelského serverového ovládacího prvku, jaký jsme popisovali ve čtvrtém díle tohoto seriálu. Ten je možné cachovat úplně stejně jako obyčejnou stránku - takže můžeme například sloupeček se zprávami generovat při každém požadavku znovu zatímco část stránky s anketou může být generována jen každou hodinu nebo dvě.

Za druhé můžeme využít objektu Cache, do kterého můžeme vložit libovolný jiný objekt (často například DataSet) a nastavit dobu, po kterou bude cachován. Tato metoda umožňuje rapidně snížit zatížení databázového serveru, což je například v kombinaci s používáním MSDE velmi žádoucí. Tato metoda je velmi mocná, ovšem její síla se plně projeví až v kombinaci s databázemi, tudíž jí prozatím pominu.

Možnosti cachování jsou v ASP.NET velmi silné. Můžete například definovat závislost cachovaného obsahu na určitém souboru, takže po jeho změně se obsah vygeneruje znovu, což je velmi užitečné pokud například načítáme data z XML souborů.

Závěrem

Dnešní lekce nebyla zrovna moc prakticky zaměřená, ukazuje však možnosti, které, pokud si ASP.NET oblíbíte, budete zcela jistě často používat.

Lukáš Lánský
Veškeré náměty, dotazy a připomínky pište na adresu lansky@czech-ware.net.