Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Implementing Non-ASP.NET Posts in ASP.NET

0.00/5 (No votes)
1 May 2009 1  
How to include multiple form tags in an ASP.NET page.

When interfacing with some resources on the Web, you are sometimes provided with a little snippet of HTML code. For example, to insert a PayPal button on your Website, PayPal provides HTML code that may look something like this.

<form action="https://www.paypal.com/cgi-bin/webscr" method="post">

  <input type="hidden" name="cmd" value="_xclick">
  <input type="hidden" name="business" value="bob@domain.com">


  <input type="hidden" name="lc" value="US">
  <input type="hidden" name="item_name" value="Widget">


  <input type="hidden" name="amount" value="100.00">
  <input type="hidden" name="currency_code" value="USD">


  <input type="hidden" name="bn"
    value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest">


  <input type="image"
    src="https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif"
    border="0" name="submit" alt="">

  <img alt="" border="0"
    src="https://www.paypal.com/en_US/i/scr/pixel.gif" 
    width="1" height="1">

</form>

HTML code to insert PayPal button

This snippet defines a <form> and several <input> tags, including a submit button. When the submit button is clicked, the items in the form are posted to the URL specified in the action attribute of the <form> tag. The target URL can then inspect the values of those <input> tags and perform the required operation.

However, you may find that such snippets don’t work correctly when inserted into an ASP.NET page. The main problem is that ASP.NET pages already define a form. In order for ASP.NET’s post-back mechanism to work, all the controls are placed within a <form> tag. Since HTML doesn’t allow nested <form> tags, inserting code like that shown above into an ASP.NET page causes problems.

There are a number of possible approaches to resolving this. Let me start with a couple that I think are less than ideal. The first approach is to simply move the inserted HTML code after the ending </form> tag of the ASP.NET form. Although you cannot nest <form> tags, it is okay to include multiple, non-nested <form> tags on the same page.

The result of this is that the page now has two separate <form> tags, and you’ll find this generally works as expected. However, the problem here is that you lose some ASP.NET functionality. For example, the inserted HTML code comes after your ASP.NET form, and so it is not really embedded within your ASP.NET content. And, if you are using master pages, you cannot do this in content pages because everything in a content page is placed inside of the <form> tag defined in the master page.

The second approach is kind of an ugly hack, and is shown below:

protected void btnPayPal_Click(object sender, ImageClickEventArgs e)
{
    System.Web.HttpContext.Current.Response.Clear();

    System.Web.HttpContext.Current.Response.Write("<html><head>");
    System.Web.HttpContext.Current.Response.Write("</head><body " + 
       "onload='document.form1.submit()'>");
    System.Web.HttpContext.Current.Response.Write("<form " + 
       "action='https://www.paypal.com/cgi-bin/webscr' " +
       "name='form1' method='post'>");

    System.Web.HttpContext.Current.Response.Write("<input " + 
       "type='hidden' name='cmd' value='_xclick'>");

   System.Web.HttpContext.Current.Response.Write(
       "<input type='hidden' name='business' " +
       "value='bob@domain.com'>");

   System.Web.HttpContext.Current.Response.Write(
       "<input type='hidden' name='lc' value='US'>");
   System.Web.HttpContext.Current.Response.Write(
       "<input type='hidden' name='item_name' value='Widget'>");
   System.Web.HttpContext.Current.Response.Write(
       "<input type='hidden' name='amount' value='100.00'>");
   System.Web.HttpContext.Current.Response.Write(
       "<input type='hidden' name='currency_code' value='USD'>
   System.Web.HttpContext.Current.Response.Write(
       "<input type='hidden' name='bn' " +
       "value='PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest'>

   System.Web.HttpContext.Current.Response.Write(
       "<input type='image' " +
       "src='https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif' " +
       "border='0' name='submit' alt=''>");

   System.Web.HttpContext.Current.Response.Write("<img alt='' border='0' " +
       "src='https://www.paypal.com/en_US/i/scr/pixel.gif' " +
       "width='1' height='1'>");

   System.Web.HttpContext.Current.Response.Write("</form>");
   System.Web.HttpContext.Current.Response.Write("</body></html>");

   System.Web.HttpContext.Current.Response.End();
}

Ugly hack to perform non-ASP.NET postback

This code runs in response to the user clicking a button named btnPayPal. It dynamically creates an HTML page and then serves it to the user’s browser. The page created duplicates the form in our first listing, but adds an onload attribute to the page’s <body> tag that causes the form to be submitted as soon as it loads, and the user never sees this temporary page.

This is definitely an ugly hack. And, while it works, it has some problems. The main problem is if, after running the code, the user presses the Back button in their browser, the browser will reload this temporary page, which will cause the same action to happen again, which definitely has the potential to cause some nasty problems.

After exploring both of these options, I finally settled on a third approach that seems more straightforward and doesn’t seem to have any major problems. Beginning with ASP.NET 2.0, buttons have a property called PostBackUrl, which can be used to have that button post back to a page other than the page that contains the button.

At first glance, this didn’t seem helpful. ASP.NET buttons are designed to post back to ASP.NET pages. And, I wanted to post back to a non-ASP.NET page. However, the post-back mechanism is the same in both cases. If we post back to a non-ASP.NET page, we’re going to send a lot of additional data—all of the form items on our ASP.NET form—to the target page. But, as long as their is no conflicting item names, which is unlikely, this really isn’t a problem.

Armed with this knowledge then, we can rewrite our original code block and insert it into an ASP.NET page.

<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="bob@domain.com">
<input type="hidden" name="lc" value="US">

<input type="hidden" name="item_name" value="Widget">
<input type="hidden" name="amount" value="100.00">

<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="bn"
       value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest">
<asp:ImageButton ID="ImageButton1" runat="server"
   ImageUrl="https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif"
   PostBackUrl="https://www.paypal.com/cgi-bin/webscr" />

PayPal button inserted into ASP.NET page

I’ve removed the <form> tag from this code. We don’t need it since our ASP.NET form already defines a <form> tag. I’ve removed the <img> and submit <input> tags, and I’ve replaced them with an ImageButton. I set the ImageButton’s ImageUrl property to the same PayPal button image used in the original code and, finally, I set the PostBackUrl property to the URL specified in the action attribute of the <form> tag in our original HTML code.

The result is that, when the ImageButton is clicked, the entire form is posted to the PayPal URL. As I mentioned before, this includes all our other ASP.NET values, including the page’s ViewState data. But, the ViewState data is encrypted, and the PayPal site will only look at those values it is interested in.

The result is that I am able to insert a PayPal button at any location within my ASP.NET form, I’m still able to make use of all ASP.NET features, PayPal gets all the values it needs to do its job, and there is no funny business if the user happens to hit the browser’s Back button from the PayPal site.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here