Musicista Trombettista
Insegnante Editore

Integrare PayPal in un'applicazione asp.NET
In questa pagina si parla di: asp.NET 4 - vb.NET 4
 
Indice

Di cosa si parla - Abstract

In questo articolo viene spiegato un approccio all'integrazione delle funazionalità di PayPal per i pagamenti on-line all'interno di una applicazione asp.NET.
Il punto di partenza è l'articolo di Predrag Tomasevic presente sul sito TheCodeProject. Cercherò di spiegare con qualche parola in più concetti che Mr. Tomasevic ha dato per scontato o passati con poche parole, per poi sviluppare diversi argomenti in cui mi sono imbattuto, o che affrontato in modo differente, e aggiungere ciò che Mr. Tomasevic non ha approfondito.


Introduzione

Come sappiamo PayPal è tra i metodi di pagamento più sicuri e diffusi per quanto riguarda gli acquisti on-line. E' per questo motivo che appena ho avuto la necessità di integrare un metodo di pagamento nei miei siti ho pensato immediatamente a PayPal. Sono quindi subito andato in cerca della sezione Developer nel sito PayPal e... mi sono trovato di fronte una marea di informazioni, tonnellate di documentazione, esempi di ogni tipo, decine di casistiche, ecc. Tanto che l'entusiamo iniziale era calato a tal punto da portarmi a chiedere informazioni alla mia banca per l'acquisto di un Gateway Bancario (...per fortuna gli alti costi mi hanno fermato), pensando di non essere in grado di sviluppare una struttura per gestire in modo efficiente e, soprattutto sicuro, le transazioni.
Per fortuna, come dicevo per inciso, gli alti costi del Gateway Bancario mi hanno spronato a percorrere la strada di PayPal. Devo dire che lo sviluppo e il test completo di tutto il sistema di pagamento ha richiesto più un mese di lavoro, non continuativo tipo una ventina di ore settimanali, quindi un totale di più di un centinaio di ore tra lo studio, "il capire" le cose e il metterle in pratica. A chiunque voglia cimentarsi in questa strada consiglio di armarsi di pazienza e tenacia, di non trascurare alcun aspetto, e di fare tante tante prove (...ne salta sempre fuori una...) in quanto il meccanismo finale deve esser sicuro e funzionare: i motivi sono ovvi. Quando un cliente compra, in quel momento, il sistema di pagamento deve lavorare correttamente e i soldi vanno incassati. Quello che succede dopo deve essere impeccabile altrimenti il cliente è perso.
La scelta di PayPal è, a mio avviso, un'ottima soluzione perché non devo gestire i numeri delle carte di credito e i dati personali del cliente in quanto è tutto elaborato da PayPal [1], togliendomi parecchio lavoro. Considerate che PayPal attua anche il cambio tra valute... il tutto ad un costo decisamente inferiore di qualsiasi banca.
Di fatto la strada, a parte la prima settimana è mezza di salita ripida e qualche piccolo "gran premio della montagna" da dover superare nelle settimane successive, si è sempre più semplificata e la soddisfazione è stata grande.


Punto di partenza

Si dice che "chi ben inizia è già a metà dell'opera"... nulla di più vero in questo caso. Il mio punto di partenza è stato questo:

Introduction to PayPal for C# - ASP.NET developers

un ottimo articolo scritto da Predrag Tomasevic collaboratore del fantastico sito The Code Project: contiene parecchie informazioni che consiglio a tutti di seguire passo passo.
E' assolutamente inutile che io traduca in italiano questo articolo, pari pari. Piuttosto, come detto nell'abstract, cercherò di spiegare con qualche parola in più, e con qualche esempio, concetti complessi che Mr. Tomasevic ha dato per scontato o passati con poche parole, oppure sviluppare argomenti omessi da Mr. Tomasevic o che ho affrontato in modo differente.
Quindi mi ripeto: la lettura e la comprensione dell'articolo di Mr. Tomasevic e necessaria per proseguire nella comprensione di questa pagina. Nei miei esempi darò per scontati gli argomenti trattiti da Mr. Tomasevic.

