Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.Net single control render for AJAX calls

I'm trying to implement something similar to this or this.

I've created a user control, a web service and a web method to return the rendered html of the control, executing the ajax calls via jQuery.

All works fine, but if I put something in the user control that uses a relative path (in my case an HyperLink with NavigateUrl="~/mypage.aspx") the resolution of relative path fails in my developing server.

I'm expecting: http://localhost:999/MyApp/mypage.aspx

But I get: http://localhost:999/mypage.aspx

Missing 'MyApp'...

I think the problem is on the creation of the Page used to load the control:

Page page = new Page();
Control control = page.LoadControl(userControlVirtualPath);
page.Controls.Add(control);
...

But I can't figure out why....

EDIT Just for clarity

My user control is located at ~/ascx/mycontrol.ascx and contains a really simple structure: by now just an hyperlink with NavigateUrl like "~/mypage.aspx". And "mypage.aspx" really resides on the root.

Then I've made up a web service to return to ajax the partial rendered control:

[ScriptService]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class wsAsynch : System.Web.Services.WebService
{
    [WebMethod(EnableSession = true)]
    public string GetControl(int parma1, int param2)
    {
        /* ...do some stuff with params... */
        Page pageHolder = new Page();

        UserControl viewControl = (UserControl)pageHolder.LoadControl("~/ascx/mycontrol.ascx");
        Type viewControlType = viewControl.GetType();

        /* ...set control properties with reflection... */

        pageHolder.Controls.Add(viewControl);
        StringWriter output = new StringWriter();
        HttpContext.Current.Server.Execute(pageHolder, output, false);

        return output.ToString();
    }
}

The html is correctly rendered, but the relative path in the NavigateUrl of hyperlink is incorrectly resolved, because when I execute the project from developing server of VS2008, the root of my application is

http://localhost:999/MyApp/

and it's fine, but the NavigateUrl is resolved as

http://localhost:999/mypage.aspx

losing /MyApp/ . Of Course if I put my ascx in a real page, instead of the pageHolder instance used in the ws, all works fine.

Another strange thing is that if I set the hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx") I get the correct url of the page: http://localhost:999/MyApp/mypage.aspx

And by now I'll do that, but I would understand WHY it doesn't work in the normal way. Any idea?

like image 521
tanathos Avatar asked Jun 30 '10 16:06

tanathos


1 Answers

The problem is that the Page-class is not intented for instantiating just like that. If we fire up Reflector we'll quickly see that the Asp.Net internals sets an important property after instantiating a Page class an returning it as a IHttpHandler. You would have to set AppRelativeTemplateSourceDirectory. This is a property that exists on the Control class and internally it sets the TemplateControlVirtualDirectory property which is used by for instance HyperLink to resolve the correct url for "~" in a link.

Its important that you set this value before calling the LoadControl method, since the value of AppRelativeTemplateSourceDirectory is passed on to the controls created by your "master" control.

How to obtain the correct value to set on your property? Use the static AppDomainAppVirtualPath on the HttpRuntime class. Soo, to sum it up... this should work;

[WebMethod(EnableSession = true)]
public string GetControl(int parma1, int param2)
{
    /* ...do some stuff with params... */
    var pageHolder = new Page() { AppRelativeTemplateSourceDirectory = HttpRuntime.AppDomainAppVirtualPath };

    var viewControl = (UserControl)pageHolder.LoadControl("~/ascx/mycontrol.ascx");
    var viewControlType = viewControl.GetType();

    /* ...set control properties with reflection... */

    pageHolder.Controls.Add(viewControl);
    var output = new StringWriter();
    HttpContext.Current.Server.Execute(pageHolder, output, false);

    return output.ToString();
}
like image 163
Pauli Østerø Avatar answered Sep 30 '22 14:09

Pauli Østerø