Wednesday, April 30, 2014

Authorize.Net Relay Response with ASP.NET

If you are using Authorize.Net as your payment engine and you are attempting to use Relay Response with ASP.NET, you will be disappointed to know that the code samples that Authorize.Net provides is only for Classic ASP!!  http://developer.authorize.net/downloads/samplecode/

Therefore, you are left to fend for yourself when it comes to developing a solution that is completely built on ASP.NET.

After simply converting the existing Classic ASP example over to ASP.NET, you end up with the following error message:

An error occurred while trying to report this transaction to the merchant. An e-mail has been sent to the merchant informing them of the error. The following is the result of the attempt to charge your credit card.

      This transaction has been approved.
It is advisable for you to contact the merchant to verify that you will receive the product or service.


After digging through numerous Authorize.Net Developer Forums, I FINALLY discovered the answer to resolving this error message:

In the Page directive for the ASP.NET Relay Response page, you have to add the following attribute: EnableViewStateMac="false"

If this attribute is NOT present, you will inevitably receive the error message indicated above.
 
In addition, if you are using ASP.NET 4.0/4.5, I have found that a very basic Web.config file works for my ASP.NET Web Forms project, but other ASP.NET 4.5 Web.config files (such as those that are part of One ASP.NET) DO NOT WORK!!
 
<?xml version="1.0"?>
<configuration>
 
    <system.web>
      <compilation debug="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5" />
    </system.web>
 
</configuration>


If you would like the code for the entire Relay Response page for ASP.NET Web Forms, I have provided it for you below:



<%@ page language="C#" autoeventwireup="true" codebehind="RelayResponse.aspx.cs" inherits="SIM_Example.RelayResponse" EnableViewStateMac="false"  %>
 
<!DOCTYPE html>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Transaction Receipt Page</title>
    <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
