65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP.NET 中实现非 ASP.NET Post 请求

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (4投票s)

2009年5月1日

CPOL

4分钟阅读

viewsIcon

35367

如何在 ASP.NET 页面中包含多个 form 标签。

在与 Web 上的一些资源交互时,有时会收到一小段 HTML 代码。 例如,要在您的网站上插入一个 PayPal 按钮,PayPal 会提供 HTML 代码,如下所示。

<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>

插入 PayPal 按钮的 HTML 代码

此代码片段定义了一个 <form> 标签和几个 <input> 标签,包括一个提交按钮。 单击提交按钮时,表单中的项目将被发布到 <form> 标签的 action 属性中指定的 URL。 然后,目标 URL 可以检查这些 <input> 标签的值并执行所需的操作。

但是,您可能会发现此类代码片段在插入到 ASP.NET 页面时无法正常工作。 主要问题是 ASP.NET 页面已经定义了一个表单。 为了使 ASP.NET 的回发机制正常工作,所有控件都放置在一个 <form> 标签内。 由于 HTML 不允许嵌套 <form> 标签,因此将如上所示的代码插入到 ASP.NET 页面中会导致问题。

有很多可能的方法来解决这个问题。 让我先从几个我认为不太理想的方法开始。 第一种方法是简单地将插入的 HTML 代码移动到 ASP.NET 表单的结束 </form> 标签之后。 虽然您不能嵌套 <form> 标签,但在同一页面上包含多个非嵌套 <form> 标签是可以的。

这样做的结果是,页面现在有两个单独的 <form> 标签,您会发现这通常可以按预期工作。 但是,这里的问题是您会失去一些 ASP.NET 功能。 例如,插入的 HTML 代码位于您的 ASP.NET 表单之后,因此它实际上并未嵌入到您的 ASP.NET 内容中。 而且,如果您使用的是母版页,则无法在内容页中执行此操作,因为内容页中的所有内容都放置在母版页中定义的 <form> 标签内。

第二种方法有点丑陋的 hack,如下所示

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();
}

执行非 ASP.NET 回发的丑陋 hack

此代码响应用户单击名为 btnPayPal 的按钮而运行。 它动态创建一个 HTML 页面,然后将其提供给用户的浏览器。 创建的页面复制了我们第一个列表中的表单,但在页面的 <body> 标签中添加了一个 onload 属性,该属性使表单在加载后立即提交,并且用户永远不会看到此临时页面。

这绝对是一个丑陋的 hack。 而且,虽然它可以工作,但它存在一些问题。 主要问题是,如果在运行代码后,用户按下浏览器中的“后退”按钮,浏览器将重新加载此临时页面,这将导致再次发生相同的操作,这绝对有可能导致一些讨厌的问题。

在探索了这两种选择之后,我最终选择了第三种方法,这种方法似乎更简单,并且似乎没有任何重大问题。 从 ASP.NET 2.0 开始,按钮具有一个名为 PostBackUrl 的属性,该属性可用于使该按钮回发到包含该按钮的页面以外的页面。

乍一看,这似乎没有帮助。 ASP.NET 按钮旨在回发到 ASP.NET 页面。 而且,我想回发到非 ASP.NET 页面。 但是,在两种情况下,回发机制是相同的。 如果我们回发到非 ASP.NET 页面,我们将发送大量附加数据——我们 ASP.NET 表单上的所有表单项目——到目标页面。 但是,只要没有冲突的项目名称(这不太可能),这实际上不是问题。

有了这些知识,我们就可以重写我们的原始代码块并将其插入到 ASP.NET 页面中。

<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" />

插入到 ASP.NET 页面中的 PayPal 按钮

我从这段代码中删除了 <form> 标签。 我们不需要它,因为我们的 ASP.NET 表单已经定义了一个 <form> 标签。 我删除了 <img> 和提交 <input> 标签,并将它们替换为 ImageButton。 我将 ImageButtonImageUrl 属性设置为与原始代码中使用的相同 PayPal 按钮图像,最后,我将 PostBackUrl 属性设置为原始 HTML 代码中 <form> 标签的 action 属性中指定的 URL。

结果是,当单击 ImageButton 时,整个表单将发布到 PayPal URL。 正如我之前提到的,这包括我们所有的其他 ASP.NET 值,包括页面的 ViewState 数据。 但是,ViewState 数据已加密,并且 PayPal 站点只会查看它感兴趣的值。

结果是,我能够在 ASP.NET 表单中的任何位置插入 PayPal 按钮,我仍然能够使用所有 ASP.NET 功能,PayPal 获得了完成其工作所需的所有值,并且如果用户碰巧从 PayPal 站点点击浏览器的“后退”按钮,也不会出现任何奇怪的问题。

© . All rights reserved.