I recently posted a solution to the eternal PayPal / ASP.NET form submission problem using Jeremy Schneider's custom GhostForm class. Since then, several people have made mention of a problem that I came across myself when coding this, namely getting your project to recognize the reference to the new custom form class.

PayPal Checkout Button

 

Using a Web Application Project in VS 2005, I recently came up against something similar when attempting to place the SqlHelper.cs class in the App_Code folder. At that time I offered a quick hack. Since then, I have thought better of using the App_Code folder in my Web Application Projects and just create a normal folder and put the helper class in there along with my data access class. The App-Code is more trouble than it is worth for a small project where there is practically zero compilation time to be saved anyway.

Back to the problem at hand... when attempting to compile, you may get the following error:

"The name 'mainForm' does not exist in the current context"

First, check your scopes; make sure that wherever you are using the mainForm object is in the same scope as the instantiation. Ideally, create a separate Class Library Project in your solution and add the custom form class to it. Compile your new project separately and reference that from your e-commerce project. Right-click the References folder in Solution Explorer and browse to the DLL for the custom form.

CustomForm Class Library Project

 

Add the following to your master page and ignore any red squigglies you get in Visual Studio:

<%@ Register TagPrefix="CF" Namespace="CustomForm" Assembly="CustomForm" %>
<body>
    <CF:GhostForm id="mainForm" runat="server">
    ...
</body>

 

Add markup to the ASPX for the dummy PayPal button and a functioning ASP.NET button:

<img src="https://www.sandbox.paypal.com/en_US/i/btn/btn_xpressCheckout.gif"> <asp:Button ID="checkoutBtn" runat="server" OnClick="CheckButton_Click"
    Text="Checkout" Width="100" CausesValidation="false" /> 

 

using CustomForm;

namespace MyProject
{
    public partial class purchase : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            ...
            // Workaround for PayPal form problem
            GhostForm mainForm = new GhostForm();
            mainForm.RenderFormTag = false;
        }
        ...
    }
    ...
}

 

Although specific to my own project requirements, here's the complete handler code for the button click: 

        protected void CheckButton_Click(object sender, EventArgs e)
        {
            // Live PayPal URL
            // const string SERVER_URL = "https://www.paypal.com/cgi-bin/webscr";
            // Sandbox PayPal URL
            const string SERVER_URL = "https://www.sandbox.paypal.com/cgi-bin/webscr";
           
            // Live business parameter
            // const string BUSINESS = "grace@graceguitars.com";
            // Sandbox business parameter
            const string BUSINESS = "tester@hotmail.com";

            // Return URL for IPN processing
            const string NOTIFY_URL = "http://www.mysite.com/PayPalReturnURL.aspx";

            decimal totalAmount = 0.00M;
            int productID = 0;
            int totalUnits = 0;
            decimal totalShipping = 0.00M;
            string paypalURL = "";
            string itemName = "Grace\'s Guitars";
            string itemNumber = "";

            if (cart.Count > 0)
            {
                BizClass biz = new BizClass();
              
                // TransactionID will be later used to check against IPN info
                string transID = Guid.NewGuid().ToString();
               
                // Create a new Order in DB
                orderID = biz.AddOrder(out orderID, transID, false, DateTime.Now);
                itemNumber = Convert.ToString(orderID);

                foreach (ShoppingCartItem item in cart)
                {
                    totalAmount += item.Total;
                    totalUnits += item.Units;
                    productID += item.ProductID;

                    // Store order details in database
                    biz.AddOrderDetails(orderID, productID, item.Units);
                }   
                // Eventually, use a SQL Server job to remove unconfirmed orders

                // Calculate total shipping cost for total number of units
                totalShipping = CalculateShipping(totalUnits);

                // Get back the URL-encoded URL for PayPal   
                paypalURL = GetPayPalURL(SERVER_URL, BUSINESS, itemName, itemNumber,
                    totalAmount, totalShipping, NOTIFY_URL);
                Response.Redirect(paypalURL, true);
            }
        }

 

You need to sign into your PayPal Developer account before submitting your test purchases. You will be able to see a history of your test transactions in the sandbox admin section.

PayPal Sandbox

 

