Monday, April 9, 2007

Designing MasterPages

MasterPages, What are they? Lets first Imagine the case where you have to build a website. Of course, the design must be the same across all the pages, so what you will find yourself doing is, you will be copying the HTML code of the design in all pages, I.e. duplicate work! so what's the alternative way? MasterPages!

MasterPages allow you to create a consistent layout for the pages in your application. A single master page defines the look and feel and standard behavior that you want for all of the pages (or a group of pages) in your application. You can then create individual content pages that contain the content you want to display. When users request the content pages, they merge with the master page to produce output that combines the layout of the master page with the content from the content page. Sounds Cool right?


For more information about how MasterPages work, please visit this link http://msdn2.Microsoft.com/en-us/library/wtxbf3hh.aspx


But, my aim in this post was not just introducing you to masterpages. I wanted to discuss the way of designing these masterpages because I faced a lot of trouble and problems when I just got started.

Professional designers use special tools like Adobe Image Ready to create nice designs, and cut the pics into boxes and tables. The Adobe Image Ready then can create an HTML page with a table and adjusting everything, images, background images, background colors,........etc. So what will you be doing is just replacing the masterpage HTML code with that you have in the HTML code you got from the Adobe Image Ready where it has all the code for all the content you made in your nice design. But please don't forget to add the following tags in the body section of the HTML code, and placing everything inside it.



<form id="form1" runat="server">

</form>

The reason for this tag is of course known, as if you didn't add these tags, and tried to put any server control in the page, these controls will throw an exception, saying "Control must be placed inside a form tag with runat="server"".

Here we come to the real problem where most of people suffer from. Lets see the case were we have a masterpage (Masterpage.master) and a content page (Default.aspx), where they are in the same directory


Everything will go really simple, cute and so smooth. No problems at all. in your content page (Default.aspx) you will find everything you placed in the masterpage. Lets first see the other situation and where the problem appears, then we will get to know what is the reason and how to solve it.



In this case, the content page (ForgotPassword.aspx) is in another subdirectory of that where we placed our masterpage. what you will usually find is that not everything you placed in the masterpage appears in your page, background images disappeared, images aren't there, and a red X mark appears instead. The only thing that acts normally is the background color.

At runtime, the master page and the content page are in the same control hierarchy – the master page is essentially a user control inside the content page. At design time, however, the master page and content page are two different entities. In fact, the master page and content page may live in different directories. During design time, it's easy to put URLs and relative paths into our master pages, but we have to be careful when using relative paths. Take the following master page excerpt as an example:

<div>
<img src="logo.gif" alt="Company Logo"
/>

<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>

As long as the master page and the web form live in the same directory, the company logo will display in the browser. When the master page and web form live in different directories, the image will not appear. The browser requests knows nothing about master pages. The browser will interpret any relative paths it finds in the HTML as being relative to the webform. If our logo and master page files are in the root directory, but the web form is in a subdirectory, the browser will ask for logo.gif from the same subdirectory. The server will respond with a 404 (file not found) error.

The good news is, the ASP.NET runtime does provide a feature called “URL rebasing”. The runtime will try to “rebase” relative URLs it finds on server-side controls inside a master page. This means the following relative path will work, no matter where the master page and web form live.

<img src="logo.gif" alt="Company Logo" runat="server" />

We’ve added a runat=”server” attribute to the image tag, making the <img> a server-side control. When the master page file and logo are in the root directory, but the web form is in a subdirectory, the ASP.NET runtime will rebase the relative path it finds in the src attribute to point to the root of the website.

The following code will also work, because we are using a server-side Image object.

<asp:Image ImageUrl="logo.gif" runat="server" />

Now lets have a look at background images, as we have to act differently with them.

<body background="logo.gif" runat="server">
<!-- the background for the body tag will break -->
<form id="form1" runat="server">
<div id="Div1" style="background-image: url('logo.gif');" runat="server">
<!-- My background is also broken. -->
</div>

If you need to use a relative path in an area where the runtime does not provide the rebasing feature, you can compute a client side URL using ResolveClientUrl and passing a relative path. ResolveClientUrl, when called from inside a master page, will take into account the location of the master page, the location specified in the HTTP request, and the location specified by the relative path parameter to formulate the correct relative path to return.

<body background=<%= ResolveClientUrl("logo.gif") %> >

When working with image paths in embedded styles, it’s often a good idea to move the style definition into a .css file. The ASP.NET runtime will rebase the path it finds inside a link tag, so we won’t have any problems locating the stylesheet from any webform. Take the following style definition in a .css file:

body
{
background-image:url('images\logo.gif');
}

Relative paths are safe inside a .css file because the browser will always request logo.gif relative to the location of the stylesheet.

13 comments:

  1. Great article, we want to know the other problems you'v faced in ASP.NET and designing, so we can benefit more and more, and keep going (Y)

    ReplyDelete
  2. Thank you for your post on Master Pages. It was very informative and well written. It also helped me to solve an issue I had with displaying an image on pages at varying subdirectories.

    Cheers!

    ReplyDelete
  3. Very Informative...
    Thanks!!! :)

    ReplyDelete
  4. Ahmed,

    Thanks a million for this article - you explained it extremely well. I was about tearing my hair out trying to resolve this issue until I found your post.

    THANKS THANKS THANKS!

    ~joe

    ReplyDelete
  5. This is very helpful. Thanks for posting this. I wonder why microsoft didn't enable the rebasing option by default and then allow you disable it explicity. When would you want the relative path to a link in your master page, but not the content page that runs with it?

    Thanks again.

    ReplyDelete
  6. Many, many thanks. You help me tremendously with the "body" trick.

    ReplyDelete
  7. Excellent article.

    ReplyDelete
  8. tanks alot .
    very usefull.

    ReplyDelete
  9. This was very helpful, thanks, I haven't faced the image problem yet but am frustrated with trying to read the master page and hence the web.sitemap from a subdirectory. Any advice would be greatly appreciated!
    Thanks!

    ReplyDelete
  10. thanks so much i m moroccan-canadian software engineer and i appreciate ur article wich helps me so much.

    ReplyDelete
  11. fuck the master page

    ReplyDelete
  12. Really helpful...thank you very much...it worked after adding runat=server, but the CSS is not working from subdirectory.Any help?

    ReplyDelete
    Replies
    1. Hey, am glad you find it that helpful.
      Will you please elaborate with your problem? What do you mean by CSS not working from sub-directory?
      Feel free to share your code or whatever, and I would love to help.

      Delete