HAVIT Knowledge Base

Vývoj webových aplikací, .NET, SQL, návrh
Welcome to HAVIT Knowledge Base Sign in | Join | Help
-
Home Články Forums Obrázky Soubory

ASP.NET

Vývoj webových aplikací ASP.NET

ASP.NET Routing - alternativa k URL Rewritingu

.NET Framework 3.5 SP1 přináší alternativní přístup k URL Rewritingu - tzv. ASP.NET Routing, ve zkratce:

  • jde o modul System.Web.Routing.UrlRoutingModule a související třídy, vše z assembly System.Web.Routing (novinka v SP1 k .NET 3.5),
  • modul pracuje nad globální routovací tabulkou (RouteTable), v které je uložena uspořádaná kolekce Routes (v podstatě seznam postupně vyhodnocovaných pravidel - instancí třídy Route, resp. potomků RouteBase)
  • pravidlo v kolekci Routes může mít název, na který se pak dá odkazovat při zpětném sestavování URL,
  • pro každé pravidlo (pattern cesty) je v kolekci uložen odkaz na IRouteHandler, který má daný request obsloužit (IRouteHandler předepisuje jedinou metodu GetHttpHandler(), která vrací příslušný IHttpHandler pro odbavení requestu)
  • ASP.NET routing nedělá "rewriting", tedy nevymění surově za běhu requestu ASP.NETu cestu, ale jde o čisté řešení používající přímo nasměrování na odpovídající HttpHandler
  • routovací tabulku lze využít (a je to zásadní výhoda ASP.NET routingu) i ke zpětné rekonstrukci URL a tedy lze udělat čistě routing obousměrný (adresu veškerých odkazů a redirectů v aplikaci zjišťuji z routingu metodou GetVirtualPath).

Jak tedy implementovat ASP.NET Routing pro WebForms (původně byl zamýšlen především pro MVC, používá ho i Dynamic Data):

  1. Nareferencujeme assembly System.Web.Routing (ve VS přes References, popř. ve web.configu do system.web/compilation/assemblies.
  2. V příslušné částí web.configu (dle verze IIS system.web/httpModules, nebo system.webServer/modules) zapojíme do hry modul UrlRoutingModule:
    <add name="RoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
  3. Vytvoříme routovací tabulku (typicky z Application_Start v global.asax)
    private void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }

    public static void RegisterRoutes(RouteCollection routeCollection)
    {
        routeCollection.Add("Test", new Route("test/{MyParam}", new MyRouteHandler("~/MyFolder/Page.aspx")));
    }

    - v patternu pro routu dáváme parametry do složených závorek {parametr}
    - parametry od sebe musí být oddělený textovou konstatnou, typicky lomítkem /, ale třeba i {language}-{country}/{something} pro cs-CZ/test
    - na konci patternu můžeme použít hvězdičkový parametr {*parametr}, který požere veškerý zbývající text do konce řetězce (vstupního URL) - případné další parsování tohoto parametru je už na nás
    - připomínám, že pravidla se vyhodnocují v pořadí v jakém jsou v kolekci a uplatní se první vyhovující pravidlo (není tedy dobré začínat {*myParam}, dál už se nedostanete)
     

  4. Vytvoříme třídu implementující IRouteHandler, která bude requesty obsluhovat, v případě WebForms vracíme regulérní IHttpHandler (potomek Page) odpovídající potřebné připravené stránce, která má request obsloužit
    public class MyRouteHandler : IRouteHandler
    {
        private string _targetVirtualPath;

        #region Constructor
        public MyRouteHandler(string targetVirtualPath)
        {
            _targetVirtualPath = targetVirtualPath;
        }
        #endregion

        #region GetHttpHandler
        /// <summary>
        /// Provides the object that processes the request.
        /// </summary>
        /// <param name="requestContext">An object that encapsulates information about the request.</param>
        /// <returns>An object that processes the request.</returns>
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            // zkopírování parametrů z route do HttpContext.Items
            foreach (var urlParm in requestContext.RouteData.Values)
            {
                requestContext.HttpContext.Items[urlParm.Key] = urlParm.Value;
            }
                
            return BuildManager.CreateInstanceFromVirtualPath(_targetVirtualPath, typeof(Page)) as IHttpHandler;
        }
        #endregion
    }
  5. Část kódu v metodě GetHttpHandler ukazuje vyzvednutí parametrů zjištěných z routy a možný způsob jejich předání do stránky (přes kolekci Items HttpContextu).
  6. Ve stránce pak můžeme na takto předané parametry přistupovat
    TestLb.Text = HttpContext.Current.Items["MyParam"].ToString();
  7. A pokud bychom chtěli zkonstruovat URL stránky na základě pravidel v RouteTable použijeme např.
    Response.Redirect(RouteTable.Routes.GetVirtualPath(null, "Test", new RouteValueDictionary()
                { {"MyParam", "hodnota"}
                }).VirtualPath);
    ...chceme URL od routy Test při použití parametrů MyParam=hodnota. Pokud bychom název cesty nezadali, najde routing sám první routu, která předané parametry používá.

 

