views:

48

answers:

2

This question got me thinking about how one might go about doing the relatively undoable: seamlessly integrate server-generated HTML from ASP.NET with client-side control via javascript. Sure, you can always use javascript/jquery/libraries to create the same display client-side. But much of the time, it's easier to do all the rendering on the server instead of just passing data to a client-side control which must handle the user interface and rendering. Or maybe you've already got a lot of less-interactive server code that you'd really rather not completely re-do using javascript libraries to just add some better interactivity.

I had a theory which seems to work in a basic proof of concept. Suppose you want to completely re-render the HTML of a server-generated control based on a client-side event, without posting back. So using jquery, I have a page:

    default.aspx:
   <a id="link1" href="#">Click Here</a>
   <div id="container">
   <asp:PlaceHolder id="MyPlaceholder" runat="server" />
   </div>
    <script type="text/javascript">
        $(document).ready(function() {
            $('#link1').click(function() {
                $.ajax({
                    url: "default.aspx",
                    type: "GET",
                    dataType: "html",
                    async: true,
                    data: { "ajax": "1" },
                    success: function(obj) {
                    // replace the HTML
                        $('#container').html(obj);
                    }
                });
            });
        });

The event causes it to query itself with ajax. The codebehind that does the trickery is like this:

    TestUserControl ctl;
    string ajax;
    protected void Page_Load(object sender, EventArgs e)
    {
        ctl = (TestUserControl)Page.LoadControl("TestUserControl.ascx");
        Myplaceholder.Controls.Add(ctl);
        ctl.OnRender += new TestuserControl.RenderHandler(ctl_Render);
    }
    protected void Page_PreRender()
    {
        ajax = Request.QueryString["ajax"] == null ? "" : Request.QueryString["ajax"];
    }
    void ctl_Render()
    {
        if (ajax == "1")
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);

            using (HtmlTextWriter writer = new HtmlTextWriter(sw))
            {
                ctl.DoRender(writer);
            }

            Response.Write(sb.ToString());
            Response.End();
        }
    }

In TestUserControl, i expose base.render to get the output:

   public void DoRender(HtmlTextWriter writer)
    {
        base.Render(writer);
    }

Basically, if the page is called without the "ajax" querystring, it just acts like itself. But when that querystring is used, it intercepts the output stream from the content I am concerned with (a usercontrol called TestUserControl.ascx) and renders just that. This is returned to the client, which updates the HTML. All the IDs will be recreated exactly as before since I am not trying to render just that control in isolation, but in context of its own page. Theoretically, every bit of magic created by ASP.NET should be reproduced, retrieved and updated by the ajax query.

Apart from the obvious lack of efficiency, it seems to work swimmingly in this little test. I can completely rerender the control using the server generated HTML without a postback and I've written zero javascript. This example doesn't actually change anything, but it would be simple to pass more parameters to change the output.

I was wondering if anyone had tried anything like this in practice? What potential problems might I not be thinking of?

If server performance is not an issue, it seems like it might be quite easy way to get a heck of a lot of functionality with all the benefits of ASP.NET server controls. But I can't seem to find any discussion of using this technique in practice so I am wondering what I might be missing.

+2  A: 

Well, for starters, you're sending a GET request to your page, so the control you want to update won't receive up-to-date form data. More importantly, ViewState will be lost and you probably don't want that, unless your user control is very simple.

You could work around the problem by using a POST request, but there are other potential issues, e.g. can you guarantee that the client scripts embedded in your user control either run again or don't when you update it, consistently, on all browsers?

Fortunately, others have already solved those problems. I'd suggest you place your user control inside an UpdatePanel and force a refresh from the client side:

__doPostBack("yourUpdatePanelClientID", "");
Frédéric Hamidi
You know, this came from the desire to avoid UpdatePanels because of the many ways I have gotten into trouble when mixing them with javascript and other updatepanels. In the end I think I am simply trying to recreate one through the back door... ah well.
jamietre