If you want some sample code for constructing the URL, I suggest you check out the following whitepaper from Rick Strahl. This should be enough to see you up and running. Many times, people get compiler errors due to badly-formed namespace declarations and class references. Always double-check your code :-)

 

GhostForm.zip (448.00 bytes)



Comments (46) -

Some.NET(Guy)
Some.NET(Guy) United States
4/5/2008 6:08:34 AM #

Anthony -

I still think this solution is waaay too complex. Check out the solution I have posted on my site (dotnetdiscussion.net/.../). Ghost forms is taking this problem to a complexity level it doesn't need to be at.

agrace
agrace United States
4/5/2008 6:42:10 AM #

Hi Jason,

I think this is a case of what's your favorite color!

Anthony Wink

Some.NET(Guy)
Some.NET(Guy) United States
4/5/2008 6:43:53 AM #

Haha... I suppose that's possible. Shouldn't everyone like my favorite color though? :-D

steve
steve United Kingdom
8/25/2008 8:49:33 AM #

Pretty much similar to my situation, trying to implement a simple 'buy now' ASP.NET 2 site turned into a fairly complex eCom solution. Anyway, thought I'd share a little hack that I stumbled upon quite by accident and fairly early on (thankfully). After finding that the form action didn't send the user to paypal, I inadvertantly placed a <form></form> just before the paypal form information. It worked! Try it. I'm not sure if this is causing any other issues (none I've come across yet anyway), but it works! Try it and let me know.

agrace
agrace United States
8/28/2008 11:48:55 PM #

Steve,

I heard of this but never tried it out. Were the form tags nested or place separately from each other, in the context of the .aspx page?

Anthony Smile

Dathan
Dathan Canada
9/27/2008 6:06:47 AM #

There's a much simpler solution.  Drop the <form> tags supplied by PayPal and instead just use an <asp:Button> tag for the BuyNow or AddToCart or whatever with the PostBackUrl attribute set to the PayPal url.

One-liner ;)

D

agrace
agrace United States
9/27/2008 9:44:48 PM #

Dathan,

Sounds like a winner; I opted for Jeremy's solution because it gave <i>me</i> more flexible and better structured code from a reuse point of view. Your solution Dathan is remarkably simple like all great solutions. Thanks for sharing!!

Note, when passing this info we need to check in our code that none of the params have been tampered with. We are not talking encrypted transactions here Smile

Alfonso
Alfonso Mexico
10/6/2008 11:31:12 PM #

I tested Dathan's solution, and so far it works fine in local environment. I still need to customize further, but that is the first solution that is working for me.   Thanks

agrace
agrace United States
10/6/2008 11:34:47 PM #

Alfonso,

Will you keep us posted on this when you go live?

Thanks!
Anthony Smile

David
David United States
10/19/2008 4:40:00 AM #

Ok wait - I found this solution using javascript that is SOOOOOOO brilliantly simple compared to any of this MasterPage and Ghostform lunacy that I can't believe this isn't the top search returned on Google for this issue:
http://www.nerdymusings.com/LPMArticle.asp?ID=29

Basically you just need to remove the form tags from the Paypal HTML and then replace the image button with an A link around an image. In the A link you have javascript that resets "theForm" which is ASP.NET's main form to point to Paypal instead of back to your page.

<a href="javascript:theForm.__VIEWSTATE.value='';
theForm.encoding='application/x-www-form-urlencoded';
theForm.action='https://www.paypal.com/cgi-bin/webscr';theForm.submit();">
<img src="images/buynow.gif" border="0"></a>

David

agrace
agrace United States
10/19/2008 4:49:26 AM #

David,

The reason we didn't do this initially is because of the browser's need to have JavaScript enabled for this to work. There are all types of JavaScript hacks out there but the challenge was to find an <i>elegant</i> way around the form problem using ASP.NET... Also, check out Nathan's solution above.

Anthony Smile

Peter
Peter Sweden
11/13/2008 4:10:32 AM #

Excellent blog post.

Two questions though:
1) Where do you get GetPayPalURL from? Can't find it anywhere.
2) How do you control if the transaction is a success (the buyer pays) or a error (the buyer aborts the transaction). If the transaction is successful I want to update my database with some values, that's why I need to control this.

