Skip Navigation LinksHome : CBC Classes : ASP.Net : Page Layout and Masterpages

Masterpages and page layout (CS218)

  1. Masterpage Basics (Important Concepts!)
    1. Site Design vs. Page Design and Why Use A Masterpage (video)
    2. Creating a Masterpage (video)
    3. Creating Web Forms (.aspx files) That Use A Masterpage (video)
    4. ContentPlaceholders and Content panels (video)
    5. Making your own ContentPlaceholders and Content panels (video)
  2. Masterpage Examples
    1. Creating a typical layout with divs, css and floats (video)
    2. Creating a typical layout with asp:panels and absolute positioning (video)
    3. Creating a typical three row layout with divs (video)
    4. Adding a footer to three row layout (video)
    5. Adding a sidebar to three row layout (video)
    6. Creating a three column layout with asp:panels (video)
    7. Adding a footer to three column layout (video)
  3. Other things to do on the masterpage
    1. Meta tags (video)
      <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    2. Fixing problems with image paths on the masterpage (video, Notes )
    3. Fixing problems with background image paths on the masterpage (video, Notes )
    4. Adding a colored background to the masterpage (video)
    5. Adding a gradient background to the masterpage (video, Notes)

ASP.Net - Problems With Image Paths


One of the frustrating things about working with ASP.Net is the different ways it treats path names. You can read Microsoft' s explanation of the way paths should work, the problem is that for some reason they don't work consistently.

In this section we look at the following:

  1. The way paths should work in theory
  2. Fixing paths for images on the masterpage
  3. Fixing paths for backgrounds on the masterpage


The way image paths should work in theory

To summarize the way that image paths should work:

  1. If the path is inside an HTML element like img , then starting the path with a "/" indicates that you should start from the webroot or top level folder. For example:<img src=/images/pic.jpg alt="picture" />
  2. If the path is inside an ASP.Net server control like asp:Image, then starting the path with a "~/" instead of "/" indicates that you should start from the webroot or top level folder. For example:<asp:Image ImageUrl="~/images/pic.jpg" ID="Image1" runat="server" />


Fixing paths for images on the masterpage

However, for some unknown reason, I've seen both methods fail many many times. Sometimes they work, sometimes they don't. I've literally spent hours building sites and pages to test this, pages that do nothing but load an image; but I can't figure out what makes it work in some cases but fail in others.

One of the fixes, that works for the <img> tag is to add the "~/" to the start of the path, and then also include runat="server". So the tag will become:

   <img src=~/images/pic.jpg alt="picture" runat="server" />

This ASP.Net source code:

    <img id="Img1" src="/images/pic.JPG" width="200" />fail <br />
    <img id="Img2" src="~/images/pic.JPG" width="200" />fail <br />
    <img id="Img3" src="images/pic.JPG" width="200" />fail <br />

    <img id="Img4" src="/images/pic.JPG" width="200" runat="server" />
        fail <br />
    <img id="Img5" src="~/images/pic.JPG" runat="server" width="200" /> <br />
    <img id="Img6" src="images/pic.JPG" runat="server" width="200" /> <br />
    
    <asp:Image ID="Image1" runat="server" ImageUrl="/images/pic.jpg" 
        Width="200px" /> fail <br />
    <asp:Image ID="Image2" runat="server" ImageUrl="~/images/pic.jpg" 
        Width="200px" /> <br />
    <asp:Image ID="Image3" runat="server" ImageUrl="images/pic.jpg" 
        Width="200px" /> <br />

is changed to the following HTML/XHTML when the .aspx file is processed.

    <img id="Img1" src="/images/pic.JPG" width="200" />fail <br />
    <img id="Img2" src="~/images/pic.JPG" width="200" />fail<br />
    <img id="Img3" src="images/pic.JPG" width="200" />fail<br />
    
    <img id="Img4" src="/images/pic.JPG" width="200" />fail<br />
    <img id="Img5" src="../images/pic.JPG" id="Img2" width="200" /><br />
    <img id="Img6" src="../images/pic.JPG" id="Img3" width="200" /><br />
    
    <img ID="Image1" src="/images/pic.jpg" style="width:200px;" />fail<br />
    <img ID="Image2" src="../images/pic.jpg" style="width:200px;" /><br />
    <img ID="Image3" src="../images/pic.jpg" style="width:200px;" /><br />

If you look closely, you'll see that the only cases that worked mapped the path to a relative path. In this case it's ../images/pic.jpg. The other thing all the successful cases had is runat="server", and they never start the path with a "/". (However, I have had the "/" work on other web sites. Hmm.)

So ... the solution is to use one of the following, but change the path to match the path to your image.

    <img id="Img5" src="~/images/pic.JPG" runat="server" width="200" /> <br />
    <img id="Img6" src="images/pic.JPG" runat="server" width="200" /> <br />
    <asp:Image ID="Image2" runat="server" ImageUrl="~/images/pic.jpg" 
        Width="200px" /> <br />
    <asp:Image ID="Image3" runat="server" ImageUrl="images/pic.jpg" 
        Width="200px" /> <br />



