I'm trying to implement a Paypal Instant Payment Notification (IPN)
The protocol is
So far I have
[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;
}
My problem is I can't figure out how to send the original request to Paypal with the parameters in the same order.
I could build a HttpContent
with my PaypalIPNBindingModel
but I can't guarantee the order.
Is there any way I could achieve this?
Thank you
I believe you should not use parameter binding and just read the raw request yourself. Subsequently, you can deserialize into the model yourself. Alternatively, if you want to leverage Web API's model binding and at the same time, access the raw request body, here is one way I could think of.
When Web API binds the request body into the parameter, the request body stream is emptied. Subsequently, you cannot read it again.
[HttpPost]
public async Task IPN(PaypalIPNBindingModel model)
{
var body = await Request.Content.ReadAsStringAsync(); // body will be "".
}
So, you have to read the body before model binding runs in Web API pipeline. If you create a message handler, you can ready the body there and store it in the properties dictionary of the request object.
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);
}
}
Then, from controller you can retrieve the body string, like this. At this point, you have the raw request body as well as the parameter-bound model.
[HttpPost]
public void IPN(PaypalIPNBindingModel model)
{
var body = (string)(Request.Properties["body"]);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With