I am using this code: http://www.aspsidan.se/code/default.asp?c=23777

I have, like many others, worked with this _too_ many hours... Smile

agrace
agrace United States
11/13/2008 5:36:33 AM #


Here you go Peter Smile

protected string GetPayPalURL(
string SERVER_URL,
string business,
string[] itemNames,
int[] quantities,
decimal[] amounts,
double[] itemWeight,
int orderID,
string NOTIFY_URL)
{
// Customer will be required to specify
// delivery address to PayPal
   const string NO_SHIPPING = "2";

   StringBuilder url = new StringBuilder();
   url.Append(SERVER_URL + "?cmd=_cart&upload=1");
   url.Append("&business=" + HttpUtility.UrlEncode(business));

   for (int i = 0; i < itemNames.Length; i++)
   {
      url.Append("&item_name" + "_" + (i + 1).ToString() +
         "=" + HttpUtility.UrlEncode(itemNames[i]));
      url.Append("&quantity" + "_" + (i + 1).ToString() +
         "=" + quantities[i].ToString().Replace(",", "."));
      url.Append("&amount" + "_" + (i + 1).ToString() +
         "=" + amounts[i].ToString().Replace(",", "."));
      url.Append("&weight" + "_" + (i + 1).ToString() +
         "=" + itemWeight[i].ToString().Replace(",", "."));
     }

      url.Append("&no_shipping="
         + HttpUtility.UrlEncode(NO_SHIPPING));
      url.Append("&item_number="
         + HttpUtility.UrlEncode(orderID.ToString()));
      url.Append("&notify_url="
         + HttpUtility.UrlEncode(NOTIFY_URL));

      return url.ToString();
}

agrace
agrace United States
11/13/2008 5:43:43 AM #

Peter,

Sorry, I forgot to answer the second part of your question. You need to use IPN for this. Although he's using ASP.NET MVC, Rob Conery gives a really good video presentation on how to do this for PayPal here:

http://www.asp.net/learn/mvc-videos/video-432.aspx

Anthony Smile

Peter
Peter Sweden
11/13/2008 11:55:46 AM #

Thank you for the quick answers, Anthony Smile

I have wondering about the following this morning (works!):
www.paypal.com/.../webscr

That is the url that my code with <form>-tags generates by this code:
http://www.aspsidan.se/code/default.asp?c=23777

