CodersBarn.com
The ASP.NET Community Blog

Integrate PayPal Checkout Button with ASP.NET 2.0

March 27, 2008 19:23 by agrace

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

kick it on DotNetKicks.com   PHP, ASP, .NET, JSP Resources, Reviews   vote it on Web Development Community

GhostForm.zip (448.00 bytes)


Comments

April 5. 2008 06:08

Some.NET(Guy)

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.

Some.NET(Guy)

April 5. 2008 06:42

agrace

Hi Jason,

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

Anthony Wink

agrace

April 5. 2008 06:43

Some.NET(Guy)

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

Some.NET(Guy)

April 8. 2008 06:55

pingback

Pingback from tried34567.info

paypal

tried34567.info

April 9. 2008 03:15

pingback

Pingback from alvinashcraft.com

Dew Drop - April 1, 2008 | Alvin Ashcraft's Morning Dew

alvinashcraft.com

April 24. 2008 23:08

pingback

Pingback from countnazgul.com

countnazgul.com  » Blog Archive   » Diigo bookmarks 04/17/2008 (a.m.)

countnazgul.com

August 25. 2008 08:49

steve

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.

steve

August 28. 2008 23:48

agrace

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

agrace

September 27. 2008 06:06

Dathan

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

Dathan

September 27. 2008 21:44

agrace

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

agrace

October 6. 2008 23:31

Alfonso

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

Alfonso

October 6. 2008 23:34

agrace

Alfonso,

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

Thanks!
Anthony Smile

agrace

October 19. 2008 04:40

David

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

David

October 19. 2008 04:49

agrace

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

agrace

November 13. 2008 04:10

Peter

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

Peter

November 13. 2008 05:36

agrace


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

November 13. 2008 05:43

agrace

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

agrace

November 13. 2008 11:55

Peter

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

Peter

November 13. 2008 14:24

agrace

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

agrace

November 22. 2008 01:17

webmaven

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.

webmaven

December 6. 2008 14:42

trackback

Trackback from Web Development Community

Integrate PayPal Checkout Button with ASP.NET 2.0

Web Development Community

December 30. 2008 08:05

Speed Dating

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.

Speed Dating

February 9. 2009 06:22

vivek

Please give detailed code

vivek

February 9. 2009 10:46

agrace

@vivek,

Which part is giving you problems?

Anthony Smile

agrace

February 25. 2009 09:44

Winnie Abraham

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

Winnie Abraham

February 25. 2009 10:52

agrace

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

agrace

February 26. 2009 01:26

Winnie Abraham

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?

Winnie Abraham

February 26. 2009 09:32

agrace

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

agrace

February 27. 2009 00:18

Winnie Abraham


hi,

thanks a lot anthony.your code helped .

Winnie Abraham

February 27. 2009 03:42

Winnie Abraham

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

Winnie Abraham

February 27. 2009 08:52

agrace

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

agrace

March 2. 2009 23:56

Winnie Abraham

hi,

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

Winnie Abraham

March 3. 2009 00:36

agrace

Winnie,

Have you used the PayPal sandbox?

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

Anthony Smile

agrace

March 5. 2009 02:32

Winnie Abraham

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

March 6. 2009 01:33

Winnie Abraham

can u plz help me on that?

Winnie Abraham

March 6. 2009 06:08

agrace

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

agrace

March 10. 2009 02:41

Winnie Abraham

thanx for ur help.sometimes a slice of salmon helps

Winnie Abraham

March 10. 2009 04:53

agrace

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

Don't forget the fennel Wink

agrace

June 3. 2009 16:46

Asoka Sampath

Great Example. Thanks a lot

Asoka Sampath

June 4. 2009 17:20

pingback

Pingback from msahoo.wordpress.com

Paypal Integration with ASP.Net « Manoranjan's Tech World

msahoo.wordpress.com

July 19. 2009 10:45

friendster graphics comments

can u plz help me on that?

friendster graphics comments

July 19. 2009 19:52

agrace

@friendster, what are u having a problem with?

agrace

May 23. 2010 11:45

pingback

Pingback from 425.an74.com

Gmc L300 1 Used, Car Saturn L300 3 - 425.an74.com

425.an74.com

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading