locked
Use httphandler to dynamically output system.web.ui.page via Master Page RRS feed

  • Question

  • User-1699666177 posted

    Hi - I'm working on a front-controller style application in ASP.NET
    2.0. I have mapped all HTTP requests to ASPNET_ISAPI, and use an
    HttpModule to do a database lookup on the search-engine-friendly URLs
    that my app uses, in order to select the correct output for the
    context.

    Mapping the HTTP request to a physical ASPX page seems fairly
    straightforward with HttpContext.RewritePath. However, I don't really
    want any physical ASPX pages in my app. All my content lives in the
    database, so I'd like to create a System.Web.UI.Page object in my 
    HttpHandler class, set it to use a MasterPage for templating the output, and
    add WebControls and Content to it dynamically as mandated by the content logic.

    Anyway, I created a class that extends System.Web.UI.Page and set this
    as my HttpHandler in web.config. Lo and behold, I can get it it to
    handle requests and return data via Response.Write(). HOWEVER - I can't get it to work with MasterPages when I try to set the MasterPageFile property. The "MasterPage.CreateMaster()" fails in its call to "VirtualPathProvider.CombineVirtualPathsInternal()" because apparently
    basePath is null.

    Does anybody know if it's possible to do this, or do I need a rethink?

    Thursday, December 8, 2005 6:08 AM

Answers

  • User-1699666177 posted

    Hiya, yes I did fix this eventually. In my HttpHandler class (extension of System.Web.UI.Page), I do:  

    protected override void OnPreInit(EventArgs e)
    {
    	/* ..... Lots of other stuff ..... */
    
    	base.AppRelativeVirtualpath = Request.ApplicationPath;
    
    	/* ..... Lots of other stuff ..... */
    }
    FYI I also do the following to make the page controls behave properly:
    protected override void OnInit(EventArgs e)
    {
    	/* ..... Lots of other stuff ..... */
    // Set Path to the requested RawURL to fool Page Controls about their base path location Context.RewritePath(Request.RawUrl);
    	/* ..... Lots of other stuff ..... *

    }
    One last thing - I had to intercept the rendering of the page and rewrite the Form's "action" attribute to make it post back to itself properly, because I was doing my own URL rewriting.
     
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, April 2, 2007 5:23 AM

All replies

  • User130843581 posted

    Hi Zootius,


    Did you manage to solve this problem?
    Im currently dealing with the exact same challenge, but can't get around a physical .aspx page.

    Maybe you picked an alternative solution?

    With regards
    Kim Andersen

    Wednesday, June 21, 2006 8:19 AM
  • User-1311559603 posted
    Anyone find a solution to this?  I've got the same problem too ....
    Wednesday, February 7, 2007 2:11 PM
  • User-1699666177 posted

    Hiya, yes I did fix this eventually. In my HttpHandler class (extension of System.Web.UI.Page), I do:  

    protected override void OnPreInit(EventArgs e)
    {
    	/* ..... Lots of other stuff ..... */
    
    	base.AppRelativeVirtualpath = Request.ApplicationPath;
    
    	/* ..... Lots of other stuff ..... */
    }
    FYI I also do the following to make the page controls behave properly:
    protected override void OnInit(EventArgs e)
    {
    	/* ..... Lots of other stuff ..... */
    // Set Path to the requested RawURL to fool Page Controls about their base path location Context.RewritePath(Request.RawUrl);
    	/* ..... Lots of other stuff ..... *

    }
    One last thing - I had to intercept the rendering of the page and rewrite the Form's "action" attribute to make it post back to itself properly, because I was doing my own URL rewriting.
     
    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, April 2, 2007 5:23 AM
  • User-1311559603 posted

    zootius:

    Thanks for the reply!  It was very helpful.  However, I managed to encounter another issue ...

    When I try to add Content controls, I get the following exception when I set the ContentPlaceHolderID property:

    Setting the ContentPlaceHolderID property of System.Web.UI.WebControls.Content is not supported.

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.NotSupportedException: Setting the ContentPlaceHolderID property of System.Web.UI.WebControls.Content is not supported.

    Source Error:

    Line 22: 
    Line 23: phHead = new Content();
    Line 24: phHead.ContentPlaceHolderID = "phHead";
    Line 25:
    Line 26: phContent = new Content();

    Where you able to get around this?

     Thanks!
     

    Monday, April 2, 2007 9:24 AM
  • User-1699666177 posted

    No worries, sorry the reply was so late :)

    I don't have a solution to using Content objects programatically - but I'm not sure you need them. In your HttpHandler's OnInit() method (assuming you set the MasterPageFile in OnPreInit()), you can find your ContentPlaceHolder controls programatically and add your dynamically generated controls directly to them; after all, a ContentPlaceHolder is just a fancy NamingContainer.

    I enclose a utility method I wrote to recursively find a control with a given ID (i.e. your ContentPlaceHolder ID), starting from a given point in the control tree (i.e Master.Page):

     
     

    /// <summary>
    /// Given a root Control, does a recursive search for a Control with the given ID.
    /// </summary>
    /// <param name="ctlRoot"></param>
    /// <param name="strID"></param>
    /// <returns></returns>
    public static Control FindControlRecursive(Control ctlRoot, string strID)
    {
    	if (ctlRoot.ID == strID)
    	{
    		return ctlRoot;
    	}
    	foreach (Control ctlTemp1 in ctlRoot.Controls)
    	{
    		Control ctlTemp2 = FindControlRecursive(ctlTemp1, strID);
    		if (ctlTemp2 != null)
    		{
    			return ctlTemp2;
    		}
    	}
    	return null;
    }
     
    Apologies if such a recursive find method already exists in the .NET framework - I couldn't work out a way to make FindControl() do it. Let me know if I've been missing a trick!
    Monday, April 2, 2007 10:43 AM
  • User-1311559603 posted

    I arrived at a similar solution shortly after my reply.  After realizing that the ContentPlaceHolder is nothing but a naming container, I figured I could just use FindControl() to get a reference of the place holder I wanted to add controls to.  I also realized that I didn't need a Content object, but a ContentPlaceHolder.  So I'm doing this in the overridden OnInit method of my HttpHandler(Page):

     

    phHead = (ContentPlaceHolder)Master.FindControl("phHead"); 
    phHead.Controls.Add(myControl);
     

    Thanks again!
    Monday, April 2, 2007 11:07 AM