Jak je to s cestami a adresami v ASP.NET

6. díl - Jak je to s cestami a adresami v ASP.NET

Tomáš Herceg       5. 9. 2010       ASP.NET WebForms, ASP.NET/IIS, HTTP/HTML, .NET       7959 zobrazení

V tomto díle našeho seriálu se podíváme na adresy a cesty v ASP.NET aplikacích. Řekneme si, jak zjistit absolutní URL aplikace, i cestu ve filesystému k jejím souborům.

Tento kratší díl našeho seriálu se taky nebude zabývat vývojem komponent, stejně jako minulý díl, ale doufám, že bude užitečný.

V ASP.NET aplikacích potřebujeme často zjišťovat či převádět různé cesty k souborům či webové adresy. Většinu z nich jsme schopni získat ze třídy HttpRequest, ale u některých je to trochu složitější.

Je potřeba rozlišovat pojmy adresa a cesta. Adresa je absolutní či relativní URL, které používáme pro přístup ke stránce (nebo něčemu jinému) pomocí protokolu HTTP. Adresa se zadává do prohlížeče anebo třeba do odkazů ve stránce.

Cestou rozumíme cestu v souborovém systému, která určuje, kde leží daný soubor. Pozor, tady jde o cestu v souborovém systému serveru, ne lokálního počítače, kde si uživatel prohlíží stránku! Cestu používáme, pokud z webové aplikace potřebujeme pracovat se soubory ve vlastní složce (jinam nás bezpečnostní nastavení serveru většinou nepustí, i když jsou výjimky).

Ještě jeden pojem je třeba vysvětlit, a to virtuální adresa. Je to adresa začínající vlnkou, která značí kořenový adresář webové aplikace. Pokud aplikace běží na adrese http://www.vbnet.cz, pak adresa ~/Forum.aspx reprezentuje stránku http://www.vbnet.cz/Forum.aspx. Pokud by aplikace běžela na adrese http://localhost/Test/, pak by to byla stránka http://localhost/Test/Forum.aspx.

Pozor, virtuální adresy jsou věcí ASP.NET, prohlížeče je z logiky věci nezná (neví, kde je kořen aplikace). Nelze je tedy použít všude, jen u elementů ve stránce, které mají runat=”server”.

 

Přehled funkcí

Vzhledem k tomu, že v cestách a adresách a funkcích, které je poskytují, je značný zmatek, snad pomůže tato přehledová tabulka. Spouští se stránka Default.aspx v adresáři test, tedy ~/test/Default.aspx.

Aplikace běžící na vývojovém serveru ve Visual Studiu na http://localhost:58414/UrlTest/
Request.ApplicationPath /UrlTest
Request.AppRelativeCurrentExecutionFilePath ~/test/Default.aspx
Request.CurrentExecutionFilePath /UrlTest/test/Default.aspx
Request.FilePath /UrlTest/test/Default.aspx
Request.Path /UrlTest/test/Default.aspx
Request.PhysicalApplicationPath d:\Temp\UrlTest\
Request.PhysicalPath d:\Temp\UrlTest\test\Default.aspx
Request.RawUrl /UrlTest/test/Default.aspx?test=test
Request.Url http://localhost:58414/UrlTest/test/Default.aspx?test=test
HostingEnvironment.ApplicationPhysicalPath d:\Temp\UrlTest\
HostingEnvironment.ApplicationVirtualPath /UrlTest

 

Aplikace běžící na IISce na http://localhost:12345/
Request.ApplicationPath /
Request.AppRelativeCurrentExecutionFilePath ~/test/Default.aspx
Request.CurrentExecutionFilePath /test/Default.aspx
Request.FilePath /test/Default.aspx
Request.Path /test/Default.aspx
Request.PhysicalApplicationPath D:\Temp\UrlTest\
Request.PhysicalPath D:\Temp\UrlTest\test\Default.aspx
Request.RawUrl /test/Default.aspx?test=test
Request.Url http://localhost:12345/test/Default.aspx?test=test
HostingEnvironment.ApplicationPhysicalPath D:\Temp\UrlTest\
HostingEnvironment.ApplicationVirtualPath /

 

Co co znamená?

Request.ApplicationPath a HostingEnvironment.ApplicationVirtualPath

Tyto dvě vlastnosti vrací to samé – relativní adresu ke kořeni aplikace na serveru. Protože ve druhém případě běží aplikace přímo v kořeni, je cesta jen /. V prvním případě je /UrlTest. Druhá varianta přes HostingEnvironment se používá v případě, že nemáme instanci třídy HttpRequest. Pokud jsme ve stránce, máme ji zpřístupněnou přes vlastnost Request. Pokud jsme jinde, můžeme ji získat přes HttpContext.Current.Request. Někde to ale nejde (například v Global.asax v Application_Start, pokud jsme v integrated módu na IISce). Tam pak použijeme právě HostingEnvironment.

Request.AppRelativeCurrentExecutionFilePath

Virtuální adresa k právě vykonávanému souboru (stránce atd.) v rámci aplikace.

Request.CurrentExecutionFilePath, Request.FilePath a Request.Path

