1 Comments

Naime radi se o ovome; kako adresu: http://www.somesite.com/Proizvod.aspx?id=41
pretvoriti u ovako nešto: http://www.somesite.com/Engines/WarpCore-TDI/

url rewrite Već duže vrijeme gledam PHP site-ove koji imaju lijepo napisane URLove, i neprestano se čudim zašto malo koji web site napravljen u ASP.NETu slijedi tu praksu. Apache i PHP imaju .htaccess, koji im je tamo pred nosom, i uz malo Regex znanja svi ga koriste. Ali .net developeri nemaju takvu datoteku, ili im nije pred nosom, pa valjda malo tko zna kako u samom .net Frameworku postoji solidna podrška za prepisivanje URLova i nekoliko open source frameworka koji to isto rade bez potrebe pisanja linije koda.
Scott Guthrie je već na svojem blogu pokazao nekoliko načina za prepisivanje URL adresa. Ima ih nekoliko, ali svi se oslanjaju na metodu unutar HttpContext-a:
HttpContext.Current.RewritePath();
kojoj se može pristupiti preko BeginRequest eventa unutar Global.asax datoteke, ili izradom HttpModula koji se kasnije može reusati.

Ja neću pisati svoj url rewriter, niti pokazivati kako se radi sa spomenutom metodom, jer smatram da je za ovakve “infrastrukturne” potrebe pametnije iskoristiti neki gotov framework (osim ako se radi o učenju frameworka!). Pokazati ću kako se može iskoristiti UrlRewritingNet framework za dobiti pravilne Url adrese, te koji su trikovi, mane i prednosti upotrebe istog. [more]

Preuzeto iz dokumentacije:

What is UrlRewritingNet.UrlRewrite?
UrlRewritingNet.UrlRewrite is a module which could be embedded in an ASP.NET 2.0 application to
rewrite Urls (Internet addresses) for displaying the user another URL than used from the server. With
UrlRewritingNet.UrlRewrite you only have to define a few simple rules for rewriting your addresses.

Način rada:

  • Regex patterni url-ova su definirani u Web.config datoteci
    npr: “~/novosti/(.*)/(.*).aspx”
  • Kod svakog requesta za stranicom, UrlRewriting prolazi kroz sve patterne dokle ne naiđe na onaj koji zadovoljava upisani Url
  • Prepisivanje URLa:
    ~/novosti/naslov-vijesti/567.aspx se prepisuje u /novosti.aspx?id=567
  • stranica vidi prepisani Url

Postupak konfiguriranja UrlRewritingNet:

  1. skinite potrebni DLL sa službenog sitea i referencirajte ga u svome projektu
  2. u Web.Configu pod sekcijom <httpModules> dodajte:
    <add name="UrlRewriteModule" type="UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter"/> 
    i pod <configSections>:
    <configSections>
    <section name="urlrewritingnet" restartOnExternalChanges="true" requirePermission ="false" type="UrlRewritingNet.Configuration.UrlRewriteSection, UrlRewritingNet.UrlRewriter" />
    </configSections>
  3. Dodajte ruleove (sa regex patternima):
    <add name="novosti" virtualUrl="^~/novosti/(.*)/(.*).aspx" destinationUrl="~/news.aspx?naslov=$1&id=$2" ignoreCase="true" />
    ovo je samo jedan primjer, a vi si ih dodajte po želji, koliko god je potrebno za web site. Primjetite $1 i $2 u destinationUrl. Na to se mapira prvi i drugi regex “(.*")” iz virtualUrl (“.*” u regex jeziku znači proizvoljan broj znakova)
  4. U samom code-behindeu stranice sada možete pristupiti parametrima preko Request.QueryString, kao što ste i prije radili. Postoje još opcije da se QueryString parametri spreme u HttpContext.Items, da se parametri igroriraju i sl., ali više o tome i drugim opcijama možete pogledat u dokumentaciji frameworka.

U adresi, odnosno danim primjerima se i dalje nalazi “.aspx” nastavak. Naime, kod IIS6 web servera ASP.NET frameworku se prepuštaju samo requesti sa određenim ekstenzijama (aspx, ascx, asmx, axd,…). Da smo u ruleu (patternu) postavili virtualUrl=”~/Novosti/(.*)/” , bez aspx, taj request ne bi bio uopće proslijeđen .net Frameworku. U slučaju IIS7, Url-ovi bez ekstenzije bi trebali raditi, barem u  Integrated pipeline-u. Ako želite i na IIS6 koristiti Url-ove bez ekstenzije, morati će te konfigurirati IIS da prosljeđuje sve requeste .net-u (opis dostupan u dokumentaciji), ali takve stvari pružatelji hostinga (shared prvenstveno) rijetko dozvoljavaju. Eventualno će te ih moći nagovoriti da mapiraju .htm i .html ekstenziju na .net. Što se tiče samog Googla, mišljenja su oprečna o tome dali on više voli Url-ove bez ekstenzije ili sa njom. Ako stranica ima loš i nekvalitetan sadržaj, nikakav Url vas neće spasiti od loše pozicije u google indexu ;)

