Klasické ASP (Active Server Pages) zavedlo koncepci tzv. webových aplikací. Webové aplikace představují soubor několika .asp stránek a jednoho global.asa. ASP.NET na tuto koncepci navázalo a dále ji rozšířilo.

Webovou aplikaci ASP.NET mohou tvořit ASP.NET stránky (soubory s příponou .aspx), global.asax, webové služby, uživatelské kontroly, konfigurační soubory a další. Stejně jako u původního ASP je webová aplikace definovaná pomocí aplikačního rootu v IIS (Internet Information Server). Aplikační root lze snadno vytvořit pomocí IIS snap-in MMC (Micorosft Management Console). Ve většině případů se vytvářením aplikační rootu nemusíte zabývat, neboť tak za vás učiní poskytovatel webhostingu pro vaši aplikaci.

Důležité je podotknout, že úroveň izolace aplikace, která se při vytváření aplikačního rootu pomocí snap-in nastavuje, nemá na izolaci ASP.NET aplikace žádný vliv. ASP.NET totiž beží v samostatném procesu a používá odlišný mechanismus. Vyznačením aplikačního rootu se vytvoří tzv. aplikační doména, která je izolovaná od ostatních aplikačních domén, nesdílí s nimi paměťový prostor a tedy ani data uložená v Application a Session objektech. V případě „spadnutí“ aplikace pak nejsou ostatní aplikace běžící na stejném IIS serveru postiženy.

Typická webová aplikace ASP.NET obsahuje mimo jiné tyto tři součásti:

  • 1) podadresář bin – tento podadresář je umístěn pod aplikačním rootem a používá se pro umístění .NET komponent (assembly).
  • 2) global.asax – nástupce původního global.asa, který umožňuje deklaraci proměnných na úrovni aplikace a programové ošetření událostí generovaných na úrovni aplikace
  • 3) web.config – soubor s konfiguračním nastavením ASP.NET aplikace

Komponenty v ASP ve znamení registry

V ASP se zkompilovaný kód používal ve formě COM komponent, které bylo třeba na serveru nejdříve registrovat pomocí nástroje regsvr32.exe a až poté se daly používat v .asp stránkách. Registrací se provedl zápis do registry s uvedením tzv. ProgID a fyzickým umístěním zkompilovaného kódu ve formě .dll a dalších údajů o komponentě. Instance objektu se vytvářela voláním Server.CreateObject(„…“), kde atributem bylo toto ProgID, např. CDONTS.NewMail. Při vytváření se tak opět využívaly registry.

Tento model obsahoval pro internetové aplikace významné nevýhody. Zejména byl nutný přímý přístup na server, kvůli nutnosti registrace komponenty, dále registrovaná komponenta byla přístupná pro všechny ostatní aplikace, což nebylo vždy žádoucí a v neposlední řadě v případě nutnosti výměny komponenty, bylo potřeba zastavit celý IIS server, což znamenalo výpadek fungování nejen dané aplikace, ale celého IIS serveru.

Komponenty v ASP.NET patří do podadresáře bin

Všechny zmíněné neduhy používání komponent v ASP aplikacích odstraňuje ASP.NET. Komponenty v ASP.NET jsou zapouzdřené v assembly a pro použití komponenty v ASP.NET aplikaci stačí pouze tuto assembly zkopírovat do podadresáře bin. Není potřeba mít přímý přístup na server, kopírování lze provést např. pomocí FTP. Assembly umístěné v podadresáři bin jsou automaticky nahrány a ihned připraveny k používání.

Kde bere ASP.NET informaci o tom, co komponenta umí, když se do registry nic nezapisuje? Přímo z assembly, které kromě zkompilovaného kódu obsahuje metadata a je tudíž samopopisné. Potřebné informace jsou tedy umístěné společně s kódem na jednom místě, registry jsou zbytečné.

Jelikož je komponenta umístěna v podadresáři bin aplikačního rootu, je dostupná pouze dané aplikaci. Ostatní aplikace k ní nemají přístup. Je-li potřeba aby byla komponenta přístupná všem aplikacím, je nutno ji zaregistrovat do Global Assembly Cache.

Pro výměnu komponenty již není nutno zastavit a spustit IIS. ASP.NET totiž využívá notifikace změn souborů v podadresáři bin. Jakmile je soubor s assembly přepsán, nastane událost, kterou ASP.NET zachytí a učiní následující. Vytvoří novou aplikační doménu, nahraje do paměti komponentu z přepsaného soubory assembly a veškeré nové požadaky směřuje do nové aplikační domény. Původní aplikační doménu odstraní, jakmile jsou obslouženy předchozí požadavky v ní.