Tyto funkce vrací to samé, liší se jen při použití funkce Server.Transfer (postrčení jiné stránky, než na jakou bylo dotázáno). Request.FilePath a Request.Path vrací relativní adresu ke stránce, na níž byl původní požadavek, Request.CurrentExecutionFilePath vrací adresu stránky, která se skutečně odeslala.

Pokud tedy ve stránce Transfer.aspx zavolám Server.Transfer(“test/Default.aspx”), budou mít Request.FilePath a Request.Path hodnotu /Transfer.aspx, zatímco Request.CurrentExecutionFilePath hodnotu /test/Default.aspx.

Jaký je rozdíl mezi Request.Path a Request.FilePath, to opravdu nevím. V referenčních zdrojácích jsou obě implementované jinak. Víte-li někdo, podělte se v komentářích.

Request.PhysicalApplicationPath a HostingEnvironment.ApplicationPhysicalPath

Vrací cestu v souborovém systému serveru ke kořenovému adresáři aplikace. Pokud chcete zapisovat něco třeba do adresáře App_Data pomocí kódu v aplikaci, tohle jsou ty správné vlastnosti. Anebo použít funkci Server.MapPath("~/App_Data").

Varianta přes HostingEnvironment je opět pro případy, kdy nemáme instanci HttpRequest a HttpContext.Current vrací null.

Request.PhysicalPath

Vrací cestu v souborovém systému ke stránce (skriptu), který se právě provádí.

Request.RawUrl

Adresa (relativní vůči kořeni serveru), na kterou se klient skutečně dotazoval, včetně QueryStringu. Používá se často pro redirect na stránku, kde právě jsme (pro zrušení postbacku například po smazání položky, aby zmáčknutí F5 v prohlížeči nevyvolalo požadavek na smazání znovu) – Response.Redirect(Request.RawUrl).

Request.Url

Vrací celou URL adresu aktuálního požadavku, ne jako string, ale jako System.Uri.

 

Absolutní URL adresa aplikace

To, co mi vždy v ASP.NET chybělo je HostingEnvironment.AbsoluteApplicationUri nebo něco podobného – absolutní URL adresa aplikace. V prvním případě, když běžíme na lokálním serveru, nechť vrací http://localhost:58414/UrlTest, když na IISce, nechť http://localhost:12345/.

Taková funkce nikde bohužel není (anebo jsem ji nenašel, ale hledal jsem dost dlouho), je tedy třeba si ji napsat. Nedávno jsem se ptal Michala Valáška, jak to dělá, a zjistil jsem, že prakticky stejně jako já.

 

Já obvykle používám třídu Globals.cs, která obsahuje některé často používané a užitečné funkce, například právě vlastnost ApplicationAbsoluteUri. Ta vypadá zhruba takto:

     private static object applicationAbsoluteUriLocker = new object();
private static string applicationAbsoluteUri;
/// <summary>
/// Vrací absolutní URL kořenu aplikace
/// </summary>
public static string ApplicationAbsoluteUri
{
get
{
if (applicationAbsoluteUri == null)
lock (applicationAbsoluteUriLocker)
if (applicationAbsoluteUri == null)
{
// zjistit absolutní URL aplikace
var builder = new UriBuilder(HttpContext.Current.Request.Url);
builder.Fragment = string.Empty;
builder.Query = string.Empty;
builder.Path = HttpContext.Current.Request.ApplicationPath;
applicationAbsoluteUri = builder.ToString();
}

return applicationAbsoluteUri;
}
}

Samotná absolutní URL je uložena v privátní proměnné applicationAbsoluteUri. Při prvním volání vlastnosti ApplicationAbsoluteUri se zjistí, zda-li je proměnná naplněna a pokud ne, naplní se.

Protože se jedná o statickou vlastnost, musí být thread-safe. Zamykám se tedy na vlastní proměnné typu object, která slouží jen tomuto účelu (není dobré zamykat se na něčem jiném, časem na to zapomenete a uděláte si deadlock). Je zde vidět klasická thread-safe inicializace – kontrola přes if, pak zámek, a druhá kontrola. První if je zde proto, abychom při každém použití zbytečně nezamykali, zámky jsou pomalé (ne moc, ale znatelné to je). Pokud by dvě vlákna prošla první podmínkou zároveň nebo těsně po sobě, jedno se uspí na zámku, zatímco druhé pronikne dovnitř a zinicializuje proměnnou. Proto je nutná druhá kontrola, aby v okamžiku, kdy je do kritické sekce vpuštěno druhé vlákno, neprovádělo inicializaci podruhé (ono by to tady nevadilo, ale je dobré se tento vzor naučit – při jiném použití už to vadit může).

Samotné zjištění URL probíhá poměrně snadno – aktuální Uri si dáme do třídy UriBuilder, vymažeme QueryString (?test=blabla atd.) a Fragment (#kotva), i když ten by tam být neměl, je to věc prohlížeče, na server se neodesílá (ale pro jistotu to tam máme). A jako cestu, tedy to, co je za http://server/, dáme relativní adresu ke kořenu aplikace.

A to je celé, uložíme do proměné a vrátíme ji.

 

hodnocení článku

0 bodů / 2 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

 

 

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback