Saturday, June 9, 2012

MVC3 and Authorize.net

One of my clients asked me to “hook-up” a new website, wakeupwitheasyup.com,  to their merchant account, Authorize.net.  Up to this date most of my experience with merchant accounts was in using shopping cart solutions like zencart, opencart, and using paypal tools.  The challenge with this situation was that I had already created a website using a C# MVC3 solution and My client’s timelines were short and needed to get online ordering up as soon as possible.  We did not have the time to put together a new shopping cart site and theme it to match their current site and to get security certificates and all of that setup.  Knowing the urgency I took a look at what tools Authorize.net had available.  They had several developer packages on their website, http://developer.authorize.net/downloads/samplecode, though I was not sure exactly what the difference between these solutions were or what they were for.  I read some of the brief materials on their website and guessed that the solution I was looking for was “Server Integration Method (SIM)”.  Some of the other solutions I am still not quite sure what they were for.  Luckily the solution I downloaded was exactly what I needed.  With this solution I am able to pass a product description and price to Authorize.net’s secure servers and they will handle the actual order and payment processing.  This is great since it would not involved a major re-design of the website, which will keep the cost and timelines down for the client.

First thing I discovered was that the sample code that I downloaded was designed in VS 2008.  Not a big deal, I converted it to VS 2010 and there were no errors.  Everything converted perfectly.  There are two values that are needed for anyone looking to go further in this process, the api login id and the transaction key.  The second thing to note is that the default URL that is in the package is for developers using this package to integrate into their own solutions.  Authorize.net uses a different URL for developers in their testing than they do for business users (whether the code is in test mode or production).  Even though I am a developer I am using my client’s api key (I do not have one as of yet) so I had to change the URL from https://test.authorize.net/gateway/transact.dll (by use by developers) to https://secure.authorize.net/gateway/transact.dll (for use by clients).  If you are a developer looking to add this functionality to your solution but are not a client you can obtain a free developer’s api login by going to http://developer.authorize.net.

Now that I have the project converted and the three values updated I launched the project which is just a basic page with a visual of a price, product description and a button.  Pressing the button posted the info to authorize.net’s webservers.  I was sent to a screen that showed an ordering screen with the product info and price that was on my page along fields to enter my order info.

So far so good.  At this point I was thinking that this was going to be one of the easiest things I was going to have to do.  I then copied the appropriate fields, code and values to my client’s website.  This is where I ran into the issue.  When I clicked the button I received an error that the info Authorize.net received was incorrect.

One thing to note is that this process uses what is called a “post” to send the values to Authorize.net.  For those that are not familiar with what a “post” is, it is a process whereby a web page define a “form” with fields in it that can be sent to another website based upon the name of the field.  This solution uses several hidden fields to store values that are needed for the authentication process that is needed to communicate with Authorize.net.  The code to create these values is done using server-side code which means that these fields need have the attribute “runat=’server’” so that the server-side code could reference them.

So far this does not sound like a big deal except that I decided to use master pages to help keep the look and feels of all the pages consistent.  One of the elements of master pages is that by default custom values are added to the front of the ID and Name attributes of any of the server-side fields on the page (to help keep fields unique).  The reason why I was getting failures was because the name attributes had been changed as a result of this configuration.  There is an option in the code to prevent the “ID” attribute from changing though the problem is Authorize.net’s process is pulling field values using the “name” attribute.  C# does not have any options for keeping the “name” attribute the same as what I put in.

So what does this mean?  This means that I am not able to handle the logic to send the proper values to Authorize.net on the ordering page.  The best option that I can come up with in short time (there may be others that are better that I did not think of) was to create a generic page that is not associated to a master page to handle the posting to Authorize.net.

In thinking about this I was concerned about someone being able to “hack” the process and changing the price or product info through other means.  For this reason I did not want to send the info via querystring and I wanted to have some logic to prevent the posting page from receiving requests fron unauthorized pages.

Since I am using MVC3 I am not able to use a button with associated events to perform the logic that I needed.  Instead I have to use a button that calls a URL.  Like I said I did not want to have the product and price in the URL so instead I am passing a code.  I opened the Order controller in my MVC3 application and created a new ActionResult called SendOrder.  I also create a new class (and put it into the model folder) called Product that has two variables, Price and Product Description.  In the SendOrder controller I create a new variable with the type of Product.  Then I have a switch statement that looks at the code that is passed in the URL.  Based upon the code I then update the Product variable with the appropriate values for the product code passed.  I then call the View and pass the variable (as a Model) into the page.

Next I created a new view (without a master page) called SendOrder.  I moved all the code that I had previously tested with to this page.  All of the page elements are hidden so I added some simple text “Please wait while your order is being processed.”  I then set the “onload” attribute of the body of the page to “window.document.forms[0].submit();” which will cause the page to post its information to Authorize.net’s website as soon as the DOM is finished loading.  Depending upon what browser you are using there is a brief delay where the user will see this page and when the next page it displayed.  I did not see any delay with Chrome though for both IE9 and FireFox I did notice a delay (though it does work on all three of the major browsers).

This approach is not perfect though it was working fine and I think is secure enough to prevent anyone from hacking their own price.  I removed the “test” to put the page into production and then copied all the files to the client’s webserver and everything continues to work after that.  It would have been a lot nicer to have a full shopping cart and to not have to deal with some of the inherent issues that I ran into though with all of that we were able to added an online-ordering process to their website in about 4 hours worth of work.

No comments:

Post a Comment