Abych demonstroval toto chování, vytvořil jsem jednoduchou webovou aplikaci, která fyzicky vymění soubor s komponentou, kterou používá a simuluje tak změnu verze. Nejprve jsem ve Visual Studiu .NET založil nový projekt typu Class Library s názvem Komponenta. Obsahuje jednoduchou třídu Class1 s metodou Verze(), která vrací textový řetězec. Komponentu jsem dvakrát zkompiloval, pokaždé jsem upravil metodu Verze() tak, aby vracela jiný textový řetězec a výslednou assembly Komponenta.dll jsem pod názvy Komponenta1.dll a Komponenta2.dll zkopíroval do dočasného adresáře. Tato komponenta bude představovat různé verze aplikační logiky.

Kód metody je:

    public string Verze()
    {
     return „Komponenta verze č. 1“;
    }

Poté jsem založil nový projekt typu ASP.NET Web Application s názvem WebAppKomp, který bude tvořit webové rozhraní. Do podadresáře bin jsem zkopíroval jeden ze souborů komponenty a přejmenoval jej na Komponenta.dll, oba soubory komponenty jsem pak zkopíroval do podadresáře coms pod adresářem bin. Protože webová aplikace bude komponentu volat, je třeba přidat na ni referenci. To se provádí v Solution Exploreru kliknutím pravým tlačítkem na References, z menu vyberte Add Reference… a na záložce Projects pomocí tlačítka Browse… najděte soubor Komponenta.dll.

Na plochu webového formuláře jsem natáhl čtyři ovládací prvky typu Label a jedno tlačítko. Kliknutí na tlačítko vyvolá spuštění následujícího kódu:

  private void Button1_Click(object sender, System.EventArgs e)
  {
    int cyklus;
    Application.Lock();
    Komponenta.Class1 objComp = new Komponenta.Class1();
    cyklus=(int)Application[„Cyklus“];
    cyklus=cyklus-1;
    Application[„Cyklus“]=cyklus;
    if ((int)Application[„Cyklus“]==2)
    {
      if (objComp.Verze()==“Komponenta verze č. 1″)
      {
        Application[„path“]=Server.MapPath(„bin/coms/Komponenta2.dll“);
      }
      else
      {
        Application[„path“]=Server.MapPath(„bin/coms/Komponenta1.dll“);
      }
    }
    Label2.Text=Application[„Cyklus“].ToString();
    Label4.Text=objComp.Verze();
    Application.UnLock();
  }

Ten, kromě volání metody Verze() komponenty, zajišťuje i řízení cyklu aplikace a odkaz na fyzické umístění komponenty v jiné verzi, než která je právě v aplikaci načtená. Jakmile cyklus končí, stane se následující: do Application["path"] se zapíše fyzická cesta na novou komponentu. Při následujícím kliknutí se v události Page_Load překopíruje přes soubor s nataženou komponentou (Komponenta.dll) soubor s jinou verzí komponenty. Požadavek, který se právě vykonává, ještě ale neskončil, proto výsledek volání metody Verze() stále vrací stejnou hodnotu. Až následující požadavek způsobí natažení aktualizované komponenty do paměti a protože dochází k založení nové aplikační domény, spustí se událost Application_Start v global.asax, kde se nastaví proměnná pro cyklus na počáteční hodnotu.

Kód kopírování assembly s komponentou:

  private void Page_Load(object sender, System.EventArgs e)
  {
    Label2.Text=Application[„Cyklus“].ToString();
    if ((int)Application[„Cyklus“]==2)
    {
      System.IO.File.Copy(Application[„path“].ToString(),Server.MapPath(„bin/Komponenta.dll“),true);
    }
  }

Kód v global.asax:

  protected void Application_Start(Object sender, EventArgs e)
  {
    Application[„Cyklus“]=6;
  }

Je třeba upozornit na to, že jelikož se jedná o webovou aplikaci, ke které má přístup více uživatelů než jeden, po kliknutí na tlačítko může být už cyklus aplikace v jiné fázi, než byl po minulém kliknutí (jiní uživatelé klikali také), takže pak cyklus nepůsobí „spojitě.“

Celou aplikaci si můžete vyzkoušet.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Žádný příspěvek v diskuzi

Odpovědět