What’s so important about "paths"?
A young developer was struggling with the hardest problem on
earth. He was trying to show an image in two different web pages. The image was
appearing on one web page, and, the same was not appearing on another!
Following was the
Following was the
HTML
element he was struggling with:<img
id="imgAction" src="images/action.jpg" />
Guess what, the poor developer was none but me!
I still can remember, I had troubles with setting appropriate paths for different elements(
That was a great mastery to me in those early days, along with lots of other mysterious things I was going through each day.
Its obvious, I didn’t have clear understanding about setting the href or src property values appropriately for the
Its been long, those days are gone. I grew up a little, and, I don’t have any problem with those mysterious paths these days. Still today, I see lots of newbies struggle with these path related issues (See here and here) and these hurts. So, I decided to uncover those “path mysteries” for the absolute beginners (Like me in October 2004) so that, they don’t have to waste a minute for setting appropriate path values for
Please note that, this article doesn’t discuss any “rocket science”. All It talks about is some plain old basic stuff and great chance is, you already are a master of the subject matter. But, I often love to go back to the basics, and try to sharpen my knowledge, to make myself a little better then yesterday. Who knows? someone might just feel the same. If you are one of those, feel free to proceed.
I still can remember, I had troubles with setting appropriate paths for different elements(
Images/documents/videos
etc) in the web pages. I used to
struggle with putting download links in the pages and show images and/video
files (Which I still have to do) by using different HTML
elements or server controls along with
setting their different attributes (href, src etc) values. It sounds funny,
but, often I used to find myself in situations where the images were appearing
in one page and not appearing in another Or, the download links were braking
often. I wondered why! That was a great mastery to me in those early days, along with lots of other mysterious things I was going through each day.
Its obvious, I didn’t have clear understanding about setting the href or src property values appropriately for the
HTML
and Asp.net
server controls, and that’s why I had to
suffer.Its been long, those days are gone. I grew up a little, and, I don’t have any problem with those mysterious paths these days. Still today, I see lots of newbies struggle with these path related issues (See here and here) and these hurts. So, I decided to uncover those “path mysteries” for the absolute beginners (Like me in October 2004) so that, they don’t have to waste a minute for setting appropriate path values for
Asp.net
pages.Please note that, this article doesn’t discuss any “rocket science”. All It talks about is some plain old basic stuff and great chance is, you already are a master of the subject matter. But, I often love to go back to the basics, and try to sharpen my knowledge, to make myself a little better then yesterday. Who knows? someone might just feel the same. If you are one of those, feel free to proceed.
What did I
mean by "Path"?
In an
Well, these look pretty straight-forward. But, its some of those cases, you may have found yourself not making those work and you wondered how. This article will try to address those issues and reveal all mysteries.
For most kind of
How browser loads elements containing “
In
Once the
Asp.net
applications, we either use HTML
elements or Server controls for adding
several elements (Such as, Image
, HyperLink
etc.) in the pages. For an <img>
element, we need to set an “src
”
attribute value (Usually, in terms of relative URL path) that points to an
image within the application in general. Also, for an anchor <a>
element, we need to set an “href
”
value that points to a resource (Be it a page or an image or a downloadable zip
file) within the application directory. These are the attributes that I am
referring as “path
” in general. Well, these look pretty straight-forward. But, its some of those cases, you may have found yourself not making those work and you wondered how. This article will try to address those issues and reveal all mysteries.
For most kind of
HTML
element, there is a corresponding Server
control in Asp.net
.
Naturally, the server controls also have corresponding attributes that accepts
the path values as relative URLs, and, set those into theHTML
element’s path attribute that they
render in the browser. So, like the HTML
elements, there are path related issues
for server controls too. As a result, understanding the basic path related
issues for HTML
elements first will make it easier for
us to understand the Server control related path issues later.How browser loads elements containing “
path
”
attributes?In
HTTP
,
user hits a URL
in the browser (Or, does something that
hits a URL
,
such as clicking a Link
or aButton
)
and an HTTP
request is sent over the wire to the
specified web URL
.
The server in turn generates some response (Mostly in the form of HTML
markups) that the browser receives and
interprets it into the user interface in terms of some understandable output. Once the
HTML
markups are generated from the server
for a page, browser loads the HTML
first and once its is done loading, it
starts loading the elements in the HTML
markup that have “path
”
attributes. For each of those such elements (Such as, <img>, <a> <link>
<script>
etc),
browser sends an asynchronous request again to the server with the URL
that is provided in their “path
”
attributes (src
or href
). Asynchronous request
means, browser sends the requests “behind the scene”, and, doesn’t wait for the
response from server while doing other activity. So, the UI remains responsive
to the user, and, when the response is received from the server, the UI is
updated with the response data.Figure : Asynchronous loading of images in browser
Now, most of the cases, the
URL
values provided to these HTML
elements are relative, because, the
resources requested by the URL
resides within the web application’s
folder structure. While browser loads these relative paths, it calculate the
absolute URL
paths by combining the host
application’s base URL
plus the relative URL
and sends the request to the
same host application. But, if for any reason the resources (Image
files,javascript
or css
files or files to be downloaded by
users) are kept within some different web applications and served from there,
(That is, these are not kept within the web application's root folder) the URL
values contain some absolute paths.
These cases, browsers send asynchronous request to the absolute URL
provided in the path attributes and
receives responses and update the UI output. This is mostly done for optimizing
performance of web page loading at user’s browser (Because, from the browser HTTP
allows to use only two simultaneous
connections to use for each domain address and hence, it sometimes take too
much time to load all markups and resources from a single host web
application). Based upon this relative path, browser calculates an absolute path and sends a request to the server to obtain the actual resource and render or loads in the browser. Now, if for any reason the src value is set inappropriately, the browser will not be able to determine the correct
URL
for the resource, and consequently the URL
request will fail and the corresponding
resource will not be loaded or appear in the page.So, let us try to understand how browser actually determines the absolute image url based upon the relative url set to the src attribute.
Path
calculation basic rule
As has been said already, images and other resources are mostly
kept within the web application's root folder, in a designated directory and we
usually provide a relative path of the images (And other resources) so that
browser can calculate the absolute image
Now, let us assume we have a page
URL
using the provided relative path as the
src attribute value. We can of course set absolute URLs for all images and resources
in our application (Assuming that, the resources resides within the web
application’s root folder structure), but, this is highly discouraged because
in case the site URL is changed later for some reason, all of the src attribute
values will needed to be changed. That would be horrible. (Absolute URLs are
only used if the resources are kept in different server for optimizing
performance, those servers are called Content Delivery Network-CDN).Now, let us assume we have a page
http://www.mysite.com/default.aspx
,
which contains an <img>
elemtn
with the following src
attrubte value:src
= "/images/action.jpg"
As we can guess, within the web application’s root folder, there
is an “
images
” folder where there is an “action.jpg
”
file. While encountering this element, browser will try to determine an
absolute URL (http://www.mysite.com/images/action.jpg
)
and send an asynchronous request to this URL
. If the web server finds
the image at this location, it will read and send the image in the response and
browser shows it in the output.
A little
complexity
Not all pages are implemented directly within the web
application's root folder and its pretty common to implement pages under some
folder structure. So, let us assume we have a following situation in our
application:
The currently browsed page is :
The currently browsed page is :
http://www.mysite.com/pages/default.aspx
,
The img src in the page is set as :
src = "/images/action.jpg"
This will fail to load the image and show in the browser. Why?
well, its because, the browser now calculates the absolute image path as
follows:
http://www.mysite.com/pages/images/action.jpg
And, as the image is not available in the above
URL
path, browser will fail to display the
image, because, the correct image URL
should be http://www.mysite.com/images/action.jpg
.
So, how to fix this URL path?
You can fix it in two approaches, one approach is you use a
relative path based upon the current directory of current page and another is
you use a relative path based upon the site’s base
URL
.
Relative
path based on current directory:
Let us assume the following scenario:
Current directory of your page is :
http://www.mysite.com/pages/
And,
directory of requested image is :http://www.mysite.com/images/
So, for calculating the correct relative path of the image from
within the page, you should go one level up (by using
".."
)
from the "pages
" directory and then add the relative path of the image by
adding"/images/action.jpg".
So, the corrected src should be set as
follows this time:src
= "../images/action.jpg"
And, based upon the above relative path from within the /pages
folder, browser will be able to determine the correct absolute image
URL
as follows:http://www.mysite.com/images/action.jpg
And, the image will be shown in the browser.
Relative
path based on Site’s base URL:
Alternatively, you can use an image path that would let the
browser calculate the absolute url based upon the web site's base URL address.
For this, you have to set the
src
value as follows:src
= "/images/action.jpg"
(Note that, the path starts with a "/"
this time)
This will result in the browser calculating the absolute path
(Relative to the root directory) as follows, no matter in what folder structure
your page is under the web root folder.
http://www.mysite.com/images/action.jpg
So, the browser will be able to display the image successfully
in the browser.
CAUTION!
The 2nd strategy should be used only if the web application is
deployed under a web site, rather than a virtual directly in the
So, if we had a web application deployed under a virtual directory as follows:
And, if we set the
IIS
(A Virtual directory is a directory/path
name that is appended after the web site’s base URL
, pointing to a web
application's root folder. There could be multiple virtual directories deployed
under a site, each pointing to a different Asp.net
application code base.). The reason is,
browser calculates the full URL
path based upon the web site's root URL
(Not the virtual directory's root url)
plus the relative url.So, if we had a web application deployed under a virtual directory as follows:
http://www.mysite.com/app/pages/default.aspx
(app is the virtual directory here)And, if we set the
src
attribute of an image element in this
page as follows:src
= "images/action.jpg"
Browser will calculate the absolute
And, the above
URL
as follows (Using only the site URL
):http://www.mysite.com/images/action.jpg
And, the above
URL
request will fail this time because, the
correct image URL
should actually be as follows:http://www.mysite.com/app/images/action.jpg
Path
related issues with Asp.net Server controls
Enough learning on paths and URLs with
Almost every
HTML
elements, and by this time we have had a
solid understanding about how the browsers determine URL
paths for the HTML
elements. We are now knowledgeable
enough to understand the path related issues that might happens with Asp.net
Server controls.Almost every
HTML
element has a corresponding Asp.net
Server control. For example, for HTML
<img>
element,Asp.net
has the following server control:<asp:image
id="Image1" ImageUrl="~/image/action.png"
runat="server"/>
The above server control actually renders an
Figure : Visual Studio intellisence for picking
And, if the path is set by clicking the "
<img> HTML
element in the browser, and, the ImageUrl
property value is set to the src
property value of the <img>
element. Note that, when you set the ImageUrl's
property value in Visual Studio, you
usually set by using "Pick URL
" visual studio
intellisence. Figure : Visual Studio intellisence for picking
ImageUrl
propertyAnd, if the path is set by clicking the "
Pick URL
"
for any server control, visual studio sets the ImageUrl
property value with a
path starts with the character "~"
(Tilde).
What is
"~"?
"~"
(Tilde) is a special character that is
usually used to set URL
paths for Asp.net
Server controls and this character instructs
the Asp.net run time to resolve the relative path of the server control.Not clear? Let’s see some examples to make it easy:
Example1:
Say, we have an web page at the following
URL
:http://www.mysite.com/pages/default.aspx
This page contains an
<asp:Image />
element with the ImageUrl
value set as :</asp:Image
ImageUrl="~/image/action.png" id="Image1"
runat="server"/>
So, when this page is requested by the browser, the
And hence, the full relative
Asp.net
runtime will replace the "~"
with the relative path that navigates the
browser from the current folder(http://www.mysite.com/pages/
) to
the web application's root folder (http://www.mysite.com/
)
,that is, one directory up ( "..
" ), to build the
correct relative URL
of the img element.And hence, the full relative
URL
be resolved as : "~/image/action.png" =
“../image/action.jpg"
Example2:
Say, we have another web page at the following
URL
:http://www.mysite.com/default.aspx
This web page also contains an
So, when this page is requested by the browser, the
And hence, the full relative
Based upon the relative URL’s in either cases, browser will be able to determine a correct absolute
<asp:Image>
element with the ImageUrl
value set as :ImageUrl="~/image/action.png"
So, when this page is requested by the browser, the
Asp.net
runtime will replace the "~"
with the relative path that navigates
the browser from the current directory (http://www.mysite.com/
) to
the web application's root directory (http://www.mysite.com/
).
That is, with a blank ( ""
) as both current directory paths are
same now.And hence, the full relative
URL
be resolved as : "~/image/action.png" =
"/image/action.jpg"
Based upon the relative URL’s in either cases, browser will be able to determine a correct absolute
URL
for the image and hit an asynchronous
request to the server to load the image and show in the output.
User
control related path problem: A classic issue
Suppose our
Let us assume, we have a following scenario:
A user control is located at :
Asp.net
web application has an organized folder
structure for aspx pages and user controls (ascx
),
for laying out the pages and controls in a logical structure within the root
folder. Let us assume, we have a following scenario:
A user control is located at :
/UserControls/Products/UCProductDetails.ascx
The user control has an
HTML
img element : <img src=""..>
(The src
is not set yet)
A page is located at
:/Pages/Products/ProductDetails.aspx
,
which uses this user control.
Another page is located at :
/Pages/Home.aspx
,
which also uses this user control.
Figure : Accessing User control from multiple
aspx at different locations
Note that, the
<img>
element is being used within the user
control. No matter what the user control's location is within the folder
structure, when the page is requested from the browser, the Asp.net runtime
loads the page along with the user control, executes it and sends the HTML
output to the browser. So, at browser’s
end, there is only HTML
markup, and the browser will simply try
to determine the relative path of the image based upon the current location of
the page.Note that, the user control is used in both aspx page. So, if the currently browsed page is
http://www.mysite.com/Pages/Products/ProductDetails.aspx
,The src value of the
<img>
element should be set as:src
= "../../images/details.jpg"
(Because, browser has to navigate two
folder up and then search the image within the “images”
folder.But, if the currently browsed page is
http://www.mysite.com/Pages/Home.aspx
,The src value of the
<img>
element should be set as:src
= "../images/details.jpg"
(Because, browser has to navigate now
one folder up to access the image within the “images”
folder.Huston, we have a problem :(
To solve this, the correct relative
URL
of the <img>
element within the user control has to
be determined based upon folder location of the requested page. Fortunately, we
don’t have to do this as we have our old friend “~”
(Tilde). All we have to do
is to replace the HTML <img>
element with an Server control and set
the ImageUrl property that starts with "~"
(Tilde). That is:ImageUrl
= "~/images/details.jpg"
Or, we should turn the
In either case, Asp.net application will be able to calculate the appropriate relative directory at the server-end, based upon the location of the currently requested page, no matter where the page or user control is within the folder structure of the web application.
<img>
element to a server control as follows:<img
runat="server" id="imgDetails"
src="~/images/details.jpg" />
In either case, Asp.net application will be able to calculate the appropriate relative directory at the server-end, based upon the location of the currently requested page, no matter where the page or user control is within the folder structure of the web application.
What about
other elements?
Not only image elements/controls, but, there are other
Unfortunately, not all
HTML
elements and Asp.net
Server controls also, which will have
the same path related issues when used within the user controls and, the same
logic should be applied to them to solve the issues. Unfortunately, not all
HTML
elements have a corresponding server
control in Asp.net. For these kinds of elements, adding the runat=”server”
attribute and set the path starting with “~”
(Tilde) will not work. Why? because,
adding the runat="server"
converts these elements as HtmlGenericControl
at the server-end, and, this type of
object doesn't have anything to resolve the Tilde(~
)
operator to determine the correct relative URL.
For these kinds of elements,
For example, let’s say a user control has the following
Page.ResolveClientUrl()
is the perfect solution.For example, let’s say a user control has the following
HTML
elements:<script src="../js/common.js" type="text/javascript" language="javascript"/>
<link rel="Stylesheet" href="../style/common.css" type="text/css" />
As this user control could be used from any web page within the
web application, there will be path related issues with these
To solve this issue, the above elements should also be modified with the
<script>
and <link>
elements also (If paths properties are
set for one page appropriately, the same path will not work other pages in
different directory ).To solve this issue, the above elements should also be modified with the
ResolveClientUrl()
as follows: <script src='<%=ResolveClientUrl("~/js/common.js")%>' type="text/javascript" language="javascript"/>
<link rel="Stylesheet" href='<%=ResolveClientUrl("~/style/common.css")%>' type="text/css" />
Path
related issues in the Code behind and back-end
Up to now we’ve learnt how the
We can of course set path/urls at the
At the most basic level, each Server control has a
You can set the
Or simply,
This assumes that the
I explored the
Note that, the two URLs are little bit different. First one is relative in terms of current page location within
As a Page or a User control is also a control, that means, you can also call the
Or, simply
Asp.net
runtime resolves relative paths for HTML
elements and Server controls and what
are the best practices for setting paths appropriately, in different
situations. One important thing to notice, in all cases, we've discussed
setting appropriate paths in the XHTML
markups, not in the CodeBehind files. Control.ResolveUrl(string
path)
We can of course set path/urls at the
XHTML
markups if the paths/urls are well known
in design time. But, if for any reason if the path/url is not known in advance
(Say, the path/url will vary based upon some conditions) or simply if you are
more interested to set the paths/urls in the back-end, you need to know a
programmatic way for resolving correct relative paths.At the most basic level, each Server control has a
ResolveUrl()
method (Inherited from the base Control
class), that accepts a string path/url value. So, if you have a Server control
as follows:<asp:Image
ID="Image1" runat="server" />
You can set the
ImageUrl
property in the CodeBehind as follows:Image1.ImageUrl
= Image1.ResolveUrl("~/images/action.jpg");
Or simply,
Image1.ImageUrl
= “~/images/action.jpg”;
This assumes that the
action.jpg
is available in this relative path : /images/action.jpg
.
Note that, you have to supply a "root relative" path that starts with
the Tilde ("~
"), to get the correct relative path.I explored the
HTML
markup using FireBug, that is rendered
for setting the ImageUrl
in the markup, and found that, the HTML
is a little difference with the HTML
that is rendered for setting ImageUrl usingImage1.ResolveUrl("~/images/action.jpg");
in the CodeBehind, which is interesting.
Here is the difference:HTML
generated for setting ImageUrl
at Markup:<img
style="border-width: 0px;" src="../images/action.jpg"
id="Image1">
HTML
Markup generated for setting ImageUrl
at CodeBehind:<img
style="border-width: 0px;"
src="/WebSite3/images/action.jpg" id="Image1">
Note that, the two URLs are little bit different. First one is relative in terms of current page location within
/Pages/
and Second one is relative in terms of
web application's root folder. But, in either case, the request image will be
rendered from correct location in the browser.As a Page or a User control is also a control, that means, you can also call the
ResolveUrl()
in the following way also:Image1.ImageUrl
= this.ResolveUrl("~/images/action.jpg");
Or, simply
Image1.ImageUrl
= ResolveUrl("~/images/action.jpg");
VirtualPathUtility.ToAbsolute(string
path)
As each control has the
You won’t get the Control objects within the
ResolveUrl()
method, it is easily possible to invoke
it and get the correct relative path for any server control (By supplying the
root-relative path that starts with the Tilde "~
"
operator). But, what if you have to resolve a relative path from within the HttpHandler
or a HttpModule
, or
even, from within a class library?You won’t get the Control objects within the
Httphandler
or HttpModule
.
So, you can’t call theResolveUrl()
method.
Fortunately, there is an easy way. You can use the following method that
accepts the same parameter argument (Like ResolveUrl()
).VirtualPathUtility.ToAbsolute("~/images/action.jpg")
Along with this method, the
VirtualPathUtility
has many other utility methods also that
aid in calculation of various path related logic, to make our life easier.
Getting the
physical file paths from relative URLs
Determining the physical location of a file, based upon a
relative URL path is a pretty common need. You might have a requirement of
reading and writing files stored within the web application folder and you only
have the relative path/URL of the file, not the physical file location. What
would you do?
Fortunately, we have a good old friend, the
When you call the
Suppose our web application’s root folder location is as follows:
Fortunately, we have a good old friend, the
Server.MapPath().
When you call the
Server.MapPath()
with a relative path/URL, it returns the
complete physical location of the file that is stored within the web
application folder. Let us see some examples:Suppose our web application’s root folder location is as follows:
C:\applications\aspnet\www.mysite.com\
string
RootPath = Server.MapPath(“~”)
This returns the path
“C:\applications\aspnet\www.mysite.com\”
string
FilePath = Server.MapPath(“~/images/search.jpg”
This returns the path
“C:\applications\aspnet\www.mysite.com\images\search.jpg”
Please note that, the physical path of the file/folder that is
returned by the
Server.MapPath()
does not guarantee that the file or
folder exists there physically. It just maps the supplied relative path to a
physical path location based upon the web application’s root directory. It’s
your responsibility to ensure that the physical location of the file or folder
actually exists ( Using System.IO.Path.Exists(FilePath)
), before you proceed the next step.
Path
properties in Request object
There are some important Path properties in the Request object
that are kind of “Must know” for Asp.net geeks. Here are these:
Request.ApplicationPath
This returns the Application’s path relative to the Site’s path.
Please note that, the “
Please note that, the “
Application
” can be a virtual directory or the site
itself. So, if the current application is deployed under a site, for a URL http://www.mysite.com/home.aspx
,
this would simply return “/”
And, if the current application is deployed under a virtual
directory, for a
URLhttp://www.mysite.com/account/home.aspx
,
(Where account is the virtual directory name) this would return the path “/account”
This property is handy if you need to calculate a relative
URL
of any resource within the application,
if you know where in the web application this resource exists.
Request.FilePath
Returns the relative or virtual path of the current request, in
terms of the site’s
URL
.
That is, for a URLhttp://www.mysite.com/account/home.aspx
,
this would return /account/home.aspx
. It
doesn’t matter whether the application is a virtual directory or a site.
Request.CurrentExecutionFilePath
Same as
Lets see an example:
You hit a URL
Request.FilePath
(See above), except the fact that, it
returns the path even if the current page is executing as a result of invoking Server.Execute()
or Server.Transfer().
Lets see an example:
You hit a URL
http://www.mysite.com/pages/home.aspx
and calledServer.Execute(“~/pages/common/CheckStatus.aspx”)
or Server.Transfer(“~/pages/common/CheckStatus.aspx”)
within the Home.aspx
Now, the
And,
Request.CurrentExecutionFilePath
within the CheckStatus.aspx
would return/pages/common/checkstatus.aspx
(The page that is being executed from
the Home.aspx)And,
Request.FilePath
within the CheckStatus.aspx
would return /Pages/Home.aspx
(The original page that executed the Server.Execute()
or Server.Transfer()
Request.Path
This returns the
Request.FilePath
,
including any query string parameters if present.
Request.PhysicalApplicationPath
This returns the web application’s physical folder location, no
matter whether it is a Site or Virtual directory. For example,
C:\applications\aspnet\www.mysite.com\
Request.PhysicalPath
This returns the physical path of the currently requested file
in the
URL
.
For example,C:\applications\aspnet\www.mysite.com\home.aspx
To
summarize:
·
If any user control has an
HTML
element or Asp.net
server control that has any kind of path
property (src
or href
or ImageUrl
), the path value
should be started with the "~/"
(Tilde) and the element should be
converted to a Server control (By adding runat=”server”
).
·
If any page has an
HTML
element that has any kind of path
property, the path values should be started with a relative path "/"
or "../"
(Given that, the correct relative path
is set). And, for any server control in the pages, the property values should
be started with the "~/"(
Tilde).
·
If path values if to be set in the CodeBehind files, the
control.ResolveUrl(“~/path”)
has to be used. If path
values are to be set inside an HttpHandler
, or, HttpModule
, or, a class library, theVirtualPathUtility.ToAbsolute(“~/path”)
has to be used.
Isn’t it wonderful to have some clear understanding on the
basics? I wish I had that in my early days!
No comments:
Post a Comment