But when I use your code this url generates (don't work!):
www.paypal.com/.../...notify_url=www.mywebpage.com

What am I missing? Like you see in the code-paster I have two input-fields by the names "hosted_button_id" and "cmd", and one select-tag by the name "os0", do I have to send those values to the PayPalURL too? In that case, how?

I never thought there whould be this much problem with setting upp the Buy Now-button Smile

agrace
agrace United States
11/13/2008 2:24:12 PM #

Peter,

Read through the PayPal documentation. It's wordy but required reading:

www.paypalobjects.com/.../..._IntegrationGuide.pdf

You are not passing the required parameters to the GetPayPalURL. At the end of the day, you are not passing the parameters to PayPal that it expects. Also, for IPN to work, you need to use either a non-local server or try to use an IP.

Hopefully, in the near future, I will post a full working example. Try getting it to work in the PayPal sandbox first, without the IPN. Break the problem down. When I was doing this for the first time, I would copy the code generated by PayPal buttons on other sites to get a feel for how it was put together.

Anthony Smile

webmaven
webmaven United States
11/22/2008 1:17:45 AM #

you're not going to believe this, but i just converted the paypal form into an href with querystring and it seems to work just fine.

Speed Dating
Speed Dating United States
12/30/2008 8:05:44 AM #

This is just great. I use Paypal, and asp.net technology on my site. This is a problem my programmer and I have been looking for info on. I am certain he will be able to diagnose and fix the problem more clearly after reading this post. Thank you for sharing.

vivek
vivek United States
2/9/2009 6:22:03 AM #

Please give detailed code

agrace
agrace United States
2/9/2009 10:46:12 AM #

@vivek,

Which part is giving you problems?

Anthony Smile

Winnie Abraham
Winnie Abraham India
2/25/2009 9:44:16 AM #

i would like to know how to make process more than one items to paypal?

agrace
agrace United States
2/25/2009 10:52:42 AM #

Winnie,

The code sample above is doing just that. The total amount and total shipping are calculated "before" being sent as parameters to PayPal.

Anthony Smile

Winnie Abraham
Winnie Abraham India
2/26/2009 1:26:05 AM #

u have declared itemname as string in button click n pass it to the getpaypal url as parameter,but u declared itemname as string[] itemnames? how is that possible?

agrace
agrace United States
2/26/2009 9:32:12 AM #

Well spotted Winnie. What happened is that I used a code snippet from a different application I write to answer Peter's question. As soon as I get a chance I'm going to post a downloadable cart application, Here is code that should work for you:

.....
string[] itemNames = new string[cart.Count];
                decimal[] amounts = new decimal[cart.Count];
                int[] quantities = new int[cart.Count];
                double[] itemWeight = new double[cart.Count];

                int i = 0;
                foreach (ShoppingCartItem item in cart)
                {
                    // Store order details in database
                    totalUnits += item.Units;
                    productID += item.ProductID;
                    // biz.AddOrderDetails(orderID, productID, item.Units);

                    // Gather transaction details to be added to PayPal URL parameters
                    itemNames[i] = item.ProductName;
                    amounts[i] = item.ProductPrice;
                    quantities[i] = item.Units;
                    itemWeight[i] = item.ProductWeight;
                    i++;
                }
                // Eventually, use a SQL Server job to remove unconfirmed orders

                paypalURL = GetPayPalURL(SERVER_URL, BUSINESS, itemNames,
                    quantities, amounts, itemWeight, orderID, NOTIFY_URL);
                
                cart.Clear();
                Session.Clear();
                Response.Redirect(paypalURL, true);

....

protected string GetPayPalURL(string SERVER_URL, string business, string[] itemNames,
            int[] quantities, decimal[] amounts, double[] itemWeight, int orderID, string NOTIFY_URL)
        {
            // Customer will be required to specify delivery address to PayPal
            const string NO_SHIPPING = "2";

            StringBuilder url = new StringBuilder();
            url.Append(SERVER_URL + "?cmd=_cart&upload=1");
            url.Append("&business=" + HttpUtility.UrlEncode(business));

            for (int i = 0; i < itemNames.Length; i++)
            {
                url.Append("&item_name" + "_" + (i + 1).ToString() + "=" + HttpUtility.UrlEncode(itemNames[i]));
                url.Append("&quantity" + "_" + (i + 1).ToString() + "=" + quantities[i].ToString().Replace(",", "."));
                url.Append("&amount" + "_" + (i + 1).ToString() + "=" + amounts[i].ToString().Replace(",", "."));
                url.Append("&weight" + "_" + (i + 1).ToString() + "=" + itemWeight[i].ToString().Replace(",", "."));
            }

            url.Append("&no_shipping=" + HttpUtility.UrlEncode(NO_SHIPPING));
            url.Append("&item_number=" + HttpUtility.UrlEncode(orderID.ToString()));
            url.Append("&notify_url=" + HttpUtility.UrlEncode(NOTIFY_URL));

            return url.ToString();
        }

Winnie Abraham
Winnie Abraham India
2/27/2009 12:18:29 AM #


hi,

thanks a lot anthony.your code helped .

Winnie Abraham
Winnie Abraham India
2/27/2009 3:42:34 AM #

another problem -- after payments in paypal how to get returned back to my site with the detailed reciept.

agrace
agrace United States
2/27/2009 8:52:04 AM #

I use an Orders table in my database with a "confirmed" field. You can place the transaction details there just before sending the customer over to PayPal. When the IPN returns successfully, you can update the "confirmed" filed and use the details of the Orders table as the basis of your receipt. Remember, that you can still access all your sales data in PayPal admin Smile

Winnie Abraham
Winnie Abraham India
3/2/2009 11:56:24 PM #

hi,

the problem is the  IPN is not returning successfully, what i have to do  to make it success.

agrace
agrace United States
3/3/2009 12:36:06 AM #

Winnie,

Have you used the PayPal sandbox?

I've emailed you seperately for a copy of your code.

Anthony Smile

Winnie Abraham
Winnie Abraham India
3/5/2009 2:32:52 AM #

i have a table with field image that stores just a name of the image,in my page i am  using a grid view to dispaly this image.and its displaying. but if there is no image in table field
it comes showing a box with cross.so how to avoid that

i am getting the image everything using select query in to a datatable n i use this datatable as datasource to bind my grid view

Winnie Abraham
Winnie Abraham India
3/6/2009 1:33:30 AM #

can u plz help me on that?

agrace
agrace United States
3/6/2009 6:08:33 AM #

Winnie,

I suggest you Google it and brush up on your ASP.NET. It's better if you learn to fish rather than someone handing you a slice of salmon...

Anthony Smile

Winnie Abraham
Winnie Abraham India
3/10/2009 2:41:07 AM #

thanx for ur help.sometimes a slice of salmon helps

agrace
agrace United States
3/10/2009 4:53:19 AM #

www.codeproject.com/KB/database/images2db.aspx

Don't forget the fennel Wink

Asoka Sampath
Asoka Sampath
6/3/2009 4:46:34 PM #

Great Example. Thanks a lot

friendster graphics comments
friendster graphics comments United States
7/19/2009 10:45:43 AM #

can u plz help me on that?

agrace
agrace United States
7/19/2009 7:52:08 PM #

@friendster, what are u having a problem with?

Eyewebmaster
Eyewebmaster Philippines
12/16/2011 4:16:19 PM #

I've iframe my aspx paypal button to PHP. Now when I've tried to tick my paypal button it didn't give me success. Now I'm looking for some code on how can I execute that button to open it up to another window or tab.. And probably I'll be making a documentation for this to help others also.


Hope you can help. Thank you.

@Eyewebmaster,

With PHP you are not facing the one-form-tag restriction that crops up with ASP.NET Web Forms. Just try the sample code from the PayPal site and you should be good.


Rosendo Cuyasen from Eyewebmaster

Armaghan
Armaghan United States
3/31/2012 5:14:54 PM #

I'm confused, why do you even need the GhostForm() or turn form rendering on or off when you're doing a "Response.Redirect"?
It should work either way?

bluehost coupon
bluehost coupon Afghanistan
4/12/2012 12:45:34 AM #

Hi, all - I'm a newbie who just spent all day today trying to add a single PayPal button to my site (built in VWD2005X Ed).  I am not using a starter kit and literally just wanted to add an encrypted Buy Now Button to my page.  Here's what I tried, and here's what WORKED.

admin
admin United States
6/27/2012 8:24:17 AM #

Aditi,

Short answer is you can't, plus iframes are deprecated in HTML5, etc... My advice is never use iframes for anything.

Anthony Smile

Aditi Patre
Aditi Patre India
6/27/2012 10:15:28 AM #

Hi Anthony,

What would you suggest then, my client requires that the flow should be seamless without user being redirected to paypal site. I tried searching about Direct API but I think tat would be quite tough as I have to ensure PCI compatibility.

Please suggest me some solution & some tips guidelines.

If u check the below link, chapter4 page33 first line says that "PayPal offers a compact payment form that can be integrated in an iFrame on your website." where is this template/ compact payment form available on paypal website

cms.paypal.com/.../HostedSolution.pdf

Thanx
Aditi

admin
admin United States
6/27/2012 1:42:07 PM #

Aditi,

I've never used the Pro Solution before so can't honestly say.. have you looked through the PayPal dev forums and asked the question there?

Rgds,
Anthony Smile

Ana - Regalarme
Ana - Regalarme Spain
2/14/2013 4:32:09 AM #

Nice tip

That solved my problem

Thanks

Ramesh
Ramesh India
3/29/2013 12:14:02 PM #

I want to send discount to paypal...
How can I send?????
Pleaaaaaase help me....

Speeddating NYC
Speeddating NYC United States
4/5/2013 8:46:06 AM #

Great! Just the answers I was looking for.

Pingbacks and trackbacks (8)+