1

I have a website that is running under ASP.Net. It has a number of ascx controls that each represent a different page. The master page would call LoadControl() on the ascx and then add it to a panel. The ascx Page_Load() would then hook up a personal save function to an event on the page so that the "Save" button on the master page would do the right thing. This is all working.

I am now trying to be more dynamic and use jQuery more and do things more on the client side. To that end, I am experimenting with loading the ascx controls dynamically. The goal is to be able to do this with minimal changes to each ascx. I have a page, with the following contents (edited for brevity):

<head>
<script language="javascript" type="text/javascript">
function documentMetadataLoad()
{
    jQuery.ajax({
      type: "GET",  //GET
      url: "JQueryHandler.ashx?Operation=LoadPage&Name=/UserControls/DocumentManagment/DocumentMetadata.ascx",
      dataType: "html",
      cache: false,
      success: function (response)
      {
        $('#property_tab').html(response);
      },
      error: function ()
      {
        debugger;
        $('#property_tab').html('error');
      }
    });
</script>
</head>
<body id="mainBody" class="bodyClass">
<form id="form1" runat="server">
<div id="btn_save">
    <a href="#" id="btnSave" class="topBtnText">Save</a>
</div>
<div>
    <div id="tab1" onclick="documentMetadataLoad(); ">Properties</div>
</div>
<div id="property_tab" style="display: Block;"></div>
</form>
</body>

This page will dynamically load a control called DocumentMetadata.ascx when the user clicks on a tab. (Yes, I am aware that there is probably a gaping security hole when the client passes the path of the control, but this is a proof-of-concept.)

The JQueryHandler will take the given path and generate a page. Its ProcessRequest() looks like this:

public void ProcessRequest(HttpContext context)
{
    if (context.Request.QueryString["Operation"] == "LoadPage")
    {
        String strPath = context.Request.QueryString["Name"];
        using (TisPage MyPage = new TisPage())
        {
            HtmlForm f = new HtmlForm();
            f.Action = context.Request.UrlReferrer.AbsolutePath;
            UserControl userctrl = MyPage.LoadControl(strPath) as UserControl;
            f.Controls.Add(userctrl);
            MyPage.Controls.Add(f);
            context.Server.Execute(MyPage, context.Response.Output, true);
        }
    }
}

(Thank you to http://www.infoconcepts.com/rendering-ascx-files-ajax/ for indicating a HtmlForm should wrap the control.) TisPage is a subclass of System.Web.UI.Page, with an added event for saving data, which the ascx expects.

Now, the problem I am having is that I want the DocumentMetadata.ascx to have its save function called when the user presses the #btnSave. This is code behind, and it expects to have its viewstate retained. So I assume I will have to have a postback. I would prefer not to have to rewrite the C# save function to be its own ashx call with passed in parameters; there are a lot of pages like this and it would not be worth the trouble to rewrite them all.

I have the following code in the DocumentMetadata.ascx to setup the button press to do something.

$(document).ready(function ()
{
    $("#btnSave").bind("click", Save);

});

function Save()
{
    debugger;
    __doPostBack('ctl00', null);
}

I experimented by having a call to __doPostBack() in the Javascript, but I then get the error: "Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster." As an experiment, I tried to remove my machine key configuration from my web.config, but that did not seem to help.

Is there a way to use JavaScript to call the code behind of an ascx control that was loaded with jQuery?

2
  • 1
    You can't use the postback methods of a control that was loaded via ajax. I suggest transfering all those postback methods to classes and using a web service/method to communicate with them. It will take some time, but you'll have a much cleaner/faster/versatile app in the long run. Commented May 14, 2013 at 18:33
  • I agree that everything would be better if the code was transferred to a web service, but the sheer number of pages makes that prohibitive. The workaround would be to continue using the old interface for those pages, but use the jQuery Ajax method for new pages. Do you have a reference that states that postbacks can't be used in ajax loaded controls? I would like to be able to show my boss an official statement. Commented May 14, 2013 at 22:23

2 Answers 2

1

Loading a .ascx control through ajax is the same as loading a string. It is a one-way pipeline, and there is no post-back communication available with that control. The UpdatePanel solution will not work either (and they are terrible too).

My suggestion is to create client-side templates, using something like Mustache.js, then load JSON data through ajax to populate those templates, and ajax with a webservice to communicate with your server/database. By separating your code, it will be easier to maintain, you'll be able to reuse more code, better efficiency etc.

Post-backs are old school tech, and UpdatePanels are just a nasty implementation of ajax. Take some time and do it right, for both your app and yourself, and you'll both be better because of it.

Sign up to request clarification or add additional context in comments.

1 Comment

That is unfortunate to hear, but now I can stop wasting my time. The ascx page that I have that is almost entirely done in jQuery works fine as it does use a web service for all its data. Going forward we will use that method, but the old pages may never be converted. Thanks for the information.
0

What you are doing here can be more easily accomplished if you use an UpdatePanel. It works client side with partial postbacks and it preserves the ASP Page Lifecycle. You could wrap your #property_tab and your #btnSave with UpdatePanels and manage the postback events server side.

2 Comments

I added UpdatePanels around both #property_tab and #btnSave and I am still getting the "Validation of viewstate MAC failed." error. As an experiment, to test @BradM comment, I added a button on to the DocumentMetadata.ascx to see what happened when it was pressed and caused a postback. I receive the same error doing that.
@ErikAllen With updatepanels you would need to replace the javascript you wrote with server side code. The problem here is that when you load the control via Ajax, its server side events aren't available. UpdatePanels solve that because they respect the page lifecycle. You handle events like in a normal postback, but the updatepanel uses ajax.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.