Cercherò comunque di riassumere i punti trattati nell'articolo e, a seguire, di approfondire i più interessanti:

  • Introduzione ai metodi di integrazione di PayPal: Website Payments Standard (HTML), Postpayment Processing, PayPal API, Payflow Gateway. La nostra attenzione si concentrerà sui primi due aspetti, ovvero il codice html per passare i parametri a PayPal e tutto ciò che avviene dopo l'avvio della procedura di pagamento da parte dell'utente. Come dice lo stesso Tomasevic le API di PayPal permettono maggiore flessibilità, ma, considerata la complessita dell'implementazione, spesso non conviene addentrarsi, a meno che non si abbiamo esigenze particolari che non si possano ottenere con il Website Payments Standard.

  • Creazione e settaggio degli utenti per i test, ovvero per i Test Account: questa operazione è assolutamente necessaria, in quanto registrarsi alla PayPal SandBox da la possibilità di poter effettivamente "giocare nella buca della sabbia", ma invece che costruire i castelli con il secchiello e la paletta, puoi fare tutti gli esperimenti di acquisti e vendita che riterrai necessario tra i due Test Account Seller e Buyer, utilizzando soldi finti e potendo analizzare cosa succede per trovare eventuali bug nella procedura. Solamente quando tutto sarà funzionante al 100% e tutti i test saranno stati fatti, allora potrai far migrare l'applicazione al vero PayPal (dove i soldi sono veri).

  • Creazione del pulsante per il pagamento e come passare i parametri a PayPal, con i metodi Website Payments Standards.

  • Gestione del PostPayment: quando dal mio sito il cliente clicca su "Paga adesso", PayPal prende in mano la gestione della transazione. Quando quest'ultima è terminata (vedremo poi in quali modi può terminare) devo progettare un sistema per gestire quello che avviene. Le casistiche da controllare sono tre: AutoReturn, Direct Payment (PDT), Instant Payment Notification (IPN).
    Spiegherò tra poche righe cosa sono, cosa servono e come funzionano. Prima occorre precisare che PayPal ha regole ferree riguardo la gestione di quello che avviene sul sito che lo utilizza come metodo di pagamento: non si può omettere, per pigrizia o perché non si ritiene necessaria, una di queste fasi pena la chiusura dei servizi. Potete trovare informazioni in questo link e in dettagli in questo link.

  • Utilizzo delle API di PayPal: Tomasevic insiste ancora sul fatto che molti sviluppatori partono da qua, forse perché Google porta come risutlato della ricerca la documentazione della API e l'SDK di PayPal, ma che, pur non essendoci nulla di sbagliato, spesso non è necessario approfondire questo argomento. Comunque sia usare la API significa avere molto di più di un sistema di pagameto: per esempio, tra gli altri, abbiamo la posibilità di scorrere lo storico delle transazioni, gestire pagamenti ricorrenti, riborsi, ecc...


Website Payments Standard (HTML)

Questa sezione riguarda la tecnica di invio dei dati del carrello al sistema di PayPal per procedere al pagamento.
I dati vengono inviati in POST tramite una serie di:

 

<input type="hidden" ... />

 

Questo comporta essenzialmente di sviluppare due punti: come prima cosa occorre settare il parametro ACTION del <form/> verso il sito di PayPal e non in PostBack come standard nelle applicazione asp.NET, e per seconda occorrerà creare tutta una serie di <input type="hidden" ... /> che contengono i valori da passare a PayPal.

Per settare l'ACTION del <form/> utilizzo il codice della pagina:

 

Me.Form.Action = System.Configuration.ConfigurationManager.AppSettings("PayPalConnection")
Me.Form.Method = "Post"

 

Quindi all'ACTION della form assegno la connessione a PayPal con il metodo POST. D'ora in poi qualsiasi click io andrò a fare sara passato in post a PayPal e non più in PostBack all'applicazione.

Per passare i dati a PayPal, ovvero per settare gli <input type="hidden" /> utilizzo due passaggi.
Per primo predispongo una serie di Label per i campi variabili e un paio di <input type="hidden" /> per i parametri fissi:

 

<input type="hidden" name="cmd" value="_cart">
<input type="hidden" name="upload" value="1">
<asp:Label ID="lblBusiness" runat="server" Text="" />
<asp:Label ID="lblShopping" runat="server" Text="" />
<asp:Label ID="lblCurrency" runat="server" Text="" />
<asp:Label ID="lblShipping" runat="server" Text="" />
<asp:Label ID="lblReturn" runat="server" Text="" />
<asp:Label ID="lblCancelReturn" runat="server" Text="" />
<asp:Label ID="lblOrder" runat="server" Text="" />

 

