Welcome to Professional ASP.NET - Chris Love's Official Blog Sign in | Join | Help

Chris Love's Official ASP.NET Blog

Chris Love's Helpful tips, tricks and pragmatic development knowledge for the ASP.NET world.
Add to Technorati Favorites


ASP Insider
How to Publish Content from Another URL in a ContentPlaceHolder Control

It seems like every week I see a person asking a question about either placing content in the ContentPlaceHolder control dynamically or from another URL in the www.asp.net forums. By URL they typically mean another page from another site. I think many of these folks are somewhat misguided as to what Master Pages are meant to solve and how they work.

The ContentPlaceHolder control is not the same thing as a Frame or even an IFrame, which have been used in the distant past to manage consistent looks and feels for Web sites and many novice Web designers still do. Primarily this is a tactic employed by a novice designer because they either do not know anything about basic programming with .NET or other web based languages such as PHP. Frames sort of went out of favor in the late 90s and now we use tables and style sheet layouts.

Old School

The idea back in the day was to say layout a frame for the header, menu or navigation that would be on every page and then a frame where the content would go. Back in the early days of the web this was a pretty good way to do things. But as pages became more sophisticated, layouts needed to be more dynamic and really holistic.

So back in the Classic ASP days, that would be the late 90s for those of you new to .NET, we started defining our layouts using include files. So we would create a separate .asp include file for the header, the navigation and then include a common layout with references to these files on each content page in the site. I even went so far as to create include files for common methods and even the Meta tag section of my pages.

Enter ASP.NET

But when ASP.NET was introduced we sort of messed up this harmony and took away the concept of include files. The first thing many of us did was substitute user controls (.ascx) for include files and did the same thing again. As we matured we started looking for ways to essentially create Skins for our sites. Various attempts were made at making this work. In my opinion none were very good.

Finally with the release of ASP.NET 2.0 we have Master Pages. While not absolutely perfect in every way they go a very long way in solving our layout issues. We can even apply them dynamically. The way they work is we can now create a consistent layout for our pages and add a control, the ContentPlaceHolder, to our page where we want to allow content pages to supply the markup. There can even be multiple ContnetPlaceHolder controls in a Master Page.

On the Content page, .aspx, there is a Content control for each ContentPlaceHolder in the Master page. It has an attribute, ContentPlaceHolderId, that references the name of the ContentPlaceHolder in the Master page, so actual order of the Content controls is not important. Everything is rendered in Design mode of Visual Studio as if it were a whole page.

So back to the Common Question

So the common question posed on the Forums.ASP.NET pages is how to place content from another URL in the ContentPlaceHolder. Which if you still want to do that, which means you are most likely page scraping or some other useless technique to get content on your site, can be done really easily. First place a Literal control in the Content control of your content page.

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">

<asp:Literal runat=server ID="ltlContent" />

</asp:Content>

asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">

<asp:Literal runat=server ID="ltlContent" />

</asp:Content>

asp:Literal runat=server ID="ltlContent" />

</asp:Content>

asp:Content>

Next we need to use the code behind and actually retrieve the foreign URL. This is done pretty easily with a WebRequest, WeResponse and StreamReader objects. First create a new WebRequest for the foreign URL. Then make the request, retrieving the response or the content of the URL to a WebResponse object. Next we need to get the stream from the WebResponse object intro a StreamReader. This is done so we can read the HTML as text.

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

        If Not IsPostBack Then

 

            Dim wr As WebRequest = WebRequest.Create("http://www.live.com")

 

            Try

 

                Dim mr As WebResponse = wr.GetResponse

                Dim sr As New StreamReader(mr.GetResponseStream)

                Dim sHTML As String = sr.ReadToEnd

                sr.Close()

                mr.Close()

 

                If String.IsNullOrEmpty(sHTML) = False Then

 

                    ltlContent.Text = sHTML

 

                End If

 

            Catch ex As Exception

   

                'Process the Exception Here

 

            End Try

 

        End If

 

    End Sub

So now pass the text of the URL to a string using the ReadToEnd method of the StreamReader class. Because I have to put some minimal error checking in my code I check to see if I have any content to publish, and if so then I pass the string to the Text property of the Literal control on the Content page. Now the content of the URL is now displayed in our content page.

Of course you will want something a bit more sophisticated to display your content. For example you will most likely want to remove the header section from the remote URL. If it contains any references to stylesheets and JavaScript files you will want to inject them in to the Header of your actual page too. Once this is done you will most likely see the content of the remote page pretty close to how it is displayed on their site. So one of my next entries will be on injecting content and controls into the page header at run-time. But as far as publishing content inside of a ContentPlaceHolder control of a Master page, it is pretty easy, but I have to question why so many want to do this. It does not help you with Search Engine Optimization and is generally plagiarism or at least violation of copyrights too.


Share this post :
Posted: Thursday, October 18, 2007 10:47 AM

by Chris Love

Comments

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# October 18, 2007 11:08 AM

yousaid said:

Great piece, but here is my problem and hope you can help me solve it.

I have a Masterpage, so let's call it MasterPage1.

Masterpage1 has ContentPlaceHolders cphLeft, cphRight, cphCenter.

I have a contentPage, so let's call it Default.aspx.

Cphleft and cphRight, both  default to MasterPage1

I have a  UserControl located in folder,let's call the folder, MyControlFolder.

Now I have a UserControl let's call it voteBox. So I put VoteBox usercontrol in cphRight. When a user clicks the vote button, it works fine BUT the problem is it refreshes the  entire page. So what I want to do is use Ajax and ONLY refresh cphRight  when the user votes. So my problem is, HOW do I reference voteBox from the ContentPage? I have tried FindControl, but it is not working. I am using VB and will much appriciate a functional code or steps on how to do this. Gues what I have one of those posts you mentioned  see this http://forums.asp.net/t/1176047.aspx post.

Thanks,

yousaid

# October 31, 2007 9:30 AM

Jerome Vernon said:

This is cool. Can’t wait to see how you handle java script and styles (perhaps images too). My question is somewhat related to your post; Do you know of a way to add a browser window within the client browser? This would be something like the windows IE control but placed on a web form.

BTW: here is your code for this article but in C#:

   WebRequest  wr;

   wr = WebRequest.Create("http://www.live.com");

   try

   {

       WebResponse mr = wr.GetResponse();

       StreamReader sr;    

       sr = new StreamReader(mr.GetResponseStream());

       String  sHTML= sr.ReadToEnd();

       sr.Close();

       mr.Close();

       if (String.IsNullOrEmpty(sHTML) == false)

       {

           ltlContent.Text = sHTML;

       }

   }

   catch

   {

       //do nothing

   }

# October 31, 2007 12:44 PM

webbes said:

You might wanna checkout the WebClient class. It has a DownloadString method.

Second... an empty catch? Ouch that's a really, really, really bad practice.

Cheers,

Wes

# October 31, 2007 1:39 PM

Chris Love said:

Sorry Wes, it was just a simple example. I know about the WebClient class. I just like the Request and Response classes better because you get more control over the process. I also actually go the socket level at times :>.

# October 31, 2007 1:58 PM

webbes said:

I like the idea cause indeed that question does pop-up every now and then. It's just that whenever I see an empty catch, alarm bells start ringing.

Still... a nice article. Which might be something I should have mentioned in my first post...

# October 31, 2007 3:34 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

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