</head>
<body bgcolor="#FFFFFF">
    <form id="form1" runat="server">
        <%
   1:  
   2:               //Test to see if this is a test transaction.
   3:             if (TransID == "0" && ResponseCode == "1")
   4:             {
   5:  
   6:                 Response.Write("<table align='center'>");
   7:                 Response.Write("<tr>");
   8:                 Response.Write("<th><font size='5' color='red' face='arial'>TEST MODE</font></th>");
   9:                 Response.Write("<tr>");
  10:                 Response.Write("<th valign='top'><font size='1' color='black' face='arial'>This transaction will <u>NOT</u> be processed because your account is in Test Mode.</font></th>");
  11:                 Response.Write("</tr>");
  12:                 Response.Write("</table>");
  13:             }//if
  14:             Response.Write("<br>");
  15:             Response.Write("<br>");
  16:             //Test to see if the transaction resulted in Approval, Decline or Error
  17:             switch (ResponseCode)
  18:             {
  19:                 case "1":
  20:                     Response.Write("<table align='center'>");
  21:                     Response.Write("<tr>");
  22:                     Response.Write("<th><font size='3' color='#000000' face='Verdana, Arial, Helvetica, sans-serif'>This transaction has been approved.</font></th>");
  23:                     Response.Write("</tr>");
  24:                     Response.Write("</table>");
  25:                     break;
  26:                 case "2":
  27:                     Response.Write("<table align='center'>");
  28:                     Response.Write("<tr>");
  29:                     Response.Write("<th width='312'><font size='3' color='#000000' face='Verdana, Arial, Helvetica, sans-serif'>This transaction has been declined.</font></th>");
  30:                     Response.Write("</tr>");
  31:                     Response.Write("</table>");
  32:                     break;
  33:                 default:
  34:  
  35:                     Response.Write("<table align='center'>");
  36:                     Response.Write("<tr>");
  37:                     Response.Write("<th colspan='2'><font size='3' color='Red' face='Verdana, Arial, Helvetica, sans-serif'>There was an error processing this transaction.</font></th>");
  38:                     Response.Write("</tr>");
  39:                     Response.Write("</table>");
  40:                     break;
  41:             }//switch 
  42:  
  43:             Response.Write("<br>");
  44:             Response.Write("<br>");
  45:  
  46:             Response.Write("<table align='center' width='60%'>");
  47:             Response.Write("<tr>");
  48:             Response.Write("<td align='right' width='175' valign='top'>");
  49:             Response.Write("<font size='2' color='black' face='arial'>");
  50:             Response.Write("<b>");
  51:             Response.Write("Amount:" + "</b>");
  52:             Response.Write("</font>");
  53:             Response.Write("</td>");
  54:             Response.Write("<td align='left'>");
  55:             Response.Write("<font size='2' color='black' face='arial'>");
  56:  
  57:             Response.Write("$" + Amount);
  58:             Response.Write("</td>");
  59:             Response.Write("</tr>");
  60:  
  61:             Response.Write("<tr>");
  62:             Response.Write("<td align='right' width='175' valign='top'>");
  63:             Response.Write("<font size='2' color='black' face='arial'>");
  64:             Response.Write("<b>");
  65:             Response.Write("Transaction ID:" + "</b>");
  66:             Response.Write("</font>");
  67:             Response.Write("</td>");
  68:             Response.Write("<td align='left'>");
  69:             Response.Write("<font size='2' color='black' face='arial'>");
  70:             switch (TransID)
  71:             {
  72:                 case "0":
  73:                     Response.Write("Not Applicable.");
  74:                     break;
  75:  
  76:                 default:
  77:                     Response.Write(TransID);
  78:                     break;
  79:             }//switch 
  80:             Response.Write("</td>");
  81:             Response.Write("</tr>");
  82:  
  83:             Response.Write("<tr>");
  84:             Response.Write("<td align='right' width='175' valign='top'>");
  85:             Response.Write("<font size='2' color='black' face='arial'>");
  86:             Response.Write("<b>");
  87:             Response.Write("Authorization Code:" + "</b>");
  88:             Response.Write("</font>");
  89:             Response.Write("</td>");
  90:             Response.Write("<td align='left'>");
  91:             Response.Write("<font size='2' color='black' face='arial'>");
  92:             switch (AuthCode)
  93:             {
  94:                 case "000000":
  95:                     Response.Write("Not Applicable.");
  96:                     break;
  97:                 default:
  98:                     Response.Write(AuthCode);
  99:                     break;
 100:             }//switch 
 101:             Response.Write("</td>");
 102:             Response.Write("</tr>");
 103:             Response.Write("<tr>");
 104:             Response.Write("<td align='right' width='175' valign='top'>");
 105:             Response.Write("<font size='2' color='black' face='arial'>");
 106:             Response.Write("<b>");
 107:             Response.Write("Response Reason:" + "</b>");
 108:             Response.Write("</font>"); Response.Write("</td>");
 109:             Response.Write("<td align='left'>");
 110:             Response.Write("<font size='2' color='black' face='arial'>");
 111:             Response.Write("(" + ResponseReasonCode + ")");
 112:             Response.Write("&nbsp");
 113:             Response.Write(ResponseReasonText);
 114:             Response.Write("</font>");
 115:             Response.Write("<font size='1' color='black' face='arial'>");
 116:             Response.Write("</td>");
 117:             Response.Write("</tr>");
 118:             Response.Write("<tr>");
 119:  
 120:             Response.Write("<td align='right' width='175' valign='top'>");
 121:             Response.Write("<font size='2' color='black' face='arial'>");
 122:             Response.Write("<b>");
 123:             Response.Write("Address Verification:" + "</b>");
 124:             Response.Write("</font>");
 125:             Response.Write("</td>");
 126:             Response.Write("<td align='left'>");
 127:             Response.Write("<font size='2' color='black' face='arial'>");
 128:  
 129:             //Turn the AVS code into the corresponding text string.
 130:             switch (AVS)
 131:             {
 132:                 case "A":
 133:                     Response.Write("Address (Street) matches, ZIP does not.");
 134:                     break;
 135:                 case "B":
 136:                     Response.Write("Address Information Not Provided for AVS Check.");
 137:                     break;
 138:                 case "C":
 139:                     Response.Write("Street address and Postal Code not verified for international transaction due to incompatible formats. (Acquirer sent both street address and Postal Code.");
 140:                     break;
 141:                 case "D":
 142:                     Response.Write("International Transaction:  Street address and Postal Code match.");
 143:                     break;
 144:                 case "E":
 145:                     Response.Write("AVS Error.");
 146:                     break;
 147:                 case "G":
 148:                     Response.Write("Non U.S. Card Issuing Bank.");
 149:                     break;
 150:                 case "N":
 151:                     Response.Write("No Match on Address (Street) or ZIP.");
 152:                     break;
 153:                 case "P":
 154:                     Response.Write("AVS not applicable for this transaction.");
 155:                     break;
 156:                 case "R":
 157:                     Response.Write("Retry. System unavailable or timed out.");
 158:                     break;
 159:                 case "S":
 160:                     Response.Write("Service not supported by issuer.");
 161:                     break;
 162:                 case "U":
 163:                     Response.Write("Address information is unavailable.");
 164:                     break;
 165:                 case "W":
 166:                     Response.Write("9 digit ZIP matches, Address (Street) does not.");
 167:                     break;
 168:                 case "X":
 169:                     Response.Write("Address (Street) and 9 digit ZIP match.");
 170:                     break;
 171:                 case "Y":
 172:                     Response.Write("Address (Street) and 5 digit ZIP match.");
 173:                     break;
 174:                 case "Z":
 175:                     Response.Write("5 digit ZIP matches, Address (Street) does not.");
 176:                     break;
 177:                 default:
 178:                     Response.Write("The address verification system returned an unknown value.");
 179:                     break;
 180:             }//switch 
 181:             Response.Write("</td>");
 182:             Response.Write("</tr>");
 183:             Response.Write("</table>");
 184:         