A seguire il codice con cui vado a riempire le varibili:

 

lblBusiness.Text = "<input type='hidden' name='business' value='" + System.Configuration.ConfigurationManager.AppSettings("PayPalSeller") + "' />"

If spedizionePosta Then
   lblShipping.Text += "<input type='hidden' name='item_name_" + (dtAppoggio.Rows.Count + 1).ToString + "' value='Spese di Spedizione'> "
   lblShipping.Text += "<input type='hidden' name='amount_" + (dtAppoggio.Rows.Count + 1).ToString + "' value='" + speseSh + "'> "
Else
   lblShipping.Text = ""
End If

 

Nella prima istruzione definisco il parametro business con i miei dati da venditore PayPal, definiti nel Web.config. Usare quest'ultima posizione per definire i dati è una scelta legata al fatto di poter migrare tra la SandBox e il PayPal reale solo aggiornando il Web.config senza modifiche al codice.

Nel gruppo di istruzioni successivo imposto i parametri per la spedizione, solo nel caso in cui vi siano costi di spedizione.

Per ogni variabile che intendo passare dovrò fare una cosa simile: questi esempi sono semplici, più complesso è passare il carrello intero con tutti gli oggeti, quantità e prezzi, da cui deve risultare un tag <input /> con la stringa finale.

In questo link potete trovare tutte le variabili per HTML PayPal Payments Standard, così da potervi sbizzarrire e creare la soluzione più vicina alle vostre esigenze.


Analisi del Postpayment

La prima domanda che viene a tutti in mente è: dopo che il cliente ha effettuato il pagamento, posso avere una logica di controllo che mi permetta di getire l'ordine e mia volta sul mio sito, piuttosto che inviare una e-mail di conferma?
La risposta è, ovviamente, positiva. PayPal mette a disposizione una serie di logiche PostPayment che, a mio avviso, vanno tutte integrate nell'applicazione web per gestire tutte le casistiche possibili: dall'"utonto" che clicca dieci volte di fila sul link senza attendere l'elaborazione, alla chiusura inaspettata del browser causata dall'utente stesso oppure per un black-out del computer del cliente. Comunque sia, anche per queste casistiche estreme, ci sono sistemi per poter gestire l'ordine in back-end tra PayPal e il nostro sito. Il tutto deve essere fatto in sicurezza: il sistema di PayPal, se dal nostro lato sviluppato come si deve, ha una architettura tale da rendere impossibile l'iniezione di messaggi fraudolenti.
Ma andiamo con ordine.


AutoReturn

L'AutoRetun è la prima logica di base: appena terminato il pagamento l'utente viene automaticamente indirizzato ad una specifica pagina sul nostro sito.
Per settare l'AutoReturn è sufficiente seguire le istruzioni presenti nell'articolo di Tomasevic.
PayPal passa una serie di paramentri nella query string della pagina: è importante verificare questi paramentri per evitare che richiamando la pagina in momenti successivi (mettiamo il caso che l'utente aggiorni la pagina o la richiami successivamente con gli stessi), l'elaborazione avvenga due volte.
Riassumendo, l'unica cosa che fa l'AutoReturn appena effettuato il pagamento è chiamare una pagina del nostro sito (da noi definita) e passare due parametri: 1) come l'utente è tornato al mio sito 2) l'id della transazione.


Payment Data Transfer (PDT)

Il Payment Data Tranfer (PDT) serve per ricevere maggiori informazioni sul pagamento appena effettuato: come già detto, l'AutoReturn mi fornisce essenzialmente due informazioni, ossia come l'utente è tornato al mio sito (se cliccando oppure attendendo il redirect automatico), e l'id della transazione. Con quest'ultimo potrò fare richiesta a PayPal di tutte le informazioni sul pagamento.
Il meccanismo per richiedere le informazioni sulla transazione prevede che io sia in possesso di un token di autorizzazione, diverso per ogni utente iscritto a PayPal, che è possibile ottenere, come spiega Tomasevic, andando sul proprio profilo PayPal e andando a pescare il PDT Identity Token (non mi dilungo perché Tomasevic, nel suo articolo, spiega molto bene come fare).

