ASP.NET Core IPN Request Body is empty
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm using IPN for my ASP.NET Core web app (apologies for the edge case), but the data I receive from the IPN Simulator (the data that I send back with cmd=_notify-validate& prepended to it) appears to be empty. I have the code pasted below, but for the current debugging, a generic transaction is logged, instead of the simulated data (as I cannot attempt to parse it currently).
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MyProject.Config;
using MyProject.Models;
namespace MyProject.Controllers { // IPN = Instant Payment Notification
public class IPNController : Controller {
private IOptionsSnapshot storageConfig;
HelperFunctions helperFunctions = new HelperFunctions();
private class IPNContext {
public HttpRequest IPNRequest { get; set; }
public string RequestBody { get; set; }
public string Verification { get; set; } = string.Empty;
}
public IActionResult IPN ([FromServices] IOptionsSnapshot storageConfig) {
return Receive(storageConfig);
}
// Should run when an IPN is recieved
[HttpPost]
public IActionResult Receive (IOptionsSnapshot _storageConfig) {
storageConfig = _storageConfig;
IPNContext ipnContext = new IPNContext {
IPNRequest = Request
};
using (StreamReader reader = new StreamReader(ipnContext.IPNRequest.Body, Encoding.ASCII)) {
ipnContext.RequestBody = reader.ReadToEnd();
}
//Store the IPN received from PayPal
Transaction transaction = LogRequest(ipnContext);
//Fire and forget verification task
Task.Run(() => VerifyTask(ipnContext, transaction));
//Reply back a 200 code
return Ok();
}
private async Task VerifyTask (IPNContext ipnContext, Transaction transaction) {
try {
var verificationRequest = WebRequest.Create("<a href="https://www.sandbox.paypal.com/cgi-bin/webscr" target="_blank">https://www.sandbox.paypal.com/cgi-bin/webscr</a>");
//Set values for the verification request
verificationRequest.Method = "POST";
verificationRequest.ContentType = "application/x-www-form-urlencoded";
//Add cmd=_notify-validate to the payload
string strRequest = "cmd=_notify-validate&" + ipnContext.RequestBody;
verificationRequest.ContentLength = strRequest.Length;
//Attach payload to the verification request
using (StreamWriter writer = new StreamWriter(verificationRequest.GetRequestStream(), Encoding.ASCII)) {
writer.Write(strRequest);
}
//Send the request to PayPal and get the response
using (StreamReader reader = new StreamReader(verificationRequest.GetResponse().GetResponseStream())) {
ipnContext.Verification = reader.ReadToEnd();
}
}
catch (Exception exception) {
//Capture exception for manual investigation
transaction.Error += "...Failed to verify IPN task: " + exception.Message;
}
await ProcessVerificationResponse(ipnContext, transaction);
}
// Should find the table entry created when payment was made, set verified to FALSE, and return it, and optionally discard incomplete transactions.
private Transaction LogRequest (IPNContext ipnContext) {
// Persist the request values into a database or temporary data store
return new Transaction {
Id = Guid.NewGuid().ToString(),
Payer = "payer123",
Reciever = "reciever123",
Val = "20.00",
TimeSent = DateTime.Now.ToString(), // NOTE: timestamp appears to be in Iceland?
Verified = "FALSE",
Error = ""
};
}
// Should update table entry on payment validity
private async Task ProcessVerificationResponse (IPNContext ipnContext, Transaction transaction) {
if (ipnContext.Verification.Equals("VERIFIED")) {
if (transaction.Error.Equals("")) {
transaction.Verified = "TRUE";
/*
* Some values to read:
* payment_status
* txn_type
* txn_id
* payment_gross
* payer_email
* first_name
* last_name
* Probably More?
*/
}
else {
transaction.Verified = "FALSE";
}
// check that Payment_status=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
} else if (ipnContext.Verification.Equals("INVALID")) {
transaction.Error += "...IPN could not be verified because it was found to be INVALID";
} else {
transaction.Error += "...IPN could not be verified for unknown reasons (neither VALID nor INVALID)";
}
transaction.Error += "...DEBUG NOTES...IPNRequest.Body = " + ipnContext.IPNRequest.Body + "...RequestBody = " + ipnContext.RequestBody + "...Verification = " + ipnContext.Verification;
await helperFunctions.SaveTransaction(storageConfig, transaction);
}
}
}
At the bottom there, I append the data from the IPN to an error message that I log, which is always,
...IPN could not be verified because it was found to be INVALID...DEBUG NOTES...IPNRequest.Body = Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.FrameRequestStream...RequestBody = ...Verification = INVALID
As you can see, RequestBody, which, as I understand, is supposed to contain the data about the transaction, is empty. Any ideas on how to fix this?
Thank you!
- Labels:
-
IPN
-
Reporting APIs
Haven't Found your Answer?
It happens. Hit the "Login to Ask the community" button to create a question for the PayPal community.
- IPN works in sandbox but not live in Sandbox Environment
- When I do PayPal capture Order, I keep on getting Invalid Request Connection in REST APIs
- IPN SHOWS NO HTTP RESPONSE - LISTENER WORKS WITH LOCAL FORM POST in Sandbox Environment
- capture error in Sandbox Environment
- ManageRecurringPaymentsProfileStatus method stopped working. in NVP/SOAP APIs