Problems With Background Image Paths

Fixing paths for background images on the masterpage

The other time I've seen this problem occur is with background images. In particular when the background image is set on the masterpage then the image path has to work from several different folder levels, so there has to be some way to start at the webroot.

Here's the best solution, which I found on the Internet. The first step is to add the background image to your box (body, div, asp:panel etc.) using CSS. For example, to add a background image to a div with id="banner" the CSS would be:

  background-image:url('~/images/paws.jpg'); 

Like normal images, this will break and the image won't be displayed. You won't see the broken picture icon because it's a background image, but you won't see the background image either. The next step in fixing this is to add code similar to the following to the VB page for the masterpage.

Partial Class MasterPage
    Inherits System.Web.UI.MasterPage
    Public imgPath1 As String = System.Web.VirtualPathUtility.ToAbsolute("~/images/paws.jpg")
End Class

This code builds uses VirtualPathUtility.ToAbsolute to convert from the ~/folder syntax to something that works in all of the asp files. The only change you will have to make is to change ~/images/paws.jpg to match the folder and filename for your desired background image. You can also change the name of imgPath1, which just a variable name, to anything you want. The only time you'll have to change imgPath1 is if you have more than one background image. If you do, copy and paste the

   Public imgPath1 As String = System.Web.VirtualPathUtility.ToAbsolute("~/images/paws.jpg")

line, adding one copy for each background image. You will also have to change the image path and variable name for each background image.

The last step is to change the CSS code to load the content of variable. This is done with:

  background-image:url('<%= imgPath1 %>'); 

Just make sure that imgPath1 matches the variable name you used in the VB code.

Old Notes and background image tests

I've also included all my notes from when I tried to figure this out on my own. You probably don't want to read the rest of this section, because you've already seen the optimal solution. I'm just leaving the rest of this here, because I spent quite a bit of time putting it together and I can't bring myself to delete it yet.

I tried using the background attribute in the body start tag, using all of the following path variations, but nothing worked.

<body background="~/images/pic.jpg">
<body background="/images/pic.jpg">
<body background="images/pic.jpg">
<body background="~/images/pic.jpg" runat="server">
<body background="/images/pic.jpg" runat="server">
<body background="images/pic.jpg" runat="server">

Here are the results for each of the path variations after the .aspx file was processed by the server. You can see that none of the paths changed, and none of them worked.

<body background="~/images/pic.jpg">
<body background="/images/pic.jpg">
<body background="images/pic.jpg">
<body background="images/pic.jpg">
<body background="images/pic.jpg">
<body background="images/pic.jpg">

My next tactic was to try and set the CSS background-image property on the body element. Once again I tired all of the path variations, but they all failed.

body {background-image:url(~/images/pic.jpg);}
body {background-image:url(/images/pic.jpg);}
body {background-image:url(images/pic.jpg);}

The next thing I tried was using some VB code to set the style on the masterpage's form element. It runs during the page load event. But it also failed.

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) 
      Handles Me.Load
        form1.Style.Add("background-image", "/images/pic.jpg")
    End Sub

When the .aspx was run on the server, the result was this. Note that the path looks like it should work, but it doesn't.

<form method="post" action="Default.aspx" id="form1" 
    style="background-image:url(/images/pic.jpg);">

This is the code that I finally got to work. It also runs during the page load event, but instead of hardcoding the path, it grabs the first part of the path from the Request object, then adds the folder and file to the end.

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) 
      Handles Me.Load
        Dim temp As String
        temp = Request.ApplicationPath + "/images/pic.jpg"
        form1.Style.Add("background-image", temp)
    End Sub

When the .aspx file is processed by the server, this is the result. Your path will be different, and my path may be different if the application is loaded on a different server. But regardless, the code should return the correct path and set the background image.

<form method="post" action="Default.aspx" id="form1" 
    style="background-image:url(/WebSite2/images/pic.jpg);">

The only other change you may want to make is to set the style on the body element instead of the form. You'll have to set an id attribute in the body start tag, then use the id in the VB code. You also must set runat="server" in the body tag. (Only elements with runat="server" can be accessed from code.)

For example, if you had this body tag:

  <body id="masterPageBody" runat="server">

Then the VB code should be:

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) 
      Handles Me.Load
        Dim temp As String
        temp = Request.ApplicationPath + "/images/pic.jpg"
        masterPageBody.Style.Add("background-image", temp)
    End Sub

Now that I think this through, I've come to the conclusion that it isn't a great idea. Since we set runat="server" on the body all of the events that happen on anything in the page will force a roundtrip. I'm hopeful that Microsoft will fix the whole image path problem, but in the meantime I'll try and come up with a better solution.