0

I'm having an issue with the cycle of a page reload and I can't figure it out. I have an ASP button the runs at the server but it has an associated client side click. The client side Javascript is running correctly and returning true to the button click so it is also running. The Javascript makes a modification to the query string on the URL and this is also working. However, in the C# code behind, the query string is not there. Somewhere, I'm missing something.

The HTML link:

<asp:Button ID="btnRunMOReport" class="button-dbg" runat="server" 
     Text="Run MO Report" OnClick="btnMO_Report_Click" 
     OnClientClick="return validateCheckBoxesMO()" />

The JavaScript portion:

function validateCheckBoxesMO() {
   token='xyz';
   let url1 = window.location.href;

   if (url1.indexOf("?") > 0) {
     url1 = url1.substring(0, url.indexOf("?"));
   }

   url1 += "?hiddenToken=" + token;
   window.location.replace(url1);

   return true;
}

The hiddenToken is now represented on the page (?hiddenToken=xyz).

The code behind:

protected void btnMO_Report_Click(object sender, EventArgs e)
{
    MailMessage mailtest = new MailMessage();
    mailtest.IsBodyHtml = true;

    SmtpClient SmtpServertest = new SmtpClient(ConfigurationManager.AppSettings["smtp_server"]);

    mailtest.To.Add("Whoever@test123.com");
    mailtest.From = new MailAddress("Whoever@test123.com");
    mailtest.Subject = Request.QueryString["hiddenToken"];
    mailtest.Body = "Whatever";
}

The mail comes just fine but the subject is blank. Somehow, during the page reload cycle, the query string has not yet been set.

If there is a better way to pass data from the JavaScript to the code behind, I'm all ears.

I want to launch another page from the code behind but I need some data that is returned from the JS. The token is actually something I fetch, process the JSON and now I want to make that token available to the code behind for additional information to add to the new URL I am constructing. Probably TMI for this but it is what I am trying to do.

Thanks for your assistance.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Steve Cross
  • 89
  • 1
  • 13

2 Answers2

1
  • Your script isn't working because the browser makes a POST request to submit the form (and __VIEWSTATE) using the action="" attribute of the <form> that WebForms adds to your page.
  • When your client-script sets window.location it isn't changing how the <form> will behave. You could use your script to append the new querystring value to the <form>'s action="" attribute and this may work, however it will likely fail if the application has request-validation enabled (in which case ASP.NET will reject a tampered form submission).

As you're using WebForms (and you shouldn't be using WebForms in 2021...) you shouldn't try to fight it unless you understand how it all works (I'm not trying to be condescending: it took me years to figure it all out and I've been using WebForms since 2004).

Instead, provide the value through an <asp:HiddenField>:

Change your .aspx markup to this:

<asp:Button runat="server" ID="btnRunMOReport" class="button-dbg" 
     Text="Run MO Report" OnClick="btnMO_Report_Click" 
     OnClientClick="return validateCheckBoxesMO()" />

<asp:HiddenField runat="server" ID="superSecretHiddenField"  />

Change your client script to this:

function validateCheckBoxesMO() {
    const hiddenFieldId = '<%= this.superSecretHiddenField.ClientID %>';
    const hiddenField   = document.getElementById( hiddenFieldId );

    token='xyz';
   
    hiddenField.value = token;

    return true; // <-- This is wrong, btw. Instead use `Event.prototype.stopPropagation()` - but that requires the on-click function to be wired-up correctly and I don't remember the specifics other than that WebForms *doesn't* do things correctly (not out-of-spite, but because WebForms predates the standardisation of client-script events).
}

And your code-behind to this:

protected void btnMO_Report_Click(object sender, EventArgs e)
{
    MailMessage mailtest = new MailMessage();
    mailtest.IsBodyHtml = true;

    SmtpClient SmtpServertest = new SmtpClient(ConfigurationManager.AppSettings["smtp_server"]);

    mailtest.To.Add("Whoever@test123.com");
    mailtest.From = new MailAddress("Whoever@test123.com");
    mailtest.Subject = this.superSecretHiddenField.Value;
    mailtest.Body = "Whatever";
}
Dai
  • 141,631
  • 28
  • 261
  • 374
  • Thank you for your efforts. I had tried something similar to this without success. I tried using your code exactly and got the same results of the subject still being empty .It's as though the hidden field contents are being reset somewhere in the handoff. – Steve Cross Apr 20 '21 at 16:32
  • 1
    @SteveCross Please edit your question to post the **full** page code. Also try reproducing the issue with an empty page. I suspect that ASP.NET is preferring the values contained in `__VIEWSTATE` over client-side modifications which can happen based on how your page is set-up. – Dai Apr 20 '21 at 17:23
0

As noted, a button post back will in general over-write the url that you change. Unless you actually do a navigation client side that is caused by the js, then it will not persist.

So, on the most simple level, just drop in a text box, or hidden field, and put the value you need/want into that hidden textbox or field.

So, client side? Markup?

You can use this:

        <asp:Button ID="Button1" runat="server" Text="Delete"
            OnClientClick="SetHidden();"/>

        <asp:HiddenField ID="HiddenField1" runat="server" ClientIDMode="Static"/>

        <br />
        <script>
            function SetHidden() {
                hField = document.getElementById('HiddenField1');
                hField.value = 'zoo';
                return true;
            }
        </script>

So in above, we set our value in js to zoo, and of course we do return true. If we return false then the asp.net button code server side will not run - so we can control this, or even say pop up a confirm dialog and return true/false based on that to control if the server side code behind will run.

Server side, code behind? You can now use this:

Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Debug.Print(HiddenField1.Value)

End Sub

So the above is easy, clean. You can also use a text box, and set the style="display:none", but a hidden field is just as well and easy.

Albert D. Kallal
  • 42,205
  • 3
  • 34
  • 51