PayPal with ASP.NET MVC

PayPal is a cheap and easy solution for taking payments and is quick to implement in ASP.NET MVC. We will look at a simple scenario of taking a user to a PayPal payment page to checkout. There is not much information on the PayPal website about using MVC, so hopefully this should get you started. This post deals with the express checkout, but the same principle applies to the normal checkout process.

Creating a PayPal Account

You will need a sandbox account to test your transactions. The sandbox account is separate from a regular account and is all you need to sign up to before you develop and test your code.

PayPal Account Settings

It's good practice to put things like account settings in the web.config. The code in this article will access these settings. You must change the sandbox setting to False when using regular account details:
<appSettings>	 
   <add key="PayPal:Sandbox" value="True" />
   <add key="PayPal:Username" value="*" />
   <add key="PayPal:Password" value="*" />
   <add key="PayPal:Signature" value="*" />
   <add key="PayPal:ReturnUrl" value="http://www.superstarcoders.com" />
   <add key="PayPal:CancelUrl" value="http://www.superstarcoders.com" />
</appSettings>

PayPal Checkout Button

We won’t discuss the ins and outs of implementing the shopping cart functionality for adding/removing products, and will get straight onto the “buy” button. You will need to place a checkout or buy button on your page (you must use the ones PayPal provide).

Here’s how this should look in ASP.NET MVC using the Razor engine (which I’m a big fan of):

@using (Html.BeginForm("Pay", "Cart"))
{
   <input type='image' name='submit'
      src='https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif' />
}

The checkout button posts back to your controller and then you do a server side call to PayPal. This is the only API call you need to make to get the simplest of transactions going and in fact you don’t need to make this call if you're not using the express checkout, however, the nice part about doing this server side interaction is you get some feedback from PayPal which you can log (logging the interaction with a payment provider in this way for trouble shooting purposes is heavily advised) before taking the user to the PayPal website. The MVC redirect mechanism makes this quite easy in your controller. Once this redirect happens the user can pay and the transaction is complete.

public class CartController : Controller
{
   public ActionResult Index()
   {
      return View();
   }

   public ActionResult Pay()
   {
      PayPalRedirect redirect = PayPal.ExpressCheckout(new PayPalOrder { Amount = 50 });

      Session["token"] = redirect.Token;

      return new RedirectResult(redirect.Url);
   }
}

Here is the PayPal API code that you can include in your solution or a separate library:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections.Specialized;
using System.Net;
using System.IO;
using System.Globalization;

public class PayPal
{
   public static PayPalRedirect ExpressCheckout(PayPalOrder order)
   {
      NameValueCollection values = new NameValueCollection();

      values["METHOD"] = "SetExpressCheckout";
      values["RETURNURL"] = PayPalSettings.ReturnUrl;
      values["CANCELURL"] = PayPalSettings.CancelUrl;
      values["AMT"] = "";
      values["PAYMENTACTION"] = "Sale";
      values["CURRENCYCODE"] = "GBP";
      values["BUTTONSOURCE"] = "PP-ECWizard";
      values["USER"] = PayPalSettings.Username;
      values["PWD"] = PayPalSettings.Password;
      values["SIGNATURE"] = PayPalSettings.Signature;
      values["SUBJECT"] = "";
      values["VERSION"] = "2.3";
      values["AMT"] = order.Amount.ToString(CultureInfo.InvariantCulture);

      values = Submit(values);

      string ack = values["ACK"].ToLower();

      if (ack == "success" || ack == "successwithwarning")
      {
         return new PayPalRedirect
         {
            Token = values["TOKEN"],
            Url = String.Format("https://{0}/cgi-bin/webscr?cmd=_express-checkout&token={1}",
               PayPalSettings.CgiDomain, values["TOKEN"])
         };
      }
      else
      {
         throw new Exception(values["L_LONGMESSAGE0"]);
      }
   }

   private static NameValueCollection Submit(NameValueCollection values)
   {
      string data = String.Join("&", values.Cast<string>()
        .Select(key => String.Format("{0}={1}", key, HttpUtility.UrlEncode(values[key]))));

      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
         String.Format("https://{0}/nvp",PayPalSettings.ApiDomain));
      
      request.Method = "POST";
      request.ContentLength = data.Length;

