Getting a full ASP.Net rendered page as a string

comments

So there i was looking for a simple solution to offer a preview function on a CMS for a client at work, when it hit me. Why try and replicate the content of the page in anyway (i could use a blank page and fill it in, i could carry values as a session and redirect to the front end view page. The reality is: I could do many different things. The real question comes down to “How would a Ninja do it”

The CMS i was working on uses dynamic master pages and virtual URL’s (nothing really special here) but it does offer a few issues that i was so blissfully unaware of (i didn’t even stop to really think about it much.

“Let's ‘Av a Go Gov!”

So my first thought, while on the right track, was a bit naive. I thought i could simply make my CMS “View” (we are still using webforms here but hey, don’t hate on me too much) have a bunch of public properties, set the properties and then use the HttpContext to execute the page and we’d be there. I’d used this technique to make easily templat’able Ajax return values for quick and dirty Ajax return strings in the past.

My first attempt looked like:

 

Page tempPage = new Views.Blog.BlogDetail();
tempPage.PageIntro = intro;
tempPage.PageContent = content;

StringWriter sw = new StringWriter();
HttpContext.Current.Server.Execute(tempPage, sw, false);
if (!String.IsNullOrEmpty(sw.ToString()))
{
    return sw.ToString();
}

 

Sadly this didn’t work. My content view sets its MasterPage dynamically and the method that was doing this fantasmagorical action was having the null-reference-exception of doom because it couldn’t find the Page.Master object… Why????

While my frustration brewed away it dawned on me:

The Asp.Net Engine adds a hell of a lot of pretty cool stuff for us at runtime, that we often forget – we need to make sure this cool stuff still happens.

How silly of me to forget.

So i needed to run the page through its full life cycle to get the whole page. This is where our buddy the BuildManager steps out of the corner and tags himself in. His mystery precedes him and his secret toolbox of helper methods, and i needed some serious inspector gadget goodness. Assuming the fact that he does this all the time (build pages), he know a lot more about what needs to be done in this situation.

So here is the new updated version, that works a charm and yet its simplicity is nice.

 

public string GetCMSPageAsString(string intro, string content)
{
    // use the Build Manager to create a new instance
    // of the page and set up its properties
    Views.Blog.BlogDetail objContentPage = 
        BuildManager.CreateInstanceFromVirtualPath("~/Views/ContentPage.aspx", 
        typeof(Page)) as Views.Blog.BlogDetail;
    
    if (objContentPage != null)
    {
        //set the pages properties
        objContentPage.PageIntro = intro;
        objContentPage.PageContent = content;

        StringWriter sw = new StringWriter();
        //set the relative path of the page so it knows where it "is"
        objContentPage.AppRelativeVirtualPath = "~/Views/ContentPage.aspx";
        
        //execute the page
        HttpContext.Current.Server.Execute(objContentPage, sw, false);
        if (!String.IsNullOrEmpty(sw.ToString()))
        {
            //return the page as a string
            return sw.ToString();
        }
    }
    return
          "There was an Error generating your preview";
}

 

We still make the page have all its properties made public, we create a new version of the page, set all its properties and then monsieur BuildManager does his stuff. Great Stuff.

I will be using this quite a bit moving forward. I hope someone can find some use for it too.