Routingu se ještě dá nastavit spousta dalších věcí:

  • defaultní hodnoty parametrů pro každou routu,
  • constrainty na jednotlivé parametry routy (regulárním výrazem, nebo i vlastním kódem vracejícím boolean),
  • jestli má reflektovat requesty na fyzicky existující soubory (třeba /Default.aspx), nebo jestli má požírat vše a řídit se výhradně definovanými routami,
  • ...a pár dalších věcí.

Je potřeba si dát pozor zejména na:

  • autorizaci - běžná autorizace (web.config, element authorization) nastavená na fyzické soubory se při routingu neuplatní, cesta je totiž jiná, museli bychom nastavit elementy location na nové cesty, ale ztratíme tím výhodu jediného místa s definicí URL (routovací tabulky) - doporučuje se autorizaci řešit z kódu,
  • relativní cesty (např. k obrázkům, stylům, atp.)

Viz též:

Doporučené zdroje:

Published 3. září 2009 15:48 by Robert Haken
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Jarda Jirava said:

Ahoj, šlo by ještě prozradit trik, jak dostat onu routovanou cestu jako akci pro formular? Pokud už bude totiž stránka generována přes ~/MyFolder/Page.aspx tak předpokládám, že v akci bude uvedena právě tato cesta, nebo se mi tam dostane správně ~/test/nejakahodnota/ ?

Díky

-- J.

září 4, 2009 14:19
 

Robert Haken said:

jardo: V ASP.NET Routingu se tohle právě na rozdíl od URL-rewritingu vůbec neřeší, pokud máš stránku /test/cosi, tak v elementu form je atribut action prostě nastaven na action="cosi".

září 4, 2009 15:12
 

Patrik said:

Ahoj, mám problém s implementací ASP.NET Routingu dle výše uvedeného příkladu. Stále mi to hlasí tuo chybu:

Error      1      Název typu nebo oboru názvů RouteCollection nebyl nalezen (pravděpodobně jste neuvedli direktivu using nebo odkaz na sestavení).      C:\inetpub\wwwroot\priklady\web\Global.asax      12      39      C:\...\web\

Error      2      Název typu nebo oboru názvů IRouteHandler nebyl nalezen (pravděpodobně jste neuvedli direktivu using nebo odkaz na sestavení).      C:\inetpub\wwwroot\priklady\web\Global.asax      17      35      C:\...\web\

Error      3      Název typu nebo oboru názvů RequestContext nebyl nalezen (pravděpodobně jste neuvedli direktivu using nebo odkaz na sestavení).      C:\inetpub\wwwroot\priklady\web\Global.asax      34      44      C:\...\web\

Prosím o pomoc s řešením problému. Předem děkuji

března 11, 2010 14:14
 

Robert Haken said:

to Patrik: musíte si do projektu přidat assembly System.Web.Routing

března 11, 2010 15:30
 

Patrik said:

Přidal jsem <%@ Assembly Name="System.Web.Routing" %> do global.asax ale hlasí mi že jej nemůže najít.

Error 1 Nelze načíst soubor nebo sestavení System.Web.Routing nebo jeden z jejich závislých prvků. Systém nemůže nalézt uvedený soubor. C:\inetpub\wwwroot\priklady\web\Global.asax 2

nedá se tento příklad u Vás stánout ve zdroji? Moc děkuji za pomoc. Patrik

března 12, 2010 16:37
 

Robert Haken said:

to Patrik: System.Web.Routing.dll je součástí .NET Framework 3.5 SP1, který si musíte nainstalovat.

března 12, 2010 16:46
 

