ASP.NET网站跳转Authorize.Net支付网关及令牌生成故障求助
Let's break down the issues in your code and walk through how to fix them step by step to get your Authorize.Net integration working correctly for your ASP.NET WebForms project.
1. Fixing Customer Profile ID Generation
Your current code has several critical issues that prevent successful customer profile creation:
- Incorrect payment type assignment (you're passing strings instead of SDK-specific payment objects)
- Null reference risks when handling failed responses
- Redundant/unconfigured eCheck profile (if you don't need eCheck support, remove it to simplify)
Here's the corrected code:
// Set environment (sandbox for testing, production for live) ApiOperationBase<ANetApiRequest, ANetApiResponse>.RunEnvironment = AuthorizeNet.Environment.SANDBOX; // Configure merchant authentication ApiOperationBase<ANetApiRequest, ANetApiResponse>.MerchantAuthentication = new merchantAuthenticationType { name = ApiLoginID, ItemElementName = ItemChoiceType.transactionKey, Item = ApiTransactionKey }; // Create a valid credit card payment profile (use test card for sandbox) var ccPaymentProfile = new customerPaymentProfileType { payment = new paymentType { Item = new creditCardType { cardNumber = "4111111111111111", // Sandbox test card expirationDate = "2028-12" } } }; // Optional: Add eCheck profile only if you need it (configure properly) // var echeckPaymentProfile = new customerPaymentProfileType // { // payment = new paymentType // { // Item = new bankAccountType // { // accountType = bankAccountTypeEnum.checking, // routingNumber = "123456789", // accountNumber = "1234567890", // nameOnAccount = "Test User" // } // } // }; var paymentProfiles = new List<customerPaymentProfileType> { ccPaymentProfile }; // Build customer profile var customerProfile = new customerProfileType { email = emailId, paymentProfiles = paymentProfiles.ToArray() }; // Create profile request var request = new createCustomerProfileRequest { profile = customerProfile, validationMode = validationModeEnum.none }; // Execute request and handle response safely var controller = new createCustomerProfileController(request); controller.Execute(); var response = controller.GetApiResponse(); if (response != null) { if (response.messages.resultCode == messageTypeEnum.Ok) { Console.WriteLine($"Customer Profile ID: {response.customerProfileId}"); Console.WriteLine($"Payment Profile ID: {response.customerPaymentProfileIdList[0]}"); return response; } else { Console.WriteLine("Customer Profile Creation Failed:"); foreach (var error in response.messages.message) { Console.WriteLine($"Code: {error.code}, Message: {error.text}"); } } } else { var errorResponse = controller.GetErrorResponse(); if (errorResponse?.messages?.message != null) { Console.WriteLine("Customer Profile Creation Failed:"); foreach (var error in errorResponse.messages.message) { Console.WriteLine($"Code: {error.code}, Message: {error.text}"); } } else { Console.WriteLine("Null response received from Authorize.Net"); } } return null;
2. Fixing Token Generation for Payment Redirect
You're using the wrong API endpoint (getHostedProfilePageRequest is for managing customer profiles, not initiating payments). For a payment form with an amount, use getHostedPaymentPageRequest. Also, your XML string has unnecessary escaped characters and manual concatenation is error-prone.
Here's the corrected token generation code:
public string GetPaymentToken(string customerProfileId, decimal amount, HttpRequestBase callingPage) { // Build valid Iframe Communicator URL var communicatorPath = $"{callingPage.Scheme}://{callingPage.Host}"; if (callingPage.Port != 80 && callingPage.Port != 443) { communicatorPath += $":{callingPage.Port}"; } communicatorPath += "/contentx/IframeCommunicator.html"; // Build XML request using XmlDocument to avoid formatting errors var requestXml = new XmlDocument(); var root = requestXml.CreateElement("getHostedPaymentPageRequest", "AnetApi/xml/v1/schema/AnetApiSchema.xsd"); // Add merchant authentication var merchantAuth = requestXml.CreateElement("merchantAuthentication"); var apiLogin = requestXml.CreateElement("name"); apiLogin.InnerText = "API_LOGIN_ID"; var transKey = requestXml.CreateElement("transactionKey"); transKey.InnerText = "TRANSACTION_KEY"; merchantAuth.AppendChild(apiLogin); merchantAuth.AppendChild(transKey); root.AppendChild(merchantAuth); // Add transaction details (include your dynamic amount here) var transactionReq = requestXml.CreateElement("transactionRequest"); var transType = requestXml.CreateElement("transactionType"); transType.InnerText = "authCaptureTransaction"; // Use "authOnlyTransaction" if you need to capture later var amountElem = requestXml.CreateElement("amount"); amountElem.InnerText = amount.ToString("F2"); // Format to 2 decimal places transactionReq.AppendChild(transType); transactionReq.AppendChild(amountElem); root.AppendChild(transactionReq); // Link to customer profile var profileIdElem = requestXml.CreateElement("customerProfileId"); profileIdElem.InnerText = customerProfileId; root.AppendChild(profileIdElem); // Add hosted payment settings var hostedSettings = requestXml.CreateElement("hostedPaymentSettings"); hostedSettings.AppendChild(CreateSetting(requestXml, "hostedPaymentPageBorderVisible", "false")); hostedSettings.AppendChild(CreateSetting(requestXml, "hostedPaymentIFrameCommunicatorUrl", communicatorPath)); root.AppendChild(hostedSettings); requestXml.AppendChild(root); // Send request to Authorize.Net var apiUrl = "https://apitest.authorize.net/xml/v1/request.api"; var req = (HttpWebRequest)WebRequest.Create(apiUrl); req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); req.KeepAlive = false; req.Timeout = 30000; req.Method = "POST"; req.ContentType = "text/xml; charset=utf-8"; using (var stream = req.GetRequestStream()) { requestXml.Save(stream); } // Process response using (var resp = (HttpWebResponse)req.GetResponse()) using (var readStream = resp.GetResponseStream()) using (var reader = new StreamReader(readStream, Encoding.UTF8)) { var responseData = reader.ReadToEnd(); var responseDoc = new XmlDocument(); responseDoc.LoadXml(responseData); // Check for success var resultCode = responseDoc.SelectSingleNode("//resultCode")?.InnerText; if (resultCode != "Ok") { var errorMsg = responseDoc.SelectSingleNode("//message/text")?.InnerText; throw new Exception($"Token generation failed: {errorMsg ?? "Unknown error"}"); } var tokenNode = responseDoc.SelectSingleNode("//token"); return tokenNode?.InnerText ?? throw new Exception("Token not found in response"); } } // Helper method to create setting elements private XmlElement CreateSetting(XmlDocument doc, string name, string value) { var setting = doc.CreateElement("setting"); var nameElem = doc.CreateElement("settingName"); nameElem.InnerText = name; var valueElem = doc.CreateElement("settingValue"); valueElem.InnerText = value; setting.AppendChild(nameElem); setting.AppendChild(valueElem); return setting; }
3. Redirect to Authorize.Net Payment Gateway
Once you have the token, redirect the user to the hosted payment page in your button click handler:
protected void btnPay_Click(object sender, EventArgs e) { try { // Get your customer profile ID from the corrected profile creation code var customerProfileId = "YOUR_CUSTOMER_PROFILE_ID"; var paymentAmount = 99.99m; // Replace with your dynamic amount var paymentToken = GetPaymentToken(customerProfileId, paymentAmount, Request); // Redirect to sandbox payment page (use production URL for live) Response.Redirect($"https://test.authorize.net/payment/payment?token={paymentToken}"); } catch (Exception ex) { // Show error to user or log it lblPaymentError.Text = $"Payment setup failed: {ex.Message}"; } }
4. Receive Transaction ID from Response
Use the IframeCommunicator.html to listen for payment completion messages from Authorize.Net. Add this JavaScript to your page:
<script> function receivePaymentResponse(event) { // Only accept messages from Authorize.Net sandbox (update for production) if (event.origin !== "https://test.authorize.net") return; var response = JSON.parse(event.data); if (response.responseCode === "1") { // Payment succeeded - get transaction ID var transactionId = response.transactionId; // Send transaction ID to your server for processing (e.g., via AJAX) console.log("Transaction completed successfully. ID: " + transactionId); // Redirect to confirmation page or update UI } else { // Handle payment failure console.log("Payment failed: " + response.responseReasonText); } } window.addEventListener("message", receivePaymentResponse, false); </script>
Key Notes
- Always use the official Authorize.Net NuGet package (
AuthorizeNet) to avoid manual XML parsing errors where possible. - Switch to production environment and API URLs when you're ready to go live.
- Add robust error logging for all integration steps to troubleshoot issues quickly.
内容的提问来源于stack exchange,提问作者Anushri Dhale