E' interessante invece analizzare il meccanismo di dialogo con PayPal per ottenere le informazioni che ci servono. Ecco la procedura da seguire:

  • PayPal con il meccanismo dell'AutoReturn, tramite la query styring della pagina, invia al nostro sito la TransactionID, ovvero l'ID della transazione.

  • Da codice, dobbiamo fare una richiesta a PayPal di informazioni riguardanti quella TransactionID appena arrivata corredata dal PDT Identity Token.

  • Se il tutto è corretto PayPal risponde con le informazioni altrimenti risponde errore.


Personalmente ho creato una pagina PayPalReturn.aspx che esegue le operazioni di cui sopra. Tutto questo "botta-e-risposta" serve per evitare che qualcuno non autorizzato ricevi informazioni su un ordine oppure che invii al nostro sistema informazioni contraffatte, facendoci elaborare dati sbagliati. Pensiamo al caso in cui mi arrivi una stringa perfettamente contraffatta, senza tutto questo sistema di autenticazione non saprei se è vera o meno. Altro caso pensiamo se qualcuno chiama il nostro servizio con una quesry string impostata correttamente, ma con una TransactionID fraudolenta. Il nostro sistema la invierà a PayPal, e quest'ultimo risponderà errore. In questo caso nulla di più sarà fatto se non inviare una mail all'amministratore per informarlo dell'anomalia.

A seguire il codice in vb.NET:

 

If Not Page.IsPostBack Then

'Definizione dei parametri necessari
'Questo numero è fornito da PayPal: cliccare su "Profilo" poi nelle "preferenze pagamenti su sito web" dell'account
Dim authToken As String = System.Configuration.ConfigurationManager.AppSettings("PayPalAuthToken")
Dim txToken As String = Request.QueryString.Get("tx")

'Creazione della stringa per la richiesta
Dim query As String = String.Format("cmd=_notify-synch&tx={0}&at={1}", txToken, authToken)

'Definizione, creazione e invio della richiesta
Dim url As String = System.Configuration.ConfigurationManager.AppSettings("PayPalConnection")
Dim req As HttpWebRequest = WebRequest.Create(url)

req.Method = "POST"
req.ContentType = "application/x-www-form-urlencoded"
req.ContentLength = query.Length
 
Dim stOut As New StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII)
stOut.Write(query)
stOut.Close()

'Lettura della risposta
Dim stIn As New StreamReader(req.GetResponse().GetResponseStream())
Dim strResponce = stIn.ReadToEnd
stIn.Close()

Dim stringArray As String()

Dim GrossTotal As String = String.Empty

'Verifiche e utilizzo della risposta
Dim pagamentoOk As Boolean = False

If strResponce.StartsWith("SUCCESS") Then
   pagamentoOk = True

   stringArray = strResponce.Split(New String() {vbCr & vbLf, vbLf}, StringSplitOptions.None)

   Dim appoggio As String()

   'Ricavo i valori che mi servono dalla stringa, in questo caso solamente mc_gross,
   'dal momento che li ho separati tutti nell'array li ho tutti a disposizione
   
   For i As Integer = 1 To stringArray.Count - 1
    appoggio = stringArray(i).Split(New String() {"="}, StringSplitOptions.None)

    Select Case appoggio(0)
    Case Is = "mc_gross"
      GrossTotal = appoggio(1)
    End Select
   Next
Else
   pagamentoOk = False
End If

End If

 

E questo per quanto rigurda il ritorno sul mio sito dopo l'avvenuto pagamento... ma! Mettiamo il caso che l'utente dopo aver pagato chiuda il browser oppure il suo computer si spenga o vada in crash. Se avessimo solamente il PDT per ottenere le informazioni riguardo ad una transazione sicuramente qualcosa, prima o poi, lo perderemmo per strada.
PayPal ha pensato ad una logica che lavora in back-end tra il nostro sito e PayPal, vediamola in dettagli nel capitolo successivo.


Instant Payment Notification (IPN)