Patrik said:

Přes Add reference jsem přidal knihovnu System.Web.Routing.dll ale stále mi to hlásí stejný problém. Už nevím kudy kam. Přikládám link na DEMOweb, na kterým Routing zkouším. Pokud budete ochotni se na to podívat a pomoci mi Routing rozběhnout, budu velice rád. Pokud ne, pochopím Vás. Děkuji v každém připadě. Patrik

http://files.uloziste.com/715b0be510cacc16/

března 15, 2010 10:59
 

Robert Haken said:

to Patrik: uloziste mi nefunguje, ale problém bude nejspíš v tom, že se Vaše aplikace/WebSite není konfigurována pro použití .NET 3.5, ale .NET 2.0. Zkuste přepnout target z Visual Studia.

března 22, 2010 0:29
 

Patrik said:

Target mám nakonfigurován na .NET Framework 3.5. Nevim proč Vám odkaz nefunguje ale posílám nový http://programujte.com/storage/2010_03_19_16_10_08_web-routing.zip Včera jsem zkoušel přidat do global souboru <%@ Import Namespace="System.Web.Routing" %> co jsem se dočetl ale také bezvýsledně. Vím že tam bude někde nějaká hloupost ale nemohu jako začínající .NEŤák  přijít kde. Moc Vám děkuji za ochotu.

března 23, 2010 9:05
 

Robert Haken said:

to Patrik: Máte to trochu divoký, ale jak jsem říkal - v zásadě potřebujete přireferencovat assembly System.Web.Routing (pravým v Solution Exploreru na WebSite a Add Reference) - což upraví příslušně web.config. Váš kód potřebuje taky assembly System.Web.Abstractions jak následně zjistíte. Dále musíte Importem nebo plným jménem použít potřebné namespace.

března 24, 2010 0:01
 

Patrik said:

:o) tak jsem se posunul. Přereferoval jsem v assembly

<add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

<add assembly="System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

a dále jsem přidal v global.asax

<%@ Import Namespace="System.Web.Routing" %>

<%@ Import Namespace="System.Web.Abstractions" %>

kompilace končí tímto:

Error 1 V oboru názvů System.Web neexistuje název typu nebo oboru názvů Abstractions (pravděpodobně jste neuvedli odkaz na sestavení). C:\inetpub\wwwroot\web-routing\Global.asax 3

Přitom System.Web.Abstractions mám ve web.config nareferovanou viz výše.  V čem tedy dělám zase chybu a jak ji napravím? Vážně Vás s tím nechci obtěžovat ale moc by mi pomohlo kdyby mi to fungovalo.

března 24, 2010 9:51
 

Robert Haken said:

to Patrik: Obávám se, že se dostáváme k úplným základům práce s Visual Studiem, webovými projekty, assembly, namespaces, atp. Což je mimo téma tohoto článku a mimo mé časové možnosti.

března 24, 2010 10:41
 

Patrik said:

Chápu. Nechtěl jsem zatěžovat. Je pravda že k .NET a Visual Studiu jsem se dostal opravdu nedávno. Celý život jsem dělal v PHP. Proto ty rezervy Visual Studia. Kdyby byla možnost pod článkem stáhnout hotový příklad tématu, jednodušeji se to pak dá pochopit a experimentovat. Ale chápu že nechcete rozdávat zdrojáky každému. I tak si ale vážím ochoty a Vašeho času.

března 24, 2010 18:11
 

Robert Haken said:

to Patrik: Nejde o rozdávání, ale mám sám co dělat, abych se vůbec vybičoval napsat miničlánek, natož k tomu ještě vyrábět demo. Vlastní kód mám většinou v rámci velkých projektů, které se zveřejnit nedají.

března 24, 2010 22:57
 

Radomír Novák said:

Dobrý den, nedaří se mi najít kde nastavit aby byly zpracovány i některé requesty na fyzicky existují soubory, např /*.aspx, poradíte?

března 28, 2010 10:45
 

Robert Haken said:

to Radomír Novák: Řídí se to nastavením property RouteTable.Routes.RouteExistingFiles, defaultní hodnota je ale false, takže by Vám to mělo fungovat, pokud jste to nepřenastavil na true (hodnotu si ověřte debuggerem).

března 29, 2010 0:31

What do you think?

(required) 
(optional)
(required) 
Enter the code you see below

Submit