Nadam se da je pomoglo, i da će vam ovaj kratki post omogućiti da i sami primijenite popularni Url Rewriting u svome projektu!

1 Comments

Kopam ja tako po ekstenzijama za Blogengine.net (njih čak 20-tak! Ako vam je do šale, pogledajte koliko ekstenzija ima WordPress!) i naiđem na dodatak koji ispisuje vrijeme potrebno za učitavanje/iscrtavanje stranice. Kako mi je jako važno da se stranica brzo učitava, da ne bi ovih 5 posjetioca dnevno (tjedno) čekali koju sekundu previše i otišli sa stranice, valja imati precizna vremena učitavanja!

Dodam ga na blog, oduševljeno gledam vremena ispod 0,1 sekunde i divim se kako je ASP.NET brz! Potom promijenim nešto u kodu, napravim refresh stranice, čekam 5-10 sekundi da se dinamička kompilacija izvrši, kada ono u footeru opet piše: “Page loaded in 0.00569874 seconds”. Znači, nešto ne valja. Ja sam čekao barem 50-tak puta više od prikazanog vremena. [more]

Ovo je kod od ekstenzije, koji se nalazi unutar ASCX user kontrole:

public partial class User_controls_PageLoadTime : System.Web.UI.UserControl
{
    private DateTime _start;
    private DateTime _end;

    protected void Page_Init(object sender, System.EventArgs e)
    {
        _start = DateTime.Now;
    }

    protected void Page_PreRender(object sender, System.EventArgs e)
    {
        _end = DateTime.Now;
        TimeSpan time = _end.Subtract(_start);
        lblPageLoadTime.Text = string.Format("Page loaded in {0} seconds.", time.TotalSeconds.ToString());
    }
}

Kao što se vidi iz priloženog, vrijeme se mjeri od početka izvršavanja OnInit događaja, pa do PreRender događaja.

Ako pogledamo sam trace stranice:

page-load-time

vidimo da ekstenzija ne radi dobro! Za stranicu je bilo potrebno sigurno oko 4-5 sekundi za iscrtavanje, ali OnInit i OnPreRender događaji su se desili negdje u srediti samoga izvršavanja. Pregledom nekoliko dostupnih primjera nađenih na internetu se vidi da se većina primjera uglavnom bazira na ova dva događaja, ali pregledom trace rezultata možemo vidjeti da je vrijeme između ta dva događaja samo manji dio ukupnog vremena izvršavanja page life cycle-a.

Zbog toga ovdje dajem svoj prijedlog jednostavnog koda za računanje vremena potrebnog za iscrtavanje stranice. Zasniva se na događaju Application_BeginRequest koji se definiran u Global.asax datoteci. Trenutno vrijeme se spremi u HttpContext.Items Dictionary objekt (korisno spremište za objekte koji će imati životni vijek trajanja jednog requesta – npr. za DataContext od LINQ2SQLa i slično, jer se sadržaj tog Dictionarya briše nakon kraja requesta).
Na kraju same stranice (u ovom slučaju u Master stranici), u inline kodu unutar aspx datoteke se dohvati trenutno vrijeme i oduzme od vremena unutar HttpContext.Items.

Kod iz Global.asax:

void Application_BeginRequest()
{
	if(HttpContext.Current.Request.Url.AbsolutePath.Contains(".aspx"))
		HttpContext.Current.Items["load"] = DateTime.Now;
}

Provjera “.aspx” stringa unutar request URL-a je zbog mogućnosti da se BeginRequest događaj pokreće i za druge datoteke osim .aspx stranica, poput CSS, JPG,…, što je specifično za lokalni developmnet server od Visual Studia (cassini, jel?) i za IIS7 koji isto daje ASP.NET frameworku requeste na svaku datoteku i folder (IIS6 hvata samo .aspx, .asmx i slične ekstenzija).

Kod na kraju aspx stranice:

Stranica učitana u <%= DateTime.Now.Subtract( (DateTime)HttpContext.Current.Items["load"] ).TotalSeconds.ToString() %> sekundi

(Molim zanemarite nedostatak provjere dali nešto uopće postoji unutar HttpContext.Items! Ovo može rezultirati sa poznatim yellow screen of death od asp.net)

Nakon ovakve implementacije mjerenja vremena, brojka mi osobno izgleda puno uvjerljivije: 

page-load-time2

primijetite na vrhu slike desno, “ … 2.6651 sekundi”, u odnosu na prijašnjih 0.21s.

Ako postoji neki drugi način mjerenja (osim dodavanja Http Modula, za to sam previše ljen, iako pogledom na primjer od Phil Haacka vidim da koristi jako slični način mjerenja, vjerojatno i marginalno točniji), ili je ova implementacija pogrešna u nečemu, molim vas da napišete komentar ili mi pošaljete mail.