PayPal智能按钮:获取交易详情并更新至数据库
Hey there! Let's work through your PayPal payment gateway issue step by step—I’ve tackled similar ASP.NET MVC + PayPal integrations before, so I’ve got a few solid pointers for you.
First: Fixing the Transaction Data Retrieval
The key here is that you shouldn’t rely solely on frontend PayPal callback data for database updates (it’s vulnerable to tampering). Instead, you need to validate and fetch official transaction details via PayPal’s Orders API from your backend. Here’s how to set this up:
1. Update Your Frontend PayPal Button
Modify the onApprove callback to send the PayPal order ID to your ASP.NET MVC backend. This lets your server fetch the full, trusted transaction details:
paypal.Buttons({ createOrder: function(data, actions) { return actions.order.create({ purchase_units: [{ amount: { value: '10.00' } // Your dynamic amount here }] }); }, onApprove: function(data, actions) { // Send order ID to your backend verification endpoint return fetch('/PayPal/VerifyAndUpdatePayment', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ orderId: data.orderID }) }) .then(response => response.json()) .then(result => { if (result.success) { alert(`Payment confirmed! Transaction ID: ${result.transactionId}`); // Redirect to a success page if needed } else { alert('Payment verification failed. Please contact support.'); } }); } }).render('#paypal-button-container');
2. Backend Controller & PayPal API Integration
First, install the official PayPal SDK via NuGet: PayPalCheckoutSdk. Then create a controller to handle the verification and database update:
using PayPalCheckoutSdk.Core; using PayPalCheckoutSdk.Orders; using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; public class PayPalController : Controller { private readonly PayPalHttpClient _payPalClient; public PayPalController() { // Initialize with your sandbox/production credentials var environment = new SandboxEnvironment("YOUR_PAYPAL_CLIENT_ID", "YOUR_PAYPAL_CLIENT_SECRET"); _payPalClient = new PayPalHttpClient(environment); } [HttpPost] public async Task<IActionResult> VerifyAndUpdatePayment([FromBody] PaymentVerificationRequest request) { try { // Fetch full order details from PayPal var orderRequest = new OrdersGetRequest(request.OrderId); var apiResponse = await _payPalClient.Execute(orderRequest); var order = apiResponse.Result<Order>(); // Extract critical transaction data var capture = order.PurchaseUnits[0].Payments.Captures[0]; var transactionId = capture.Id; var totalAmount = order.PurchaseUnits[0].Amount.Value; var payerEmail = order.Payer.EmailAddress; var isPaymentCompleted = capture.Status == "COMPLETED"; if (isPaymentCompleted) { // Update your database here—ideally call a service layer method // Example: _orderService.MarkPaymentAsCompleted(orderIdFromYourDb, transactionId, totalAmount); return Json(new { success = true, transactionId }); } else { return Json(new { success = false, error = "Payment not marked as completed by PayPal" }); } } catch (Exception ex) { // Log the error for debugging return Json(new { success = false, error = ex.Message }); } } } // Model to receive the order ID from frontend public class PaymentVerificationRequest { public string OrderId { get; set; } }
Bonus: Add Webhooks for Reliability
To cover cases where the user closes the page before the frontend callback runs, set up a PayPal webhook. This lets PayPal send a POST request to your backend whenever a transaction is completed. You can handle this in the same PayPalController with an action that validates the webhook signature and updates your database.
Second: Where to Place the Code in ASP.NET MVC
Follow the MVC separation of responsibilities for clean, maintainable code:
- Controller: This is where the
VerifyAndUpdatePaymentaction belongs. Controllers handle HTTP requests, interact with external APIs (like PayPal), and coordinate business logic. - Service Layer (or Model): Move your database update logic into a dedicated service class (e.g.,
OrderService) instead of putting it directly in the controller. This keeps your controller focused on request handling, and your service focused on business rules. - Models: Use models like
PaymentVerificationRequestto transfer data between frontend and backend, or entity models to represent your database tables.
内容的提问来源于stack exchange,提问作者Cod Ding