      using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
      {
         writer.Write(data);
      }

      using (StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()))
      {
         return HttpUtility.ParseQueryString(reader.ReadToEnd());
      }
   }
}

The PayPal order class (which has some details left for you to fill in):

public class PayPalOrder
{
	public decimal Amount { get; set; }
}

The PayPal redirect result class:

public class PayPalRedirect
{
	public string Url { get; set; }
	public string Token { get; set; }
}

Here’s the wrapper around the ASP.NET application settings used by the PayPal API code:

using System;
using System.Configuration;
using System.ComponentModel;
using System.Globalization;

public static class PayPalSettings
{
   public static string ApiDomain
   {
      get
      {
         return Setting<bool>("PayPal:Sandbox") ? "api-3t.sandbox.paypal.com" 
            : "api-3t.paypal.com";
      }
   }

   public static string CgiDomain
   {
      get
      {
         return Setting<bool>("PayPal:Sandbox") ? "www.sandbox.paypal.com" : "www.paypal.com";
      }
   }

   public static string Signature
   {
      get
      {
         return Setting<string>("PayPal:Signature");
      }
   }

   public static string Username
   {
      get
      {
         return Setting<string>("PayPal:Username");
      }
   }

   public static string Password
   {
      get
      {
         return Setting<string>("PayPal:Password");
      }
   }
 
   public static string ReturnUrl
   {
      get
      {
         return Setting<string>("PayPal:ReturnUrl");
      }
   }
 
   public static string CancelUrl
   {
      get
      {
         return Setting<string>("PayPal:CancelUrl");
      }
   }

   private static T Setting<T>(string name)
   {
      string value = ConfigurationManager.AppSettings[name];

      if (value == null)
      {
         throw new Exception(String.Format("Could not find setting '{0}',", name));
      }

      return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
   }
}

Further Investigation

There are facilities for PayPal to notify your website that the transaction was successful (you get emailed so this isn’t entirely necessary) and there are numerous other features, but hopefully this should get you started on the path to using PayPal with ASP.NET MVC.

Attachments:

Paypal.zip

Published Tuesday 29 November 2011, 10:06 PM by Keith
Filed under: ASP.NET MVC PayPal

7 Comments

# re: PayPal with ASP.NET MVC

Wednesday 29 February 2012, 04:27 AM by Brian Noronha

Wonderful article...A systematic explanation of integrating ASP.NET MVC with PayPal gateway. One question though, Does PayPal provide concise documentation for implementing additional features with ASP.NET MVC?  

# re: PayPal with ASP.NET MVC

Wednesday 29 February 2012, 07:36 AM by Keith

Thanks Brian, unfortunately I didn't find much on MVC specifically, I read through the documentation and had to figure out the MVC parts. There is some example Web Forms code which helped a lot. The documentation for express checkout starts here and is quite detailed, but I guess they can't cover all technologies:
https://cms.paypal.com/uk/cgi-bin/?cmd=_render-content&content_ID=developer/library_documentation#ec

# re: PayPal with ASP.NET MVC

Thursday 01 March 2012, 10:12 AM by gor

Why did you use NVP API instead of SOAP ?

# re: PayPal with ASP.NET MVC

Thursday 01 March 2012, 06:42 PM by Keith

It was a personal preference rather than a deep technical reason :-)

# re: PayPal with ASP.NET MVC

Wednesday 11 April 2012, 07:36 PM by nick

I found if you set values["DESC"] = "details of the transaction"; then you get more info on the paypal login screen rather than a blank description :)

# re: PayPal with ASP.NET MVC

Thursday 12 April 2012, 07:22 PM by Keith

Hi Nick, you will certainly need to flesh the code out a bit, this article illustrates what's involved in a Hello World solution!

# re: PayPal with ASP.NET MVC

Saturday 12 January 2013, 11:55 AM by Alistair Findlay

This is a really useful piece of code! Just one thing - if you modify the line to:

values["AMT"] = order.Amount.ToString("0.00", CultureInfo.InvariantCulture);

This will format any decimal values to 2 decimal places, otherwise the default 4 decimal place value is sent to PayPal and will return an "Order total is not valid." error.

Great work though!

Leave a Comment

(required)
   

(required)
   


   

(required)
   

(required)
 

Valid XHTML 1.0 Strict