2014-10-30 17 views
9

Sto cercando di implementare un Paypal notifica immediata del pagamento (IPN)Get richiesta POST prima in un ApiController

Il protocol è

  1. PayPal HTTP POST vostro ascoltatore un messaggio IPN che notifica di un evento.
  2. Il listener restituisce una risposta HTTP 200 vuota a PayPal.
  3. Il listener HTTP invia il messaggio completo, inalterato a PayPal; il messaggio deve contenere gli stessi campi (nello stesso ordine) come messaggio originale ed essere codificato allo stesso modo del messaggio originale .
  4. PayPal invia una sola parola indietro: VERIFIED (se il messaggio corrisponde all'originale) o INVALID (se il messaggio non corrisponde all'originale ).

Finora ho

 [Route("IPN")] 
     [HttpPost] 
     public void IPN(PaypalIPNBindingModel model) 
     { 
      if (!ModelState.IsValid) 
      { 
       // if you want to use the PayPal sandbox change this from false to true 
       string response = GetPayPalResponse(model, true); 

       if (response == "VERIFIED") 
       { 

       } 
      } 
     } 

     string GetPayPalResponse(PaypalIPNBindingModel model, bool useSandbox) 
     { 
      string responseState = "INVALID"; 
      // Parse the variables 
      // Choose whether to use sandbox or live environment 
      string paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/" 
      : "https://www.paypal.com/cgi-bin/webscr"; 

      using (var client = new HttpClient()) 
      { 
       client.BaseAddress = new Uri(paypalUrl); 
       client.DefaultRequestHeaders.Accept.Clear(); 
       client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded")); 

       //STEP 2 in the paypal protocol 
       //Send HTTP CODE 200 
       HttpResponseMessage response = client.PostAsync("cgi-bin/webscr", "").Result; 

       if (response.IsSuccessStatusCode) 
       { 
        //STEP 3 
        //Send the paypal request back with _notify-validate 
        model.cmd = "_notify-validate"; 
        response = client.PostAsync("cgi-bin/webscr", THE RAW PAYPAL REQUEST in THE SAME ORDER).Result; 

        if(response.IsSuccessStatusCode) 
        { 
         responseState = response.Content.ReadAsStringAsync().Result; 
        } 
       } 
      } 

      return responseState; 
     } 

Il mio problema è che non riesco a capire come inviare la richiesta originale a Paypal con i parametri nello stesso ordine. Potrei costruire un HttpContent con il mio PaypalIPNBindingModel ma non posso garantire l'ordine.

C'è un modo per raggiungere questo obiettivo?

Grazie

+0

Non è possibile ricevere come una stringa da PayPal, quindi è possibile deserializzare da soli, fate quello che dovete fare per convalidarlo, poi posta la stringa hanno mandato indietro? –

+0

Grazie, sì penso, ma ho pensato che sarebbe stato più elegante usare il modello di binding di asp.net, ma se non c'è altro modo, farò la deserializzazione da solo. – Marc

risposta

12

credo che non si dovrebbe usare il parametro vincolante e appena letto la richiesta grezzo da soli. Successivamente, puoi deserializzare nel modello te stesso. In alternativa, se si desidera sfruttare l'associazione del modello dell'API Web e allo stesso tempo accedere al corpo della richiesta non elaborata, ecco un modo in cui potrei pensare.

Quando l'API Web esegue il binding del corpo della richiesta nel parametro, il flusso del corpo della richiesta viene svuotato. Successivamente, non puoi leggerlo di nuovo.

[HttpPost] 
public async Task IPN(PaypalIPNBindingModel model) 
{ 
    var body = await Request.Content.ReadAsStringAsync(); // body will be "". 
} 

Quindi, è necessario leggere il corpo prima dell'esecuzione del binding di modello nella pipeline dell'API Web. Se si crea un gestore messaggi, è possibile preparare il corpo lì e memorizzarlo nel dizionario delle proprietà dell'oggetto richiesta.

public class MyHandler : DelegatingHandler 
{ 
    protected async override Task<HttpResponseMessage> SendAsync(
              HttpRequestMessage request, 
              CancellationToken cancellationToken) 
    { 
     if (request.Content != null) 
     { 
      string body = await request.Content.ReadAsStringAsync(); 
      request.Properties["body"] = body; 
     } 

     return await base.SendAsync(request, cancellationToken); 
    } 
} 

Quindi, dal controller è possibile recuperare la stringa del corpo, in questo modo. A questo punto, hai il corpo della richiesta non elaborato e il modello associato al parametro.

[HttpPost] 
public void IPN(PaypalIPNBindingModel model) 
{ 
    var body = (string)(Request.Properties["body"]); 
} 
+0

Grazie, finalmente non ho usato il modello di rilegatura. – Marc

+0

Immagino che non ci sia modo di associare manualmente quella richiesta grezza a un modello? – Marc

+0

Cosa intendi legando manualmente la richiesta grezza a un modello? Se intendi creare un'istanza dell'oggetto modello in base alla richiesta non elaborata, devi farlo tu stesso. Non ho familiarità con IPN ma in base al tipo di contenuto, devi farlo. Se è disponibile un formattatore di tipo multimediale predefinito, l'API Web lo farà automaticamente. – Badri

Problemi correlati