Come detto appena sopra il meccanismo PDT lascia aperti dei dubbi riguardo alla certezza di comunicazione tra PayPal e la nostra applicazione perché dipende dal comportamento del cliente e del suo browser.
Per questo, tutte le operazione più importanti come la verifica dello stato del pagamento, la verifica della transazione (l'id della transazione e la e-mail del cliente), la verifica del dati del pagamento, il salvataggio in DB dei dati, l'invio della e-mail al cliente e chi più ne ha più ne metta vengono effettuate in questa procedura che viene richiamata indipendentemente da cosa combina il cliente dopo aver pagato.

Implementare questa procedura non è difficile perché esistono esempi già ben scritti per ogni tipo di linguaggio: vi consiglio di partire da uno di questi esempio in questo link. E' presente la procedura sopra detta per C# e vb.NET, Java 1.6, Perl, ColdFusion e PHP 5.2. Direi che ce n'è abbastanza.

La cosa che invece, personalmente, ho trovato lunga e intricata è il debug del servizio che andremo a metter in piedi. Intricato perché mentre il debug del PDT può essere fatto in locale, impostanto il nostro server di sviluppo con indirizzo di ritorno dell'AutoReturn, per quanto riguarda l'IPN occorre necessariamente che la nostra pagina contenente il servizio di back-end sia on-line. In più, non sarò io dal mio monitor, che chiamerò la pagina bensì il server di PayPal per cui sarebbe assolutamente inutile stampare a monitor informazioni di debug.
La cosa che ho fatto io è stato inviarmi un mail con tutte le informazioni, esiti positivi o negativi di ogni step, informazioni su ogni istrutzione ogni volta che la pagina veniva chiamata. E qui viene il bello! Chiamata si... ma da chi? Per fortuna PayPal ha pensato agli sviluppatori. Non è necessario simulare un acquisto ogni volta che vogliamo testare il nostro sistema IPN (che funzionerebbe anche così sia chiaro, ma perderemmo una marea di tempo), bensì si può utilizzare l'Instant Payment Notification (IPN) simulator: impostiamo l'indirizzo della nostra pagina con il servizio di back-end e simuliamo l'invio di un IPN con tutti i dati che vogliamo testare.

Anche per l'IPN occurre seguire una procedura di verifica simile al PDT per evitare di elaborare informazioni fraudolente:

  • PayPal invia in HTTP POST una serie di informazioni alla nostra pagina con il servizio IPN

  • Il nostro servizio IPN deve prendere tutto il pacchetto, aggiungere in fondo il comando cmd=_notify-validate e spedire il tutto all'indirizzo https://www.paypal.com/cgi-bin/webscr
    opure all'indirizzo https://www.sandbox.paypal.com/cgi-bin/webscr se si sta ancora sperimentando nella SandBox. Questo serve per verificare che i dati in arrivo tramite HTTP POST siano realmente partiti da PayPal.

  • PayPal risponderà con VERIFIED oppure INVALID. Dopo aver ricevuto la conferma assicurati di inviare la stringa 200 OK senza la quale PayPal continuerà ad inviare la risposta da 4 secondi, raddoppiando il tempo di attesa prima di inviare il successivo (8 secondi, 16 secondi, 32 secondi) fino a quattro giorni.


Se la risposta sarà VERIFIED allora si potrà procedere all'elaborazione, altrimenti si dovrà procedere di conseguenza.
Ecco il codice di esempio per vb.NET:

 

Imports System.Net
Imports System.IO

Partial Class vbIPNexample
Inherits System.Web.UI.Page

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'Post back to either sandbox or live
Dim strSandbox As String = "https://www.sandbox.paypal.com/cgi-bin/webscr"
Dim strLive As String = "https://www.paypal.com/cgi-bin/webscr"
Dim req As HttpWebRequest = CType(WebRequest.Create(strSandbox), HttpWebRequest)

'Set values for the request back
req.Method = "POST"
req.ContentType = "application/x-www-form-urlencoded"
Dim Param() As Byte = Request.BinaryRead(HttpContext.Current.Request.ContentLength)
Dim strRequest As String = Encoding.ASCII.GetString(Param)
strRequest = strRequest + "&cmd=_notify-validate"
req.ContentLength = strRequest.Length

'for proxy
'Dim proxy As New WebProxy(New System.Uri("http://url:port#"))
'req.Proxy = proxy

'Send the request to PayPal and get the response
Dim streamOut As StreamWriter = New StreamWriter(req.GetRequestStream(), Encoding.ASCII)
streamOut.Write(strRequest)
streamOut.Close()
Dim streamIn As StreamReader = New StreamReader(req.GetResponse().GetResponseStream())
Dim strResponse As String = streamIn.ReadToEnd()
streamIn.Close()

If strResponse = "VERIFIED" Then
'check the payment_status is Completed
'check that txn_id has not been previously processed
'check that receiver_email is your Primary PayPal email
'check that payment_amount/payment_currency are correct
'process payment
ElseIf strResponse = "INVALID" Then
'log for manual investigation
Else
'Response wasn't VERIFIED or INVALID, log for manual investigation
End If
End Sub
End Class

 

Codice, questo, che non ha bisogno di modifiche nella sostanza, al di l'ha dell'aggiunta di tutte le procedure in caso di verifca positiva o negativa delle informazioni. Ed è qua che il debug sarà più arduo perché, per sapere se l'errore è di logica oppure se avete semplicemente sbagliato a digitare il nome della vostra Stored Procedure, occorre attendere la mail alla vostra casella o qualsiasi altro mezzo abbiate escogitato per fare il debug del servizio.

Per completezza ecco un link contenente la maggior parte delle variabili IPD e IPN.


Considerazioni

Considerando che le casistiche sono davvero parecchie, occorrerà fare moltissime prove prima di rendere pubblico tutto l'apparato per accettare pagamenti e, come detto all'inzio, occorrerà parecchia pazienza.

Quando dialogato con il sito di PayPal usate sempre https://...

Spero che questa pagina, o almeno in parte, possa essere utile a chi è nuovo nell'implementazione di PayPal come metodo di pagamento on-line. Nel caso dovessi trovare errori o refusi ti chiedo di contattarmi in modo da correggere gli eventuali errori.



Link correlati

Introduction to PayPal for C# - ASP.NET developers - Articolo scritto da Predrag Tomasevic
PayPal Developer Central
PayPal SandBox
HTML Variables for PayPal Payments Standard
Code Samples - Instant Payment Notification
IPN and PDT Variables


Note

[1] Per chi non lo sapesse le transazioni di PayPal avvengo tra indirizzi e-mail: un indirizzo e-mail invia un pagamento ad un altro indirizzo e-mail. Solo PayPal è a conoscenza dei numeri delle carte di credito o dei conti correnti di appoggio.
[2] Vederla così... capisco che sia "parecchio" semplificata... ma come si dice, per capirsi!

 
 
 
Commenti
  Commento di  Maurizio Piantanida - Inserito il 02 marzo 2016  
 
 

Ciao Articolo molto esaustivo, complimenti! Premeto che sono alle prime armi con dot.net, ho seguito tutti passi da te indicati, ma con la verifica Instant Payment Notification (IPN) simulator, mi ritorna sempre un errore di questo tipo: IPN was not sent, and the handshake was not verified. Please review your information. Non riesco a capire se è un errore di codice o di server.... tu hai qualche idea? Grazie


 
 
 
  Commento di  ASP NET - Inserito il 07 ottobre 2020  
 
 

If you are looking the latest solution of a payment gateway integration in ASP.NET Web Forms, check out demos: - For PayPal https://techtolia.com/PayPal/ Receive payments from PayPal, PayPal Credit, credit or debit cards, Bancontact, BLIK, eps, giropay, iDEAL, MyBank, Przelewy24, SEPA-Lastschrift, Sofort, Venmo via PayPal. - For Stripe https://techtolia.com/Stripe/ Receive payments from credit or debit cards, Alipay, WeChat Pay, Bancontact, EPS, giropay, iDEAL, Multibanco, Przelewy24, Sofort, Payment Request Button and Secure Remote Commerce via Stripe.


 
 
Lascia un commento
 
Nome:
Cognome:
e-mail:
Commento:
Con l'invio del modulo, dichiaro di avere letto l'informativa sulla privacy qui riportata, e acconsento al trattamento dei miei dati secondo le modalità indicate, per le finalità di cui al punto 1 dell'informativa.
 
Captcha
  Specificare i caratteri visualizzati nell'immagine.


Se i caratteri nell'immagine sono di difficile comprensione prova ad aggiornare l'immagine.