%>
    </form>
</body>
</html>

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
 
namespace SIM_Example
{
    public partial class RelayResponse : System.Web.UI.Page
    {
        public string ResponseCode, ResponseReasonText, ResponseReasonCode, ResponseSubcode, AVS, ReceiptLink, TransID;
        public string Amount, AuthCode;
 
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.Form.Count > 0)
            {
                //Retrieving and defining Form Data from Post command body from Authorize.Net
                ResponseCode = Request.Form["x_response_code"].Trim();
                ResponseReasonText = Request.Form["x_response_reason_text"].Trim();
                ResponseReasonCode = Request.Form["x_response_reason_code"].Trim();
                AVS = Request.Form["x_avs_code"].Trim();
                TransID = Request.Form["x_Trans_ID"].Trim();
                AuthCode = Request.Form["x_Auth_Code"].Trim();
                Amount = Request.Form["x_Amount"].Trim();
                ReceiptLink = "http://www.authorizenet.com";
            }//if
 
            
        }//event: Page_Load
    }
}


8 comments:

  1. Thanks a lot for this post.
    From last four hours I am searching for above issue and how to capture Transaction Id on redirected page.

    But i have one more issue. As in code samples that Authorize.Net provides they have mentioned form id="simForm" runat="server" method='post' action='https://test.authorize.net/gateway/transact.dll' , but because of this I can not move to back page for some corrections in amount or something else. So what type of code I have to write over here?
    Please help me!
    Thanks in Advance

    ReplyDelete
  2. If you are interested in completely controlling the checkout process, you should not be using Relay Response or the SIM Form methodology. Instead, you will want to use the Advanced Integration Method (AIM).

    ReplyDelete
  3. Our applications are used for only billing purpose like online electricity bill, patient hospital bills etc.. Currently we are using AIM (for one time payment) and ARB (for recurring) from last many months but now we want to avoid costly PCI compliance on our server. So we are planning to shift on SIM for one time payment and trying to achieve recurring billing using CIM.

    ReplyDelete
    Replies
    1. You won't get the flexibility that you desire if you go to SIM though. If you want some additional verifications before you go to the SIM page, I would recommend creating an ASP.NET or jQuery Wizard that allows you to go through a series of screens to confirm that everything is OK before submitting to Authorize.Net. In addition, you can configure the Payment Form to make a number of fields editable (Amount is not one of them).

      Delete
  4. Hi, Samir Vaidya Sir,
    I need one more help please.
    I am using above code and it is working fine to display our customized response page. But now issue is even after response the url in address bar is not showing our website's url and it is not coming back to our website. We want to save transaction ID in our database.
    How to achieve this? after surfing on net I read somewhere that we have to use receipt page instead of relay response so I used x_receipt_link_URL as our website url & x_receipt_link_method=POST and written same above code to take Transaction ID but still gateway url is not redirecting to our original website.
    Did you worked on such type of scenario?

    ReplyDelete
    Replies
    1. Yes, please check out this blog post article: http://samirvaidya.blogspot.com/2014/05/authorizenet-error-message-referrer.html

      You have to use the Relay_Response_Url field in your original form that is posting to Authorize.Net in order for the redirect to work.

      Delete
  5. Relay Response setting and all above your provided code is working correctly but my issue is something different. Can we read our previous page session on relayresponse page? e.g. In your application you have stored Session["SomeInfo"] on login page "ww.example.com\Login.aspx". Then rendered on SIM page which is on https://test.authorize.net/gateway/transact.dll. After submitting CC details and successful/failed transaction it will come on relayresponse page, so on this relayresponse page code
    if (TransID == "0" && ResponseCode == "1") Can you get Session["SomeInfo"] which was stored at login page? right now it is always showing NULL session. Please check at you site whether it is possible to get Session values on RelayResponsepage? . So how to achieve it?

    ReplyDelete
  6. No, you cannot pass Session information to Authorize.Net. Everything works through Form Posts. Therefore, you can store the Session information into a hidden field that is used by Authorize.Net. You may be able to simply store it in a hidden field and test whether or not Authorize.Net will post it back to your Relay Response screen. Otherwise, you can review the list of hidden fields supported by Authorize.Net to see if you can use one of these instead: http://developer.authorize.net/guides/SIM/wwhelp/wwhimpl/js/html/wwhelp.htm#href=Appendix%20A.html

    ReplyDelete