Monday, October 31, 2011

Why should we use dependency injection?

In this article we will explore some of the benefits of dependency injection and how this can be used in all types of programming, including small and simple programs. Some of the example shown below make use of Guice, a dependency injection framework by Google. The same concept applies for any other dependency injection framework.
This article does not provide detailed description of Guice but it only focus on the benefits of dependency injection and design methods that improve modularity, extendibility and testing.

What is dependency injection?

Let say we want to make some tea. How would we do it and what do we need? We need to boil some water, a clean mug, tea bags, sugar and milk (at least that's what I put into mine). In order to make tea we need to provide all these ingredients and we need to manage all these ourselves. We have to fill the kettle with water and heat it up, get the milk from the refrigerator and get the rest.
Now assume that we can make tea, by simply asking someone else to do it for us. Someone that knows how to do the tea just the way we want it. Would that be better than making the tea ourselves? If yes, then welcome to dependency injection.
Dependency injection is a framework that takes care of creating objects for us without we having to worry about providing the right ingredients so to say.

A Simple Example

Let say we have a class, Person, and this class needs to send a message. The Person class requires the aid of some other class, Email, in order to send a message. Following is a simple way of doing this.
public class Email {
  public void sendEmail(String subject, String message){
  }
}

public class Person {
  private Email email = new Email();

  public void greetFriend(){
    email.sendEmail(parameters...);
  }
}
Some code is omitted from the above classes for brevity
We all agree that this is a very simple and straight forward example that involves two simple Java classes. Nevertheless, the above has some limitations as listed below.
  • The Persons class is dependent (has a strong/tight dependency) on the Email class. There is a hard connection between these two classes. Let say we have a new better version of email class, FastEmail, in order for us to use it, we need to go in each and every class that depends on the Email class, such as the Person class, replace it with the new version.
  • Let say we parametrise the Email's constructor. Again we have to go in each and every class that is initialising the Email class, such as the Person class, and change it.
  • A design decision is taken to make the Email class singleton. Similar to above we need to modify all instances where it is used.
  • In order to improve the notifications/messages system, we decide to add different message delivery systems such as SMS or tweets. The Person class and other like it, need to all be modified in order for it to use the new classes.
  • Another developer needs to use the Person class, but would like to use a different notification/message system. This cannot be achieved with the current version of the Person class as it is hardwired to the Email class. What generally happens is that the other developer duplicates the Person class and modifies it as he/she needs. The projects ends up with two versions of the Person class.
  • In the above points we mentioned many scenarios where code has to be changed. All changes made, need to and should be tested. How can we test the Person class without including the message delivery class such as the Email? Testing, in many cases, is left as an afterthought. The way we have the Person class constructed makes it hard to test it without involving the Email class. Furthermore, how would we automate such test? How can we use JUnit or the like to automate out tests?
  • Moving forward in the project, the Person class starts to depend on another class that allow this object to write a letter using the Pen class for example. The Person class can use other ways to write a letter, such as Pencil class or Typewriter class, but this approach does not allow that.
These limitations can be improved by changing the way we think and restructure our code in a modular way. This is independent from dependency injection as we will see in the following section.

Change the way we think

The Email class provides a service, that is, sending of messages over the Internet using the mail protocol. Instead of having the Person class initialising an instance of the Email class, we first create an interface, MessageService, and make the Person class using this interface instead. This removed the dependency that the Person class has on the Email and replaces it with an abstract message delivery interface.
The following three steps: define, implement and use, show how we can develop modular and extendable code. This approach also improves testing as we will see at the end of this article.
  1. Define Interfaces Many developers do not use interfaces as they see them as additional non-required code. This may be true (I said maybe as the System class makes use of interfaces) for the famous hello world program, definitely not true for the rest. Like with everything else, we have to see things in context and there will be cases when we can do without interfaces. Nevertheless, developing code using interfaces produce far more modular and extendable code as illustrated in the following examples. The example discussed in the previous section was quite simple, but nevertheless it included several pitfalls which can be easily avoided. Changing code at a later stage involves more work than having it right in the first place.
    We start by defining the MessageService interface that includes one method, sendMessage(String subject, String message). For simplicity we assume that no exceptions are thrown.
    public interface MessageService {
      void sendMessage(String subject, String message);
    }
    
  2. Implement Interfaces In the list of limitations we mentioned four possible methods of sending a message: email, fast email, SMS and tweet. Let's create four classes that handle each message delivery method and have all these classes implement the interface created above.
    public class EmailService implements MessageService {
      @Override
      public void sendMessage(String subject, String message){
        System.out.printf("Email: %s, %s%n ", subject, message);
      }
    }
    
    public class FastEmailService implements MessageService {
      @Override
      public void sendMessage(String subject, String message){
        System.out.printf("Fast Email: %s, %s%n ", subject, message);
      }
    }
    
    public class SMSService implements MessageService {
      @Override
      public void sendMessage(String subject, String message){
        System.out.printf("SMS: %s, %s%n ", subject, message);
      }
    }
    
    public class TweetService implements MessageService {
      @Override
      public void sendMessage(String subject, String message){
        System.out.printf("Tweet: %s, %s%n", subject, message);
      }
    }
    
  3. Use Interfaces Finally, instead of using classes, we use interfaces. In the Person class, we replace the Email field with the MessageService service interface as shown in red below.
    public class Person {
      private MessageService messageService;
    
      public Person(MessageService messageService){
        this.messageService = messageService;
      }
    
      public void greetFriend(){
        messageService.sendMessage(parameters...);
      }
    }
    
    Note that the Person class is not initialising the message service but it is expecting it as a parameter of its constructor. This is a key element in the design. It improves modularity, extendibility and testing. The Person class is not dependent on any implementation, but on a service defined by an interface. This means that we can use the Person class without having to worry about the underlying implementation. Furthermore, different Person instance can be instantiated using different message services.
One can argue that the new version of Person class became more complex to instantiate as it requires parameters. This is a fair statement and here is when dependency injection comes into play.

Using Dependency Injection

As mentioned in the introduction, dependency injection can help us initialising objects and provide these objects all the necessary resources (ingredients). For example, the Person class requires an instance of MessageService. The dependency injection framework will provide that for us. So to create an instance of Person, all we need to do is call something like: dependecyFramework.getInstance(Person.class). Magically, (not really), the dependency injection framework will create an instance of the Person class and provide an instance of the a MessageService to the Person object.
The next natural question will be, how does the dependency injection framework knows how to initialise the MessageService? We need to tell the dependency injection framework how to create an instance of MessageService. With Google Guice we do that by creating a module (extends AbstractModule ) as illustrated below:
public class ProjectModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(MessageService.class).to(EmailService.class);
  }
}
Here we are telling the dependency injection how to create an instance of the MessageService class. We also need to add an annotation to the Person class in order to allow the dependency injection framework to inject the necessary parameters.
public class Person {
  private MessageService messageService;

  @Inject
  public Person(MessageService messageService){
    this.messageService = messageService;
  }

  public void greetFriend(){
    messageService.sendMessage(parameters...);
  }
}
With everything set, we create an instance of the Person class using the dependency injection framework
  Injector injector = Guice.createInjector(new ProjectModule());
  Person person = injector.getInstance(Person.class);
  person.greetFriend();
We replaced a couple of lines of code with many others. What's the buzz about this? In the next section we will see some of the benefits of dependency injection and how this can be used to simplify our coding life

Benefits of Dependency Injection

In this section we will see some key benefits of dependency injection
  • Changing the message service Let's change the delivery method from email to SMS. How would we do that?
    We only need to change the ProjectModule class to map the MessageService class to the SmsService class as shown in red below.
    public class ProjectModule extends AbstractModule {
    
      @Override
      protected void configure() {
        bind(MessageService.class).to(SmsService.class);
      }
    }
    
    This one change will affect all classes initialised with the dependency injection framework without having to change any of these classes. This leads us to another advantage, testing.
  • Changing the message service We can create a MockService class which can be using in JUnit test as shown next.
    public class MockService implements MessageService {
    
      public String subject;
      public String message;
    
      @Override
      public void sendMessage(String subject, String message) {
        this.subject = subject;
        this.message = message;
      }
    
    }
    
    The above mock message service simply stores the parameters into two public fields. These fields can be used to retrieve the values of the parameters and used for testing ass illustrated next.
    public class TestPerson {
    
      private Injector injector;
    
      @Before
      public void init() {
        injector = Guice.createInjector(new AbstractModule() {
          @Override
          protected void configure() {
            bind(MockMessageService.class).in(Singleton.class);
            bind(MessageService.class).to(MockService.class);
          }
        });
      }
    
      @Test
      public void testGreetFriend() {
        Person person = injector.getInstance(Person.class);
        person.greetFriend();
    
        MockService mockService = injector
            .getInstance(MockService.class);
        assertEquals("Greet", mockService.subject);
        assertEquals("Hello my friend", mockService.message);
      }
    }
    
    This may require some explanation. So here we go. We created an injection (Guice dependency injection) just for this testing and provided a custom module (as an abstract inner anonymous class). The custom module wires the MessageService with the MockService instead. Also, we set the MockService as singleton, that is, whenever we request an instance of this class from the injection we always get the same object (singleton). After greetFriend() is invoked, we test using JUnit to make sure that the correct parameters are being passed to the message service instance.
    This design setup allows us to test the Person class independent from the other classes that it depends on in an automated manner.
  • Changing the signature of the Person constructor As we mentioned in the limitations, the Person class may evolve and include more functionality. Changing the signature of the Person constructor will not affect us as long as the injector knows how to provide the required parameters.
    public class Person {
      @Inject
      public Person(MessageService messageService, 
                    WritingService writingService){
      }
    }
    
    The Person class will still be initialised in the same way as it is now. Thus changing the Person constructor signature will not affect the other classes that make us of it.
        Person person = injector.getInstance(Person.class);
    
    The same applies for anything that is initialised and handled through the injector.
  • Passing the Injector as parameter In a project we can have one instance shared throughout the project. This can be achieved by passing the Injector as a parameter to other objects that needs it. We setup the injector at the beginning (in a main method for example), and then have it set as a constructor parameter in all the classes that require an instance of the injector. Like that one injector will server all classes in the project.

Conclusion

This ended up to be quite a long article. Dependency injection is quite simple to use and it has quite a "shallow" learning curve. This article does not explain how to use the actual dependency injection framework (such as Guice). Articles about that are easily found. This article described key benefits of using a dependency injection framework even in small projects.

Monday, October 24, 2011

Application Lifecycle Management in Visual Studio 11

This post discusses about new Application Lifecycle Management features in Visual Studio 11. Application Lifecycle Management represents how do you prioritize your requirement, how do you breakdown them into tasks and how do you implement those tasks.

image 

Start with the Requirements, Visual Studio 11 coming up with new tool PowerPoint Storyboarding which you can use for visualise your customer requirements without writing a single line of code.


image

You will be presenting with different templates and layouts to author  the requirements

image

You  can also add various visual elements like button, grid etc to your slide and can add animation to tell your developers what you want to see when click some button in your screen.

image

You can quickly build the mockups using this new tab storyboarding in PowerPoint. Now we got the requirements and need to put in project management to describe what priority you are giving to these requirements and how do you deal with them?

We can do this project management using Visual Studio Team Foundation Server. Visual Studio 11 Team Web Access enhances the developer experience with some new features.

The new Team Web Access looks as below

image

Build Reports using Queue build is a new feature in 11 version

image

You can make changes to your files under source control using Team Web Access

image

This feature is not go developers to go and use team web access use for check in and check out the files. You can use this to edit the configuration files quickly if there is any change and build the reports quickly.

Now you can create teams and their identity and can assign the product backlog for the team using Team Web Access

image

You can prioritize the work-items by just drag and drop these items in team web access. Now you have the velocity charts which represents the story points assigned to the tasks to your team members.

image

Now TFS web access having the dates for your iterations

image

The Sprint screen in Team Web Access looks as below

image

sprint is where you break your product backlog items and assign a time-period and resources to it. You also got the burndown chart in this version which updates real-time with your work-items. Earlier it took time to update till you complete the TFS reports generation.

image

Generating Dependency graph is easy using architecture menu where you can find the dependency between assemblies in your solution. This feature is also available in Visual Studio 2010.

image

It then generates the graph as shown below

image

In Visual Studio 2010 if your solution is big one then you may need lot of memory to generate these graphs every-time when you choose this option where as in 11 these results are stored in cache and generates the results quickly from cache. It shows the links down to the method level in your solution.

The new team explorer looks new with some new features

image

The suspend link allows you to save all your current work including breakpoints and multiple monitor screens(window positions) if some one asks you to drop off what you are doing now and do a new high-priority work.

You can now search for new work-items within your team explorer. Now it clearly shows what you are doing and what are the incoming requests from other team-members like code-review request etc.

image

In Visual Studio 11 it supports unit test cases that you have written in Nunit, Xunit and MS-Test. All your test cases now appear in Unit Explorer.

image

There is a new tool in Visual Studio 11 which Analyses your code and finds the similar clones in the solution

image

Analyze Solution for Code Clones identifies the blocks of code that are identical and differ in few lines. This tool is a good candidate for refactoring your code.You can also find code clones from individual files.

image

Select the piece of code which you want to find the clone and say find matching clones in solution.

Exploratory testing is something new feature in Visual Studio 11 where you can fire-up your application take the screen shot and save as test case.

image

It records every action when explore this test and create a bug

image

Reference: Cameron session from BUILD.

Friday, October 21, 2011

SQL SERVER – DATEDIFF – Accuracy of Various Dateparts

I recently received the following question through email and I found it very interesting so I want to share it with you.

“Hi Pinal,

In SQL statement below the time difference between two given dates is 3 sec, but when checked in terms of Min it says 1 Min (whereas the actual min is 0.05Min)

SELECT DATEDIFF(MI,'2011-10-14 02:18:58' , '2011-10-14 02:19:01') AS MIN_DIFF



Is this is a BUG in SQL Server ?”

Answer is NO.

It is not a bug; it is a feature that works like that. Let us understand that in a bit more detail. When you instruct SQL Server to find the time difference in minutes, it just looks at the minute section only and completely ignores hour, second, millisecond, etc. So in terms of difference in minutes, it is indeed 1.

The following will also clear how DATEDIFF works:

SELECT DATEDIFF(YEAR,'2011-12-31 23:59:59' , '2012-01-01 00:00:00') AS YEAR_DIFF


The difference between the above dates is just 1 second, but in terms of year difference it shows 1.

If you want to have accuracy in seconds, you need to use a different approach. In the first example, the accurate method is to find the number of seconds first and then divide it by 60 to convert it to minutes.

SELECT DATEDIFF(second,'2011-10-14 02:18:58' , '2011-10-14 02:19:01')/60.0 AS MIN_DIFF


Even though the concept is very simple it is always a good idea to refresh it. Please share your related experience with me through your comments.

Tuesday, October 18, 2011

Microsoft Download Center : Microsoft® Visual Studio® 11 Developer Preview (ISO)

Visual Studio 11 Developer Preview is an integrated development environment that seamlessly spans the entire life cycle of software creation, including architecture, user interface design, code creation, code insight and analysis, code deployment, testing and validation.





Download, Install and feel the difference in developing style.

Enjoy..!!!!!


P.S. Please "+1" this post if you like it.

Thanks,

Monday, October 17, 2011

Microsoft finalises Skype deal - Video chat service company will run as a division of Microsoft

Microsoft has finalised its purchase of internet video chat service Skype for $8.5 billion.

The deal was first announced five months ago and was completed on Thursday.

According to the Press Association, Microsoft has hopes that Skype will help it catch up in the social networking, mobile phone and digital video market segments.



Skype has approximately 170m users worldwide, who created around 207 billion minutes of voice and video calls last year, adding up to almost 400,000 years' worth.

Skype will operate as a division within the Microsoft and Skype CEO Tony Bates is joining Microsoft to run the division and will report to Microsoft CEO Steve Ballmer.

Wednesday, October 12, 2011

Telerik MVC Upload Control

Download Telerik library from
To see demo of uplod control, visit
Reason to write this Blog:
Many times we require to get some status message after saving files e.g. FileId from database.
In this case when we pass non empty string from action, telerik considers it as error. Here in this blog i had mentioned steps to overcome this error.
Telerik Upload control provides multiple files upload simultaneously sync/async.
 @(Html.Telerik().Upload()
        .Multiple(true)
        .Name("UploadFile")
        .ClientEvents(t => t.OnError("UploadFile.error").OnUpload("UploadFile.Upload"))
        .Async(t => t.AutoUpload(false)
  .Remove("Remove", "UploadFiles")
         .Save("Save", "UploadFiles")))

When we pass message from save(), it throws alert box with message "Error! Upload failed. Unexpected server response - see console." To override it:
1:  Get Object
Get the object of uploading control and override its existing method which generates error message.
var r = $("#UploadFile").data("tUpload");
r._alert = function (ee) { };
$("#UploadFile").data("tUpload", r);

_alert() is the function which generates error message when response from save() is non empty.
2:   Get response text from Save()
As we return status, it will fire UploadFile.error().
UploadFile.error = function (e) {
    UploadFile.filename = e.files[e.files.length - 1].name;
    UploadFile.statusMsg = e.XMLHttpRequest.responseText;
    if (e.XMLHttpRequest.responseText.indexOf("Success") < 0) {
        UploadFile.Status = "error";
    }
    else {
        UploadFile.Status = "success";
    }
};

XMLHttpRequest.responseText is the value of status sent from Save() by which you can distinguish with actual uploading error or the successful status message.

3: Change Classes to get correct output
Here, file is uploaded success fully. Though it shows with red mark as error.

Error File
We need to work on Jquery to get correct output:
Success File
$(".t-file .t-fail").removeClass("t-fail").addClass("t-success");
$(".t-file .t-success").html("uploaded");
$(".t-file .t-success").parent().find('.t-retry').removeClass("t-retry").addClass("t-delete");
$(".t-file .t-success").parent().find(".t-delete").parent().html("<span class='t-icon t-delete'></span>delete”);

4: Override function _removeFileEntry()  to get more functionality
When you click on delete button it will just remove the file list from div, and call Remove() of controller. But if you want to handle some features from Jquery, like remove FileId from list of FileId stored in hidden field, override _removeFileEntry() of telerik uploader as:

var r = $("#UploadFile").data("tUpload");
r._removeFileEntry = function (v) {};
$("#UploadFile").data("tUpload", r);


Thanks,
@VHNG

ASP.net MVC Vs ASP.net Web Form


Software Architects have been involving lot of debates about different approaches and architectures. Some of the examples are ORM Vs Store Procedures, REST Vs SOAP, etc. There is a debate happening inside the Microsoft community about ASP.net web form Vs ASP.net MVC. Many people thinking that ASP.net MVC will be replace webforms at least eventually and others are thinking that ASP.net MVC will not be replace webforms. Will ASP.net MVC replace webforms?. ASP.net MVC is an alternative approach to webforms rather than a replacement. It will not replace webforms and webforms will not replace ASP.NET MVC. The fact is that ASP.NET MVC and webforms will co-exist and that ASP.NET MVC is not a replacement for webforms. If you prefer ASP.net MVC use it and you feel webform is more comfortable, you can use it. . Both approaches are just choices and different approaches and choices are good things. Different choices are available for other platforms especially in the Java platform.
Problems with ASP.net Web Form
What are the problems with webforms? In webforms, Microsoft has tried to make windows form model development for web application development. That model was attracted lot of windows form developers especially VB 6.0 developers. Many of VB 6.0 developers had moved to ASP.net web development without knowing the basics of HTTP and web. For simulating windows form model development experience, webforms introduced event-driven approach and also introduced Viewstate and Postback. The end result is that web forms breaks the stateless nature of the Web. Both Viewstate and Postbacks have been made lot of problems and increased complexity of the web application development. Many web pages having hundreds of KB size of Viewstate that affected the performance of the applications sometime. Developers do not have the control of the rendering HTML of web forms and Server controls that render html with mixed inline style and deprecated tags that does not follows standards. Another problem with Web Forms is the integration of JavaScript frameworks due to the naming conventions of rendered HTML. The page life cycle of the Web Form is too complex and has the tightly coupling between all things in the ASP.net framework and a single class is used both to display output and handles user input. So unit testing is almost an impossible task. Today unit testing is very important in modern software development especially when we following agile methodologies and practices. Since web is a stateless thing, Events, Postbacks and Viewstate are not a good way. Today many ASP.net web form developers are facing different type pf browser compatibility issues when developing public face internet applications
The ASP.net MVC way
The ASP.NET MVC simplifies the complex parts of ASP.net Web Forms without any compromise of the power and flexibility of ASP.NET platform. ASP.net MVC implements Model-View-Controller UI pattern for web application development that lets you allows to develop applications in a loosely couples manner. MVC pattern is separating the application in three parts- Model, View and Controller. A view is responsible for rendering the user interface (UI) of the application and it is nothing more than html templates that filled with application’s data passed by the controller. The Model implements the logic for the application's data and it represents the business objects of the application that using the View for rendering user interface. Controllers are handles and responds to user input and interaction. The web request will be handled by the controller, and the controller will decide which model objects to use and which view objects to render. The MVC model replaces the Web Form events with the controller actions. The main advantages of the MVC models are clear separation of concerns, unit testing facility, and more control over the URLs and HTML. The MVC model does not use Viewstate, Postbacks, Server controls, and server-based forms that enable full control over the application and html rendered by the Views. MVC model is using Representational state transfer (REST) based URLs instead of file-name extensions used by the Web Form model so that we can make search engine optimization (SEO) URLs published by the application.
The below code shows the implementation of MVC application.
ProductsController.cs (Controller)


In this sample, I have used extension methods to the HtmlHelper class to display ordered list of information.
OrderListExtensions.cs

Category.aspx (View)

Advantages of MVC Model
  1. Enable clean separation of concerns (SoC) .
  2. Enable full control over the rendered HTML.
  3. Enable Test Driven Development (TDD) (built with TDD in mind).
  4. SEO and REST friendly URL.
  5. Easy integration with JavaScript frameworks.
  6. Support third-party view engines such as NVelocity, Brail, NHaml.
  7. No ViewState and PostBack events.
  8. Follows the stateless nature of web.
  9. Extensible and Pluggable framework. 
  10. Ideal platform for Web 2.0 applications.
Advantages of Web Form Model
  1. Provides RAD development.
  2. Easy development model for heavy data-driven LOB applications.
  3. Provides rich controls.
  4. Familiar model for windows form developers.
Which is the best approach?
The choice would be vary on different people. If you want more control over the HTML or you want Test Driven Development (TDD), or you care about web standards, accessibility, or you want to build SEO based URLs, you can choose MVC model. If you want rich controls and state oriented event-driven web development, you can choose Web Forms model. If you feel more comfortable with MVC, choose that model and you feel Web Form model is more comfortable, choose that model. Both are just choices. If you start your career with ASP.net Web Forms and do not have full knowledge of Web, it will be very difficult moving to MVC model.
I prefer MVC over Web Forms and I feel that Microsoft is going to a right direction through MVC. Its technical features as well as the open source nature are attracted me a lot.The MVC model allows me full control over the HTML and enables Test Driven Development (TDD). We can easily integrate with jQuery and other JavaScript frameworks with MVC. Using extension methods of C# 3.0, we can make powerful and rich HTML helper methods. I believe that tesatbility, refactoring capability and maintainability are the main factors for a successful project and prefer these factors than RAD capability. The MVC model allows to build highly testable, maintainable loosely coupled applications with good practices such as TDD, Seperation of Concerns (SoC) and Dependency Injection (DI). You MUST use ASP.NET MVC for public face internet applications.

Integrating Electronic Payment Processing into ASP.NET Web Applications


Electronic Payment processing continues to be a common theme for many Web based applications and while the process is getting easier with the market maturing, there's still a maze of choices and options in setting up your payment solutions and get them integrated into existing applications. In this article, I'll give a high level overview of the electronic payment processing by looking at the various players involved in the payment processing operation and some suggestions and options you have on getting hooked up with the right provider. I'll talk about how the process works, what it takes to get started and what it's going to cost. Finally I'll take you through an application that integrates payment processing and show a class you can use to integrate a few of the common Gateway services into existing applications.

The process of taking electronic payments from customers and getting the money deposited into your own accounts is a winding one, with several levels of providers being part of the transaction process. Figure 1 shows an overview of the process and the entities involved.

Figure 1: The 10,000 foot view of Credit Card Processing using one of the big Gateway providers.

Your Web Application
The process starts with your Web application. I'll be approaching this topic from the perspective of
a small business that integrates payment processing into an existing Shopping Cart solution, so the Web application is responsible for collecting the customer's contact and credit card information. In order to process a Credit Card you'll need to capture some basic information which includes:

  • Name
  • Address
  • Email Address
  • Phone Number
  • Order Amount
  • Credit Card Number
  • Expiration Date
  • Card Verification Code (optional)

Gateway Processor




Once you have collected this information, you'll need to send the information collected to a Gateway provider that can process the credit card on your behalf. Gateway providers provide, as the name suggests, the Internet Gateway API that your application can communicate with. The APIs are generally HTTP or TCP/IP based and provide a relatively simple interface that your application can communicate with.

A few common Gateway providers are Authorize.NET, Verisign (PayFlow Pro), LinkPoint. There are many other Gateway service providers but they all perform the same basic functionality for providing a standard interface for your application to process a credit card. The Gateway provider essentially provides an API that your application can talk to. The nature of the API can vary with some providers using pure HTTP POST based interfaces and others using their own proprietary TCP/IP interfaces that you can interfaces with through some published SDK. We'll talk more about how some of the provider interfaces work later in the article.

In theory Gateway providers are optional. You could in theory talk directly to the underlying processing networks, but in order to gain access to these networks you need to be certified and you need to be able to communicate with the various different processing networks that handle the actual payment processing. So unless you are a bank or large vendor that deals with a high volume of transaction this is not going to be an option. For most of us a Gateway provider is not optional.

Front End Network
The various gateway providers communicate with the front end Credit Card Processing networks that handle the actual payment processing by passing inbound transactions to the issuing bank. You can think of the front end network sort of as the gateway for the gateway providers. There a number of different providers that service this front end processing network with names such as PaymentTec, FirstData, Nova, Global Payment. The Gateway Providers interface with each of these networks that are supported. The front end network in turn interfaces with each of the issuing banks.

The issuing banks then are ultimately responsible for authorizing the credit card transaction by comparing the inbound data and reserving funds (doing an 'AUTH' only at this time). The bank actually doesn't do a whole lot of checking of the data – it merely checks to see if there are funds available and passes back an authorization code as well as the customer information available to the bank back to the front end network.

Back to the Gateway and the Web Application
The front end passes the result back to the Gateway processor which can now examine the data returned for the bank. If the result was not approved and there are not enough funds the transaction is declined immediately. If funds were approved additional checks are performed for fraud detection. The gateway performs things like AVS (Address Verification Services) validation against the contact information provided and checks the CVS code (the 3 or 4 digit code on the back or front of the card) if provided, which if it doesn't match  can cause the transaction to be Declined. Note that both AVS and CVS verification is user definable at the gateway level, typically by the store owner, so how AVS and CVS are handled may vary based on your options.

If AVS and CVS validation succeeded the order is approved and the Gateway sends back an confirmation message to the client application. Most Gateways support 3 different main response codes which are APPROVED, DECLINED, ERROR (or FAILED) along with additional information. For example Authorize.NET returns a comma delimited string that includes the authorization code, the input data of address and order amounts. The exact information returned from the providers varies per Gateway.

The key pieces of information that all providers return are:

  • Response Code
  • Message (a semi descriptive message of failure)
  • Authorization Code (if successful)
  • Transaction ID (Gateway Transaction Id you can map to your orders)

Most gateways also echo back the information that you sent to the gateway to ensure that if data was sent from one application to another that you can verify the transaction amounts.

Settling transactions
At this point the transaction has either been approved or declined. If approved the transaction is only Authorized with the issuing bank, which means that funds are put on hold only for the moment. Funds are not actually transferred and taken out of the user's account until the transaction batch is settled.

Gateways collect approved transactions into batches which are processed at regular intervals that you can specify as part of the Gateway interface. When batches are settles the Gateway communicates with the back end networks to cause the funds to be put on hold, but removed from the customer's account. At this point the money is being moved into the merchant bank account and held in escrow for a period of time – IOW, it's not immediately transferred into your checking account.

Merchant Bank – the 'Escrow' Account
The Merchant bank acts as the intermediary between your bank account the processing networks that retrieve the funds. The funds retrieved are held – typically for 2 days and then deposited into your bank account. The merchant bank also substracts the merchant percentage from each transaction, assigning the per transaction charges for the credit card processing.

The merchant provider also acts as an intermediary between you and the issuing banks should there be a dispute for payments. So if there's a fraudulent transaction or a charge back you'll hear from the Merchant bank that provides you with the details and to whom you have to send any documentation. A good merchant bank can also deflect frivolous charge back claims before they ever reach you.


AMEX, Discover, Diners, JCB – special cases
These card providers actually act as both the Issuing bank as well as the merchant provider – they essentially bypass the Merchant Service Provider when it comes for handling the authorized funds. Rather than holding funds with the Merchant Service Provider, AMEX etc. deposit directly into your merchant account after holding funds for a short period. In essence these companies are the merchant provider for the transactions. Note though that transactions still run through your merchant bank which will charge you per transaction fees for the AMEX etc. transactions as well as the Visa and MasterCard transactions.

Lest you think that this is less complicated, realize that all of the independent providers tend to charge considerably higher merchant percentages. Also, even though the merchant service provider isn't used for escrow, billing or dispute resolution cases, these providers still need to use the processing networks and gain access to them through the Merchant Service provider. So AMEX, Discover, Diner etc. all have their per transaction charges billed through the Merchant statement. Even if you were only to take AMEX you still need a merchant provider.

Your Bank Account
Finally at the end of this long journey the money from your customer – minus the merchant percentage will end up in your bank account.

Paying the man

As you might expect, most of the players in Figure 1 want to get paid in some way, so fees are involved at various levels. If you're starting out from scratch your first mission is to find a merchant provider.

Merchant Service Provider
The key to getting started usually is a merchant account which you can get from a variety of sources. The merchant account is where most of the recurring fees occur and this is where you want to make sure you're getting a good deal. Typical small business merchant rates range from 2.0-2.5% for Visa/MasterCard and 3.5-4% for AMEX, Discover etc. In addition you'll typically pay some sort of monthly statement fee, plus a per transaction charge (from 0.15 - 0.40 per transaction) for every charge and credit that is made. The Transaction charge is usually done as a minimum fee with a set number of transactions included. On my account it's a $25 minimum with 80 or so free transactions for example.

Also keep in mind that although Merchant providers quote rates like 2.2 percent, the reality is, especially for business transactions, that you rarely get these rates processed. Business cards, International cards, or cards with rewards points bump the rate in most cases into the mid 3% range. Checking my most recent statement for example, I see that my average transaction for MasterCard and Visa was 3.40% even though my discount rate is 2.25%. The base rate is important though because these 'special card' percentages are piled ontop of it.

Gateway Service
Next you'll need to find a gateway service that your merchant provider supports. This is a lot easier today than it used be in the past where typically a merchant provider was married to one specific Gateway service. Nowadays most merchant providers give you a choice Gateways you can use.

Gateway Services provide the Internet facing interface that your application can talk to. Fees here vary significantly with some of the high end, super high volume providers being fairly expensive and the mainstream providers being relatively cheap or even free in a package.

Rates for Gateways are paid for monthly gateway fee, which can range from free to $15 (Authorize.NET official rate) to the more expensive Verisign PayFlow Pro which charges $60 for monthly fees. In addition to the gateway fee the gateways also charge small per transaction fees for each transaction run against the gateway fail or not. These are typically 5 cents or so, but they can add up. And remember you're paying for transactions whether they go through or not and for the closing batches at the end of the day for each network.

There are differences in providers and the services they offer. For example, Authorize.NET works great, but they don't support debit cards. PayFlow Pro does as does LinkPoint. All the providers also claim better performance than other, but the reality is that today performance of any of the services I've worked with recently is under 5 seconds with some as fast as 1 second response times, so this shouldn't be a big issue.

How do I get my Merchant Account and Gateway?
There are a number of different ways to find providers. The easiest way today is probably to find a merchant account reseller that sells packages of both Gateway Service and Merchant Service Provider, since this is a one stop solution.  In this scenario you end up signing up in one place, filling out one set of paperwork as opposed to separately signing up with a merchant banks and gateway service.

Resellers can be found on the Internet and a good way to start if you have no idea where to look is by going to the Gateway providers and check several of their preferred services.

I'm very happy with the service and rates I get with a reseller called MerchantPlus (using Synergy for Merchant Bank and Authorize.NET for Gateway) which is the current setup I'm running. But don't take my word for it – be sure to do your research and check and compare rates and fees carefully. I can't make any other recommendations at the moment since it's been a while since I've looked provider (and I have no need <s>), but if you search around on the Web you'll find a number of good discussion boards that talk about various providers and the quality and rates of their services and user experiences. It's worth doing a little research.

Other options include checking with your existing bank which may provide merchant services, although it's probably with rates that are higher than what you can find yourself. But it never hurts to ask as pricing can vary. You can also check out large resellers like CostCo which have merchant programs that include Internet packages that are reasonable.

The Merchant provider you choose to some degree will determine which processing network is used such as Nova, PaymentTech, FirstData etc. but other than the Gateway provider you use this shouldn't make much of a difference.

Picking a Gateway Provider

These days when you sign up with a Merchant provider you likely get a choice of gateways that you can use with it. If you're building your own application, you will have to interface with these gateways. Later on in this article I'll present a class that handles a number of common gateways using a common interface.

Let's review some of the common Gateway providers:

Authorize.NET
Authorize.NET Gateway is super easy to integrate into existing applications. It uses a plain HTTP POST interface to communicate with the server, so there's no setup and configuration – you merely need an HTTP client that can post the data. Authorize.NET returns data over HTTP in a simple comma delimited format that's easy to access within just about any application.

Authorize.NET is fast and stable – I've been using them for 4 years now without any problems during that entire time. Response time's somewhere between 2-5 seconds per transaction which is plenty fast. Authorize.NET doesn't support debit cards so if you need to process those you'll need to look elsewhere.

Price: $7.95 a month, 0.05 per transaction (first 250 free), $175 cancellation fee
(prices are through MerchantPlus reseller)

Verisign PayFlow Pro
Versign's PayFlowPro uses a COM or C++ based API that works with custom client side certificate. Installation is a little more involved in that you need to install the certificate on a specific location on the Web Server. Versign has a COM based API and has published a .NET front end for the COM API (basically a COM Interop assembly). I've not used Verisign other than in test modes, but I work with several customers who use it and are happy with performance and stability. Verisign claims high stability and guarantees uptime (not sure if I buy that though) and they support a number of non-credit card payment types like debit cards, direct deposit and electronic checks.

Signing up with PayFlowPro can be done entirely on the Verisign site – they can hook you up with the gateway and merchant account. Many merchants also allow you to use PayFlowPro with their accounts. It's one of the more popular low to midrange solutions.

Direct Price: $60 a month, 0.10 per transaction(1000 free), $249 setup
(note: there are resellers that can get this pricing down a little)

LinkPoint API
LinkPoint tends to be a Gateway used for many high risk sites. The most common match is with CardServices account which also are frequently of the high risk type. Linkpoint is a frequent choice required if you get a merchant account through a local bank when you let slip that you are doing an Internet business. LinkPoint/CardServices will tend to take on just about any customer, but the rates tend to be higher and the amount of declined transaction due to fraud checks can be much higher on this network than any other.

LinkPoint provides both a COM and .NET APIs and I've used both of them. Both basically work on the same message part model where you set various objects (Order,Billing,Options etc.) and fill each with the order data.

The .NET API is using some proprietary SLL driver you have to download and install in a specific location. For both API's you also must install a certificate on your server. The API itself passes messages via proto-XML – the documents passed are not actually parsable XML, but an XML fragment. Everything about this API made me cringe and think – who designed this???

Once hooked up and installed though LinkPoint works well and fast, but as mentioned watch for higher numbers of declined orders.

I would avoid LinkPoint if you have a choice. As mentioned many traditional banks resell LinkPoint and CardServices and if you go that route you may not have a choice.

Many more providers
There are many more providers, but the above are common ones that I've worked with. A few others include AccessPoint, BluePay, PaymentNet, iTransact to name a few of the smaller ones. There are also providers that cater to the high end for the mega online stores with millions of dollars in revenue a month. Cybersource is one of the providers in that end of the market and these providers provide special merchant deals that cater to these higher end customers.

In the old days some of these high end providers were the only ones able to handle the high volume vendors were throwing at them, but times have changed and technology has improved. All the gateways I've worked with now return transaction results in under 5 seconds typically and generally don't balk at high volume. The main difference is that large vendors have enough dollar volume going through the gateways and merchant providers to work special deals for better rates.

For anything but the high end of e-Commerce applications the solutions mentioned here should work just fine.













Web Site Integration

OK, so you've picked your merchant provider and gateway – the next step is to integrate the payment processing into your Web Application. In order to do this the first step is to create the basic credit card processing routines that can interface your code with the Gateway of your choice. The focus of the following discussion is describe how to create a somewhat generic credit card processing class hierarchy that can work with various providers, and then describe how to use these classes in a custom Web Store application.

Implementing a generic set of Credit Card Classes

Assuming the rest of your site is in place the first thing you need to figure out is how to actually process the credit cards you receive. This means you'll need to write the code that interfaces with the Gateway you selected. You can go download the providers API reference and start figuring out how to use the particular gateway interface from scratch, which with most providers is not terribly difficult but even though the process is often fairly straight forward, integration tends to be time consuming due to the testing and the interaction with Gateway support to get all the information (account ids, passwords, sometimes certificates, switching accounts from test to live mode etc.) you need in order to start processing transactions.

I believe it's a good idea to use a more generic framework that is more flexible and allows to potentially switch to a different provider in the future. Over the years, I've gone through 6 different merchant providers and with each switch I ended up on a new kind of gateway. Rather than writing application level code to integrate with each of the gateways, I long ago created a generic Credit Card processing class that provides a base interface for credit card processing. The base class provides the core properties that every credit card gateway requires as well as few helper methods that validate field input, deal with formatting properties such as card numbers and card expiration dates, deal with MOD10 validation, switching into test mode, logging and so on. The provider specific implementation then handles the actual credit card processing with the Gateway.

The result is a hierarchy of credit card processing classes which are provided as part of this article. The classes include support for the following gateway services:

  • Authorize.NET
  • Verisign PayFlowPro
  • LinkPoint
  • AccessPoint
  • BluePay

Figure 2: The hierarchy of credit card processing classes presented here.

These are providers I have worked with over the years and while this list is not extensive, it contains some of the most popular Gateways and it's relatively straight forward to add other providers using the same processing logic.

This class hierarchy starts out with an abstract base class called ccProcessing. The ccProcessing class provides a core property interface that provides the common interface that application code writes to. So regardless of whether you're using Authorize.NET or BluePay, you're always setting the MerchantID and MerchantPassword properties even though the providers may call these different things (for example, BluePay calls it the AccountId and SecretKey).You always fill in customer billing information, order amounts and credit card number and expiration and this class provides a common baseline to assign the values before processing.

Here's the interface for the abstract ccProcessing class:

Member
Description
Returns a string for a single AVS code value Supported codes: ANSUWXYZER_
public string AvsCodeToString( string AvsCode );
Determines whether given string passes standard Mod10 check.
public static bool Mod10Check( string StringToValidate );
Base ValidateCard method that provides the core CreditCard checking. Should always be called at the beginning of the subclassed overridden method.
public virtual bool ValidateCard();
Billing Street Address.
Authorization Code returned for Approved transactions from the gateway
The AVS Result code from the gateway if available
Used for Linkpoint only. Specifies the path to the certificate file
Billing City
Order Comment. Usually this comment shows up on the CC bill.
Billing Company
Two letter Country Id - US, DE, CH etc.
Full expiration date in the format 01/2003
Credit Card Expiration Month as a string (2 digits ie. 08)
Credit Card Expiration Year as a 4 or 2 digit string
The credit card number. Number can contain spaces and other markup characters which are stripped for processing later.
Email address
Error flag set after a call to ValidateCard if an error occurs.
Error message if error flag is set or negative result is returned. Generally this value will contain the value of this.ValidatedResult for processor failures or more general API/HTTP failure messages.
First Name of customer's name on the card. Can be used in lieu of Name property. If Firstname and Lastname are used they get combined into a name IF Name is blank.
Reference to an wwHttp object. You can preseed this object after instantiation to allow setting custom HTTP settings prior to calling ValidateCard().
The link to hit on the server. Depending on the interface this can be a URL or domainname or domainname:Port combination.
Last Name of customer's name on the card. Can be used in lieu of Name property. If Firstname and Lastname are used they get combined into a name IF Name is blank.
Optional path to the log file used to write out request results. If this filename is blank no logging occurs. The filename specified here needs to be a fully qualified operating system path and the application has to be able to write to this path.
The merchant Id or store name or other mechanism used to identify your account.
The merchant password for your merchant account. Not used in most cases.
First name and last name on the card
The amount of the order.
The Order Id as a string. This is mainly for reference but should be unique.
Billing Phone Number
Determines what type of transaction is being processed (Sale, Credit, PreAuth)
This is a string that contains the format that's sent to the processor. Not used with all providers, but this property can be used for debugging and seeing what exactly gets sent to the server.
The raw response from the Credit Card Processor Server.
Referring Url used with certain providers
The 3 or 4 letter digit that is on the back of the card
Billing State (2 letter code or empty for foreign)
The amount of Tax for this transaction
Timeout in seconds for the connection against the remote processor
The Transaction ID returned from the server. Use to match transactions against the gateway for reporting.
Determines whether a Mod10Check is performed before sending the credit card to the processor. Turn this off for testing so you can at least get to the provider.
Optional flag that determines whether to send a test transaction Not supported for AccessPoint
The parsed error message from the server if result is not APPROVED This message generally is a string regarding the failure like 'Invalid Card' 'AVS Error' etc. This info may or may not be appropriate for your customers to see - that's up to you.
The parsed short form response. APPROVED, DECLINED, FAILED, FRAUD
Postal or Zip code

As you can see the main portion of this class provides properties for most of the possible values that you need to describe a credit card transaction. There's billing information for the customer, the Credit Card information including the Card Number, Card Expiration and CVS SecurityCode as well as the order amount.

There are processing specific properties such as the HttpLink (used with HTTP based providers like Authorize.NET, BluePay and AccessPoint). There's MerchantId and MerchantPassword that identifies the merchange.

Then there are Response values such as the ValidatedResult (APPROVED, DECLINED, FAILED, FRAUD), ValidatedMessage which returns a descriptive message returned from the provider, RawProcessorResult, which returns the raw data returned if available. There's also AuthorizationCode and TransactionId which return these values from transactions.

The base class also supports logging of every request to a log file and you can easily Test mode on and off (for those providers that support it through the gateway API) for a transaction.

There are also a couple of helper methods that can do Mod10 checking and convert a single AVS code to a string value. AVS codes are returned for failed transactions and you can use the conversion to potentially provide more information to your customers.

The worker method that does all the work is ValidateCard(). Since this class is abstract the default ValidateCard() method doesn't do anything useful (it does have logic though so make sure to call the base method in your implementation) – this method needs to be overridden by the specific processor implementation classes.

Customizations do the real work

Logic says there should be a common Gateway API for all providers, but the reality is that most of the APIs work very differently. Even those that are operationally similar – those that use pure HTTP POST interfaces like Authorize.NET, AccessPoint and BluePay – use completely different POST variables and formats. So, each of these classes essentially features a complete custom implementation to talk to the specific Gateway provider.

While the base class interface of the various processing classes is identical, most of the classes require slightly different start up configuration. This means if you plan on supporting multiple credit card providers in a single application (such as a more generic shopping cart) there's a little bit of conditional code required for each of the providers.

The following C# code is an example of how all of the supported credit card providers are integrated into my Invoice business object, which gives you a pretty good idea how the class can be used at the Application level:

/// <summary>
/// Processes credit cards for the provider set in App.Configuration.CCMerchant
/// Works with the WebStoreConfig settings for setting to configure the provider
/// settings.
/// </summary>
/// <remarks>The Invoice is not saved at this point.
/// Make sure to call Save() after this operation.</remarks>
/// <returns></returns>
public bool ProcessCreditCard()
{
    bool Result = false;

    wws_invoiceRow Inv = this.Entity;
    wws_customersRow Cust = this.Customer.Entity;

    ccProcessing CC = null;
    ccProcessors CCType = App.Configuration.CCProcessor;

    try
    {
        if (CCType == ccProcessors.AccessPoint)
        {
            CC = new ccAccessPoint();
        }
        else if (CCType == ccProcessors.AuthorizeNet)
        {
            CC = new ccAuthorizeNet();
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
        }
        else if (CCType == ccProcessors.PayFlowPro)
        {
            CC = new ccPayFlowPro();
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
        }
        else if (CCType == ccProcessors.LinkPoint)
        {
            CC = new ccLinkPoint();
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
            CC.CertificatePath = App.Configuration.CCCertificatePath;  
            // ie. "d:\app\MyCert.pem"
        }
        else if (CCType == ccProcessors.PayPalWebPaymentsPro)
        {
            CC = new ccPayPalWebPaymentsPro();
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
            ((ccPayPalWebPaymentsPro)CC).PrivateKeyPassword = "";
        }
        else if (CCType == ccProcessors.BluePay)
        {
            CC = new ccBluePay();
            CC.MerchantId = App.Configuration.CCMerchantId;
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
        }

        CC.MerchantId = App.Configuration.CCMerchantId;

        //CC.UseTestTransaction = true;

        // *** Tell whether we do SALE or Pre-Auth
        CC.ProcessType = App.Configuration.CCProcessType;

        // *** Disable this for testing to get provider response
        CC.UseMod10Check = true;

        CC.Timeout = App.Configuration.CCConnectionTimeout;  // In Seconds
        CC.HttpLink = App.Configuration.CCHostUrl;         

        CC.LogFile = App.Configuration.CCLogFile;
        CC.ReferingUrl = App.Configuration.CCReferingOrderUrl;

        // *** Name can be provided as a single string or as firstname and lastname
        //CC.Name = Cust.Firstname.TrimEnd() + " " + Cust.Lastname.TrimEnd();
        CC.Firstname = Cust.Firstname.TrimEnd();
        CC.Lastname = Cust.Lastname.TrimEnd();

        CC.Company = Cust.Company.TrimEnd();
        CC.Address = Cust.Address.TrimEnd();
        CC.State = Cust.State.TrimEnd();
        CC.City = Cust.City.TrimEnd();
        CC.Zip = Cust.Zip.TrimEnd();
        CC.Country = Cust.Countryid.TrimEnd();  // 2 Character Country ID
        CC.Phone = Cust.Phone.TrimEnd();
        CC.Email = Cust.Email.TrimEnd();

        CC.OrderAmount = Inv.Invtotal;
        CC.TaxAmount = Inv.Tax;                             // Optional
        CC.CreditCardNumber = Inv.Cc.TrimEnd();
        CC.CreditCardExpiration = Inv.Ccexp.TrimEnd();

        CC.SecurityCode = Inv.Ccsecurity.TrimEnd();

        // *** Make this Unique
        CC.OrderId = Inv.Invno.TrimEnd() + "_" + DateTime.Now.ToString();
        CC.Comment = App.Configuration.CompanyName + " Order # " +
                                                     Inv.Invno.TrimEnd();
        // *** Result returned as true or false
        Result = CC.ValidateCard();

        // *** Pick up the Validated result values from the class
        Inv.Ccresult = CC.ValidatedResult;
        if (!Result)
        {
            this.ErrorMessage = CC.ValidatedMessage;
            Inv.Ccerror = this.ErrorMessage;
        }

        // *** Always write out the raw response
        if (string.NullOrEmpty(CC.RawProcessorResult))
            Inv.Ccresultx = CC.ValidatedMessage;
        else
            Inv.Ccresultx = CC.RawProcessorResult;
    }
    catch (Exception ex)
    {
        this.SetError(ex.Message);
        Inv.Ccresult = "FAILED";
        Inv.Ccresultx = "Processing Error: " + ex.Message;
        Inv.Ccerror = "Processing Error: " + ex.Message;
        return false;
    }

    return Result;
}

This class method is designed to work with multiple credit card providers that are supported by the store. Using this routine as a front end I can use basically any of the credit card providers that are supported by the ccProcessing subclasses simply by setting a switch in the web.config file (or via an admin interface).

The code starts out instantiating each of the individual classes and setting a few provider specific properties on it. You notice that some require a certificate, others require only a merchant id, others require password and so on. Aside from that though all the various providers use identical code.

The code that follows assigns the application specific data to the processing object – in this case the data comes from Invoice and Customer objects and – for the system configuration settings – from an App.Configuration object which provides application configuration settings of various kinds with the ultimate source being in the web.config file.

The call to ValidateCard() is made which goes out and uses the provider specific code to process the credit card. The method returns true or false. If true the order was approved otherwise it was declined or failed.

The code here captures the ValidatedResult (APPROVED, DECLINED, FAILED or FRAUD) as well as the ValidatedMessage and the RawProcessorResult which in turn are stored in the invoice object. Storing the RawProcessorResult may seem like overkill but it provides a good record in case there are problem in the future such as a chargeback or fraudulent transaction. I highly recommend storing the raw response data if available by the provider.

The response value from the ValidateCard() method and the parsed result values make it easy to quickly figure out what happened during processing and take appropriate action in your application. All the parsing of the card processor response is taken care of for you in the various processor specific classes, so it's short work to pick up the result values.

In this case the results are simply stored in the business object and saved. If a failure occurs the ValidatedResult error message is displayed back to the user in the Web interface.

Notice that this code is completely provider agnostic and keeps all the messy domain knowledge about the credit card processing out of the business object code. The code is relatively short and clean and easy to read and modify and generic enough to work with various gateways at the flick of a switch. Sweet.

Gateway Provider Implementations

So now let's take a look at the individual provider implementations. As you might have guessed each one of the provider classes essentially implements the ValidateCard() method and maybe a few of the stock property settings in the constructor. For example, the various HTTP gateway classes override the HttpLink property to point at the default gateway Url so that you don't have to set it. Some providers like PayFlow also add a couple of additional properties such as explicit proxy settings that are published by their API.

Let's take a look at the various classes and what it takes to set up a couple of the gateway APIs.

Authorize.NET

Authorize.NET has become the most popular Gateway provider and having written implementation code for various gateways I can see why. Authorize.NET is easy to work with and doesn't require any external configuration. Even if you were to start from scratch building an interface you could probably do it in very short order. Authorize.NET uses plain HTTP POST operations against its gateway server.

The ccAuthorizeNet class provides Credit Card processing against the Authorize.Net Gateway. It uses plain POST operations against the Web Server so other than providing URL and login information there are no further setup requirements.

What you need:
  • Authorize.NET Gateway URL
  • Authorize.NET Merchant Login ID and Password
  • Referring URL
  • No further installation required - uses plain POST interface to server gateway
Here is the ccAuthorizeNet implementation:

/// <summary>
/// This class provides Credit Card processing against
/// the Authorize.Net Gateway.
/// </summary>
public class ccAuthorizeNet : ccProcessing
{

      public ccAuthorizeNet()
      {
            this.HttpLink  = "https://secure.authorize.net/gateway/transact.dll";
      }

      /// <summary>
      /// Validates the actual card against Authorize.Net Gateway using the HTTP
      /// interface.
      /// <seealso>Class ccAuthorizeNet</seealso>
      /// </summary>
      /// <param name=""></param>
      /// <returns>Boolean</returns>
      public override bool ValidateCard()
      {
            if (!base.ValidateCard() )
                  return false;

            if (this.Http == null)
            {
                  this.Http = new wwHttp();
                  this.Http.Timeout = this.Timeout;
            }

            string CardNo = Regex.Replace(this.CreditCardNumber,@"[ -/._#]","");

            this.Http.AddPostKey("x_version","3.1");
            this.Http.AddPostKey("x_method","CC");
            this.Http.AddPostKey("x_delim_data","True");
            this.Http.AddPostKey("x_password",this.MerchantPassword);
            this.Http.AddPostKey("x_login",this.MerchantId);

            if (this.UseTestTransaction)
                  this.Http.AddPostKey("x_test_request","True");
           

            if (this.OrderAmount >= 0)
            {
                  if (this.ProcessType == ccProcessTypes.Sale)
                        this.Http.AddPostKey("x_type","AUTH_CAPTURE");
                  else if (this.ProcessType == ccProcessTypes.PreAuth)
                        this.Http.AddPostKey("x_type","AUTH_ONLY");
                  else if (this.ProcessType == ccProcessTypes.Credit )
                        this.Http.AddPostKey("x_type","CREDIT");

                  this.Http.AddPostKey("x_amount",this.OrderAmount.ToString(
                                    CultureInfo.InvariantCulture.NumberFormat));
            }
            else
            {
                  this.Http.AddPostKey("x_type","CREDIT");
                  this.Http.AddPostKey("x_amount",((int) (-1 * this.OrderAmount)).ToString(CultureInfo.InvariantCulture.NumberFormat));
            }

            if (this.TaxAmount > 0.00M)
                  this.Http.AddPostKey("x_tax",
this.TaxAmount.ToString(CultureInfo.InvariantCulture.NumberFormat));


            this.Http.AddPostKey("x_card_num",CardNo);
            this.Http.AddPostKey("x_exp_date",this.CreditCardExpirationMonth.ToString() + "-" +
                                                this.CreditCardExpirationYear.ToString() );

            if (this.SecurityCode.Trim() != "")
                  this.Http.AddPostKey("x_card_code",this.SecurityCode.Trim());

           
            this.Http.AddPostKey("x_first_name",this.Firstname);
            this.Http.AddPostKey("x_last_name",this.Lastname);
            this.Http.AddPostKey("x_company",this.Company);
            this.Http.AddPostKey("x_address",this.Address);
            this.Http.AddPostKey("x_city",this.City);
            this.Http.AddPostKey("x_state",this.State);
            this.Http.AddPostKey("x_zip",this.Zip);
            this.Http.AddPostKey("x_country",this.Country);
           
            if (this.Phone.Trim() != "")
                  this.Http.AddPostKey("x_phone",this.Phone);

            this.Http.AddPostKey("x_email",this.Email);

            this.Http.AddPostKey("x_invoice_num",this.OrderId);
            this.Http.AddPostKey("x_description",this.Comment);

            this.Http.CreateWebRequestObject(this.HttpLink);
            this.Http.WebRequest.Referer=this.ReferringUrl;

            this.RawProcessorResult = this.Http.GetUrl(this.HttpLink);

            if (this.Http.Error)
            {
                  this.ValidatedResult = "FAILED";
                  this.ValidatedMessage = this.Http.ErrorMessage;
                  this.SetError(this.Http.ErrorMessage);
                  this.LogTransaction();
                  return false;
            }

            string[] Result = this.RawProcessorResult.Split(new char[1]  {','} );
            if (Result == null)
            {
                  this.ValidatedResult = "FAILED";
                  this.ValidatedMessage = "Invalid response received from Merchant Server";
                  this.SetError(this.ValidatedMessage);
                  this.LogTransaction();
                  return false;
            }

            // *** REMEMBER: Result Codes are in 0 based array!
      this.TransactionId = Result[6];
            this.AvsResultCode = Result[5];

            if (Result[0] == "3"  )  // Error - Processor communications usually
            {
            // *** Consider an invalid Card a DECLINE
            // *** so we can send back to the customer for display
            if (Result[3].IndexOf("credit card number is invalid") > -1)
                this.ValidatedResult = "DECLINED";
            else
                this.ValidatedResult = "FAILED";   

                  this.ValidatedMessage = Result[3];
                  this.SetError(this.ValidatedMessage);
            }
        if (Result[0] == "2" || Result[0] == "4"// Declined
        {
            this.ValidatedResult = "DECLINED";
            this.ValidatedMessage = Result[3];
            if (this.ValidatedMessage == "")
                this.ValidatedMessage = this.RawProcessorResult;
            this.SetError(this.ValidatedMessage);
        }
        else
        {
            this.ValidatedResult = "APPROVED";

            // *** Make the RawProcessorResult more readable for client application
            this.ValidatedMessage = Result[3];
            this.AuthorizationCode = Result[4];
            this.SetError(null);
        }

            this.LogTransaction();

            return !this.Error;
      }
     
}

Note, Authorize.NET's gateway API has become so popular that various smaller providers now offer Authorize.NET compatible gateways. For example, MerchantPlus offers its NaviGate gateway that uses the same Authorize.NET POST interface. Other smaller gateway providers are starting to do the same.

The class above uses a custom wwHTTP class that's a thin wrapper around the .NET WebRequest class. It's provided as part of the sample downloads for this article.

Verisign PayFlow Pro

Verisign uses a custom API that is based  that is available in COM and .NET versions. The .NET version is merely a COM interop wrapper around the COM API, so it's a bit bulky to install as you have to register both the COM object and the interop assembly. In fact I found it easier to bypass the .NET API altogether and directly call the COM API to avoid the Interop assembly which really didn't provide any special features.

The ccPayFlow class processes credit cards against Verisign PayFlowPro gateway service. This service is set up to work with the PayFlow Pro COM object which must be installed and configured properly on the machine to process credit cards. To avoid use of the Interop assembly, the class uses Late Binding with Reflection to invoke the COM API which is merely a single method call.

To configure PayFlow Pro follow these steps: Download the PayFlow Pro SDK Version 3.0 from the Verisign Web Site. You can download a free trial from here:


To install the SDK unzip the file into a directory. The following instructions are basic instructions for installing the PayFlow SDK itself - if you run into problems with this please check the SDK documentation.
The implementation used with the Web Store uses the COM implementation of PayFlow so you will need to register the COM component. To do so:
  • Find the Win32\Libs directory in the SDK
  • Copy the pfPro.dll file into the Windows\System32 directory
  • Find the Win32\COM in the SDK
  • Run PFProCOMSetup.exe in the COM\ dir to install and register the Payflow Pro COM client
  • Find and make a note of the Win32\Certs directory
  • Create an Environment Variable called PFPRO_CERT_PATH and point it at this path
    • To do this open Control Panel | System
    • Go to the Advanced Tab
    • Click on Environment Variables
    • Select System Variables
    • Create a new variable PFPRO_CERT_PATH
    • Set the value to the path of the Cert directory

       
  • For ASP.Net operation the PFPRO_CERT_PATH environment variable is not available to the NETWORK SERVICE/ASPNET account by default and you have to manually copy the CERTS directory into the operating directory of the Web Server (or rather the IIS worker process). This directory is typically:
<Windows Path>/System32/inetsrv
Copy the SDK's entire Cert directory into this path so you have:
<Windows Path>/System32/inetsrv/cert/
with the content of the certificate file.
If you've performed all these steps the PayFlow SDK should be up and running.
In addition to the steps above you'll also need PayFlow UserId and Password which should be assigned to MerchantId and MerchantPassword respectively.
Here's the implementation of the PayFlowPro class:
public class ccPayFlowPro : ccProcessing
{
    public int HostPort
    {
        get { return _HostPort; }
        set { _HostPort = value; }
    }
    private int _HostPort = 443;


    public string ProxyAddress
    {
        get { return _ProxyAddress; }
        set { _ProxyAddress = value; }
    }
    private string _ProxyAddress = "";

   
    public int ProxyPort
    {
        get { return _ProxyPort; }
        set { _ProxyPort = value; }
    }
    private int _ProxyPort = 0;


    public string ProxyUsername
    {
        get { return _ProxyUsername; }
        set { _ProxyUsername = value; }
    }
    private string _ProxyUsername = "";

    public string ProxyPassword
    {
        get { return _ProxyPassword; }
        set { _ProxyPassword = value; }
    }
    private string _ProxyPassword = "";

      /// <summary>
      /// Sign up partner ID. Required only if you signed up through
      /// a third party.
      /// </summary>
    public string SignupPartner
    {
        get { return _SignupPartner; }
        set { _SignupPartner = value; }
    }
    private string _SignupPartner = "Verisign";

      /// <summary>
      /// Overridden consistency with API names.
    /// maps to MerchantId
      /// </summary>
    public string UserId
    {
        get { return _UserId; }
        set { _UserId = value; }
    }
    private string _UserId = "";

    /// <summary>
    /// Internal string value used to hold the values sent to the server
    /// </summary>
    string Parameters = "";

    /// <summary>
      /// Validates the credit card. Supported transactions include only Sale or Credit.
      /// Credits should have a negative sales amount.
      /// </summary>
      /// <returns></returns>
      public override bool ValidateCard()
      {
            if (!base.ValidateCard())
                  return false;
           
            this.Error = false;
            this.ErrorMessage = "";

            // *** Counter that holds our parameter string to send
            this.Parameters = "";

            // *** Sale and Credit Supported
            decimal TOrderAmount = this.OrderAmount;
            if (this.OrderAmount < 0.00M)
            {
                  this.Parameters = "TRXTYPE=C";
                  TOrderAmount = this.OrderAmount * -1.0M;
            }
            else
                  this.Parameters = "TRXTYPE=S";

            string CardNo = Regex.Replace(this.CreditCardNumber,@"[ -/._#]","");
           
            string TUserId = this.UserId;

            if (TUserId == "")
                  TUserId = this.MerchantId;

            string ExpDate = string.Format("{0:##}",this.CreditCardExpirationMonth) ;
            ExpDate +=  this.CreditCardExpirationYear;

            this.Parameters += "&TENDER=C" +
                                "&ACCT=" + CardNo +
                                      "&VENDOR=" + this.MerchantId +
                                      "&USER=" + TUserId +
                                      "&PWD=" + this.MerchantPassword +
                                      "&PARTNER=" + this.SignupPartner +
                                      "&AMT=" + TOrderAmount.ToString(CultureInfo.InvariantCulture.NumberFormat) +
                                      "&EXPDATE=" + ExpDate +
                                      "&STREET=" + this.Address +
                                      "&CITY=" + this.City +
                                      "&STATE=" + this.State +
                                      "&ZIP=" + this.Zip +
                                      "&EMAIL=" + this.Email +
                                      "&COMMENT1=" + this.Comment;

           
            if (this.TaxAmount > 0.00M)
            this.Parameters += "&TAXAMT=" + this.TaxAmount.ToString(CultureInfo.InvariantCulture.NumberFormat);

            if (this.SecurityCode != "")
                  this.Parameters += "&CVV2=" + this.SecurityCode;


        // ***  Save our raw input string for debugging
        this.RawProcessorRequest = this.Parameters;

            // *** connects to Verisign COM object to handle transaction
            System.Type typPayFlow = System.Type.GetTypeFromProgID( "PFProCOMControl.PFProCOMControl.1" );
            object PayFlow = Activator.CreateInstance( typPayFlow );
           
            this.RawProcessorResult = "";

            try
            {
            // *** Use Reflection and Late binding to call COM object
            // *** to avoid creating Interop assembly
                  int context = (int) wwUtils.CallMethod(PayFlow,"CreateContext",this.HttpLink,this.HostPort,this.Timeout,
                                                   this.ProxyAddress,this.ProxyPort,this.ProxyUsername, this.ProxyPassword);
                 
            this.RawProcessorResult = (string) wwUtils.CallMethod(PayFlow,"SubmitTransaction",context,Parameters,Parameters.Length);

                  wwUtils.CallMethod(PayFlow, "DestroyContext",context);
            }
            catch(Exception ex)
            {
                  this.ValidatedResult = "FAILED";
                  this.ValidatedMessage = ex.Message;
                  this.LogTransaction();
                  return false;
            }

            string ResultValue = wwHttpUtils.GetUrlEncodedKey(this.RawProcessorResult,"RESULT");

        this.TransactionId = wwHttpUtils.GetUrlEncodedKey(this.RawProcessorResult, "PNREF");


            // *** 0 means success
            if (ResultValue == "0")
            {
                  this.ValidatedResult = "APPROVED";
            this.AuthorizationCode = wwHttpUtils.GetUrlEncodedKey(this.RawProcessorResult, "AUTHCODE");
            this.LogTransaction();
                  return true;
            }
                  // *** Empty response means we have an unknown failure
            else if (ResultValue == "")
            {
                  this.ValidatedMessage = "Unknown Error";
                  this.ValidatedResult = "FAILED";
            }
                  // *** Negative number means communication failure
            else if (ResultValue.StartsWith("-") )
            {
                  this.ValidatedResult = "FAILED";
                  this.ValidatedMessage = wwHttpUtils.GetUrlEncodedKey(this.RawProcessorResult,"RESPMSG");
                 
            }
                  // *** POSITIVE number means we have a DECLINE
            else
            {
                 this.ValidatedResult = "DECLINED";
             this.ValidatedMessage = wwHttpUtils.GetUrlEncodedKey(this.RawProcessorResult,"RESPMSG");
            }

            this.Error = true;
            this.LogTransaction();
            return false;
      }

}
Note that this class implements a few additional provider specific properties such as the proxy settings and VerisignPartner.
It's kind of ironic that this API uses COM to call out to the Verisign servers, but it requires a UrlEncoded input and output mechanism to get the actual result values.

LinkPoint API

The LinkPoint API is another custom API that provides a .NET implementation as well as a COM implementation. The .NET implementation is a bit clunky to say the least as it requires you to manually download and install a custom SSL driver that LinkPoint uses for secure communications. I guess stock .NET SSL is not good enough for these guys <g>. The need for this is likely related to their use of a custom certificate on the client.

The process of using LinkPoint involves:
  • Signing up with LinkPoint and getting a test account
  • Downloading and installing the .NET API
  • Using the ccLinkPoint class from within .NET
  • Enabling the class by setting a #define EnableLinkPoint

Getting and Installing the LinkPoint API


The LinkPoint API provides a variety of components for different languages and development environments. The API basically handles setting up transactions and sending the transactions via HTTPS to the LinkPoint Gateway server. To work with the API you only the appropriate component plus a little code to drive the component which is provided by the wwLinkPoint class.

You can download the LinkPoint API from:
https://www.linkpoint.com/viewcart/

You'll want to use the LinkPoint API .NET (C# or VB) download for Windows. This download includes a couple of DLLs (linkpointTransaction.dll and lpssl.dll) which you should copy in your bin or executable directory so your application can find it.

OpenSSL is a separate, required download
For .NET you will also need to download the OpenSSL DLLs which Linkpoint uses. You can go to http://www.linkpoint.com/support/ and follow the links from there to download and drop libeay.dll and ssleay.dll into your System32 directory.

Using the wwLinkPoint Class
Once the LinkPoint API is installed you'll need the following information from your confirmation email(s):
  • The path to the filename to which you copied your Certificate (a .PEM file)
  • Your Store Number
  • Your Store Password
  • The domain name and port number of the live or test server
Enabling the ccLinkPoint class
Because the LinkPoint API has a dependency on the external LinkPoint assemblies the ccLinkPoint class by default disables the class through a #define blo. At the top of the ccLinkPoint class there's a #define EnableLinkPoint directive, which is commented out by default. When commented the body of the class is excluded and any attempt to instantiate the class fails with an exception.
To enable the class uncomment the #define EnableLinkPoint directive. Then copy the LinkpointTransaction.dll and lpssl.dll into the bin/executable directory of your application and add a reference in your project to LinkPointTransaction.dll.
Although a factory pattern might have isolated this interface more cleanly it would have also required a separate assembly. Since LinkPoint is a specialty install and you will need to copy the LinkPoint DLLs explicitly anyway so we opted for this simpler more integrated approach.
Special Properties you need to set
CC = new ccLinkPoint();
CC.MerchantPassword = App.Configuration.CCMerchantId;   // "123412314"
CC.CertificatePath = App.Configuration.CCCertificatePath;     // "d:\app\MyCert.pem" 
 
// *** HTTP Link can be server name plus port
CC.HTTPLink = "staging.linkpt.net:1229";
// CC.Port = 1229;    // or specify port separately
Here's the implementation of the ccLinkPoint class:
#define EnableLinkPoint 

using System;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Globalization;

using Westwind.InternetTools;
using Westwind.Tools;

#if EnableLinkPoint
using LinkPointTransaction;
#endif

namespace Westwind.WebStore
{
/// <summary>
/// The ccLinkPoint class provides an ccProcessing interface to the
/// LinkPoint 6.0 interface.
/// </summary>
public class ccLinkPoint : ccProcessing
{
      /// <summary>
      /// The Port used by the LinkPoint API to communicate with the server.
      /// This port will be provided to you by LinkPoint. Note that you
      /// can also provide the port as part of the HTTPLink domainname.
      /// </summary>
      public int HostPort = 1129;

      public ccLinkPoint()
      {
            this.HttpLink = "secure.linkpt.net:1129";
      }

      #if EnableLinkPoint

      /// <summary>
      /// Validates the credit card. Supported transactions include Sale or Credit.
      /// Credits should have a negative sales amount.
      /// </summary>
      /// <returns></returns>
      public override bool ValidateCard()
      {
            if (!base.ValidateCard())
                  return false;
           
            this.Error = false;
            this.ErrorMessage = "";

            // *** Parse the HttpLink for domain + port number
            int At = this.HttpLink.IndexOf(":");
            if (At > 0)
            {
                  string t = this.HttpLink.Substring(At+1);
                  this.HostPort = int.Parse( t );
                  this.HttpLink = this.HttpLink.Substring(0,At);
            }

            // create order
            LPOrderPart order = LPOrderFactory.createOrderPart("order");

            // create a part we will use to build the order
            LPOrderPart op = LPOrderFactory.createOrderPart();
                 
            // Figure out what type of order we are processing
            if (this.OrderAmount < 0 )
            {
                  op.put("ordertype","CREDIT");
                  this.OrderAmount = this.OrderAmount * -1;
            }
            else if (this.ProcessType == ccProcessTypes.Credit )
                  op.put("ordertype","CREDIT");
            else if (this.ProcessType == ccProcessTypes.Sale )
                  op.put("ordertype","SALE");
            else if (this.ProcessType == ccProcessTypes.PreAuth )
                  op.put("ordertype","PREAUTH");
                             
            // add 'orderoptions to order
            order.addPart("orderoptions", op );

            // Build 'merchantinfo'
            op.clear();
            op.put("configfile",this.MerchantId);

            // add 'merchantinfo to order
            order.addPart("merchantinfo", op );

            // Build 'billing'
            // Required for AVS. If not provided,
            // transactions will downgrade.
            op.clear();
            op.put("name",this.Name);
            op.put("address1",this.Address);
            op.put("city",this.City);
            op.put("state",this.State);
            op.put("zip",this.Zip);
            op.put("country",this.Country);
            op.put("email",this.Email);
            op.put("phone",this.Phone);
           
            int  AddrNum = 0;
            try
            {
                  string T = this.Address.Substring( 0 , this.Address.IndexOf(" ") ).Trim();
                  AddrNum = int.Parse(T);
            }
            catch { ; }
           
            if (AddrNum != 0) 
            {
                  op.put("addrnum",  AddrNum.ToString( System.Globalization.CultureInfo.InvariantCulture.NumberFormat) );
            }
            order.addPart("billing", op );

            // Build 'creditcard'
            op.clear();
            op.put("cardnumber",this.CreditCardNumber );
            op.put("cardexpmonth",this.CreditCardExpirationMonth);
            op.put("cardexpyear",this.CreditCardExpirationYear);

            order.addPart("creditcard", op );

            // Build 'payment'
            op.clear();
            op.put("chargetotal",this.OrderAmount.ToString( System.Globalization.CultureInfo.InvariantCulture.NumberFormat ) );

            order.addPart("payment", op );     

            // *** Trasnaction Details
            op.clear();
            if (this.OrderId != null && this.OrderId != "" )
                  op.put("oid",this.OrderId );

            order.addPart("transactiondetails",op);

            if (this.Comment != "" )
            {
                  // *** Notes
                  op.clear();
                  op.put("comments",this.Comment );
                  order.addPart("notes",op);
            }

            // create transaction object 
            LinkPointTxn LPTxn = new LinkPointTxn();

            // get outgoing XML from the 'order' object
            this.RawProcessorRequest = order.toXML();

            // Call LPTxn
            try
            {
                  this.RawProcessorResult = LPTxn.send(this.CertificatePath,this.HttpLink,this.HostPort, this.RawProcessorRequest );
            }
            catch(Exception ex)
            {
                  if (this.RawProcessorResult != "")
                  {
                        string Msg = wwUtils.ExtractString(this.RawProcessorResult,"<r_error>","</r_error>") ;
                        if (Msg == "")
                              this.SetError(ex.Message);
                        else
                              this.SetError(Msg);
                  }
                  else
                  {    
                        this.SetError(ex.Message);
                  }

                  this.ValidatedMessage = this.ErrorMessage;
                  this.ValidatedResult = "FAILED";
                  return false;
            }
           
            this.ValidatedResult = wwUtils.ExtractString(this.RawProcessorResult,"<r_approved>","</r_approved>");
            if (this.ValidatedResult == "")
                  this.ValidatedResult = "FAILED";
            this.ValidatedMessage = wwUtils.ExtractString(this.RawProcessorResult,"<r_message>","</r_message>");

           
            if (this.ValidatedResult == "APPROVED")
            {
                  this.SetError(null);
            }
            else
            {
                  this.SetError( wwUtils.ExtractString(this.RawProcessorResult,"<r_error>","</r_error>") );
                  this.ValidatedMessage = this.ErrorMessage;
            }
           
            this.LogTransaction();

            return !this.Error;
      }
      #else
      public override bool ValidateCard()
      {
            throw new Exception("ccLinkPoint Class is not enabled. Set the EnableLinkPoint #define in the source file.");
      }
      #endif
}

Other providers

In addition to these three providers listed above there are also classes for AccessPoint and BluePay which are included in the download that goes with this article. The provided help file also provides the configuration details.

A few comments about these classes

Please realize that these classes provide basic sale functionality. Most of the classes support SALE/AUTH CAPTURE, AUTH and CREDIT transactions. If you need to do things like recurring billing or debit card payments you'll have to extend the functionality of these classes, but the base here should give you a good starting point for creating additional functionality or adding a new provider.

Sample Application

I've provided a small sample application that lets you test this class. You only need to configure the provider specific settings in the sample and you then should be able to test the specific provider that you have the appropriate credentials for. The sample application is included in the downloads for this article.

Testing your Gateways

All of the Gateway providers provide TestModes that allow you to test processing without charging real transactions. Some of the gateways require a special URL, while others have a flag value that lets operation switch into Test mode. The ccProcessing classes automatically switches gateways that use flags (Authorize.NET, BluePay, AccessPoint,PayFlowPro).

Once you've tested the gateways in test mode I recommend that you run a few test transactions through with live credit cards. The reason for this is that test transactions tend to give you generic messages and usually don't provide all the information that live requests return. For example, AVS codes and detailed error messages are usually not available through test modes.
Most APIs also support some special credit card numbers that are intended to run against the live gateway and to produce specific errors. For example, Authorize.NET lets you specify a special card number and set a dollar amount that matches the result error code you want to have returned. Other gateways provide similar functionality. Check the provider's gateway documentation.

What about PayPal?

PayPal is actually another alternative payment processing solution. PayPal supports both PayPal Basic and Pro. Basic is a remote site payment integration solution that requires you to navigate to PayPal's servers to validate your payment.

PayPal is a great choice if you are just starting out because it is easy to sign up without any startup costs and start taking money almost immediately. Depending on what price you're selling things at, PayPal can be a bit pricier than merchant accounts, but it's great solution for getting online quick and with paperwork and up front money outlay or any sort of commitment.

I've written an extensive article about PayPal Basic ASP.NET integration here:


PayPal recently also started offering PayPal Payments Pro which also provides a merchant type API. I currently have not completed integrating PayPal Payments Pro into this class hierarchy, although I started the process. There's some starter code in place, but it is not complete and has not been tested yet. At the time I had problems with the PayPal certificate not working and decided there were more important things than PayPals funky API <g>. Left for another day.

PayPal Pro offers flat rate merchant percentages and no transaction fees so in some situations it can be a cheaper solution. However, there's been a lot of complaining about PayPal's support and in dealing with chargeback resolution. If you are thinking about PayPal Payments Pro be sure to do some research online to see what problems exist. At the time of this writing PayPal Payments Pro just got released a couple of weeks ago. Time will tell.

Hooking up Credit Card Processing in ASP.NET

Phew, we're finally ready to put all of this to work and stick it into an application. I use a standard shopping cart as an example here, because it's likely the most common scenario and can be easily adapted to any kind of payment situation.

Let's take a quick walk through a typical Web store from shopping cart through checkout and describe the process, and then go through the code to make it happen afterwards. Figure 3 through 7 shows the process. If you want to check this out in real time, you can visit www.west-wind.com/webstoresandbox/ and access the store from there. This is a sandbox site so you can put in bogus data and play around.

It all starts with your Shopping Cart application. Generally you'll have some sort of shopping basket that collects all the items and provides running totals of the order. Figure 3 shows what this looks like on my Web site.

Figure 3: The starting point for an order is usually a shopping cart that collects and subtotals items.       

Customers will tend to browse your site, pick items and eventually are ready to check out. At that point there needs to be some way to check out or in this case Place Order. In a live site, this is usually also the point where the application transitions from regular http: to a secure https: connection.

The next couple of steps collect customer and order information. In my store I broke out this information into 2 distinct forms – one for the customer information and one for the order specific information. But you can obviously put this all onto one form (a little too busy for my taste) or split it into additional forms.

Figure 4: Taking customer information maps to the credit card billing information. Note this page should run under SSL to protect the customers personal information over the wire.

The order form collects customer information which will ultimately maps to the credit card billing information. It's important that you collect credit card BILLING information because this information is used in Address Verification of the customer. If you have separate shipping address information you should present that separately. Note the form shows a checkbox to expand shipping information that lets the customer enter the shipping address if it's different from the billing address (and in this case only if a physical shipment is requested).

I've found that it's important to make that very clear on your forms - customers often forget to use their billing address especially on business credit cards. We'll have a chance to catch this later as part of processing when Address Verification fails, but it's much easier and cheaper to catch it at the point of data entry. Make sure you make it clear that Billing address info is what you need to capture.

Figure 5: The final order form should let you capture credit card information and handle the validation process. Errors should also display back on this page.

Review Order Information
Next we need to collect the billing information from the customer. It's important that the customer can see the order information on this page so he or she can review his order before submitting payment. At minimum this form should display an order total, but I recommend you show the order in all its detail to make absolutely sure the customer knows what he's getting. I know I've gone into online stores more than once only to purchase the wrong thing or ordering 2 of something when I intended to only get one. 

Anything you can do make the orders submitted correct at the point of entry, you should do as it takes a lot more effort to fix it after the order has been placed. Not only does it take away from the automated process you're striving to achieve with an online site, it also costs money and manual processing time if you have to issue credits and/or resubmit orders.

CVS Code
The information captured here is the Credit Card Number, Expiration date and Security Code. The security code is optional with most providers but I highly recommend that you require users to provide it as it provides at least a little additional protection against fraud. Using the code also lowers your merchant percentage slightly with some merchant providers. It's a good idea to require it. If you do make sure you provide information on where to find it on the card. In Figure 5 clicking on the ? icon brings up more information and if you go to the live site you can use the text and images I use there.

Pre-Validation of Credit Card Information
The credit card gateways will validate the credit card number and expiration date and it may seem to tempting to skip validation and let the gateway deal with it. But keep in mind that every access to the gateway and the front end network costs a little money in transaction charges, so it's a good idea to do as much up front checking as possible.

Credit Card numbers can be validated using simple Mod10 validation. The form above includes some client side JavaScript that checks the card number for Mod10 compliance and notifies the user if

A JavaScript validation routine (that I used with some slight modification) in my store can be found here:


In the application above the Mod10 validation is hooked to the onblur of the credit card textbox and it displays a little tooltip underneath the textbox as a visual hint to the customer. The server side ccProcessing class also includes Mod10 validation and you can utilize that code on the server if you don't want to deal with client side script validation.

The form also validates all user input on the server. The Invoice business object has a Validate() method that can validate the user input and can check for the credit card date being valid and the various informational field being filled in. If an error of any sort occurs the form is spit back to the user with an error message (as shown above) BEFORE any credit card processing is done. In other words, the credit card processing is the last step of the invoice processing and only if everything else is OK does the card get sent off to the Gateway for processing.

Note that in ASP.NET the request posts back to the same page. And while the processing for the credit card validation is going on you want to make sure that the customer is not clicking on the submit button more than once. The form actually replaces the display content of the page as soon as the Place Order button is clicked and you'll see a display like this:

Figure 6: A 'please wait' interface replaces the form as soon as the place order button is clicked in order to avoid having customers click more than once to submit the form.

This HTML panel is merely a client side initially hidden <iframe> tag, that is made visible by the button click, while the main page content – wrapped in a <div> is hidden. The logic is hooked up to the form's onsubmit:

<form id="frmOrderForm" onsubmit="ShowWaitDisplay()" runat="server">

and then implemented with this simple JavaScript function:

function ShowWaitDisplay()
{
    document.getElementById("MainForm").style.display="none";
    IFrame = document.getElementById("WaitFrame");
    IFrame.src = "waitform.htm"
    IFrame.style.display = "inline";
    window.scrollTo(0,0);
    return true;     
}

The IFRAME loads a static HTML page that can be designed separately of the order form itself, so it's easy to maintain. If you need a dynamic message you can also use an ASPX page and pass data to it via the querystring or if more complicated via the Session object.

When the server side processing is done the page returns back to itself, since the page is using a standard page POSTBACK. If an error occurred it displays the credit card error message. This value is retrieved indirectly ccProcessing.cValidatedMessage and presented as yet another error message similar to the ones shown in Figure 5.

If the credit card processing went through the invoice is saved and written to disk and the form then redirects to an order confirmation page. which is shown in Figure 6.

Figure 7: The order confirmation page summarizes the order and lets the user know what to expect and where to go if there should be a problem. This is especially important if you're using some form of electronic fulfillment and the fulfillment (usually email) fails.

The confirmation serves a number of important functions. It obviously confirms to the customer what's she's just paid for, but more importantly it communicates to them what happens next. They paid for the product so now you need to fulfills the order. If you are a vendor that fulfills orders electronically you can notify the customer that a confirmation will be sent or that items will be shipped etc. along with a content address that can be used for them to contact support.

The confirmation form in this application is also serves as the notification portion of the application, so an order confirmation is sent with the same info displayed on this form, and if items can be confirmed immediately or accessed via a download link a confirmation notice is sent off immediately as well.

Alright, now we've seen how the order process works, let's take a look behind the scenes and see how the credit card processing is hooked into this.

How it works

In this store application the UI page that handles the credit card processing is OrderForm.aspx which is shown in Figure 5. Up until this point data has been internally collected in the application and stored in a database (or temporary table) along with some identification that identifies the customer and the invoice.

The core processing occurs in the btnSubmit_Click when the Place order button is clicked.

/// <summary>
/// Saves the invoice if all goes well!
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void btnSubmit_Click(object sender, System.EventArgs e)
{
    // *** Unbind the form and display any errors related to the binding
    this.UnbindData();

    // *** This check is somewhat application specific
    if (this.txtHeardFrom.Text.StartsWith("***"))
    {
        this.AddBindingError("Please enter where you heard about us.",this.txtHeardFrom.ID);
    }

    invRow = this.Invoice.Entity;

    // *** Override custom field handling
    invRow.Ccexp = Request.Form["txtCCMonth"] + "/" + Request.Form["txtCCYear"];
    invRow.Shipdisks = Invoice.ShipInfo.ShipToCustomer;

    if (Invoice.ShipInfo.ShippingMethod != "--")
        invRow.Shipby = Invoice.ShipInfo.ShippingMethod;

    // *** Add the DevTool Used
    if (this.DevToolUsed != "" && !this.DevToolUsed.StartsWith("***"))
        this.Invoice.SetProperty("DevToolUsed", this.DevToolUsed);

    // *** Load up the Shipping Address captured previously
    object Temp = Session["ShippingAddressPk"];
    if (Temp != null)
    {
        busShippingAddress ShipAddress = WebStoreFactory.GetbusShippingAddress();
        if (ShipAddress.Load((int)Temp))
            this.Invoice.UpdateShippingAddress(ShipAddress);
    }

    // The promo code wasn't databound to the invoice - do it now
    invRow.Ordercode = this.Invoice.ShipInfo.PromoCode;

    // *** Must recalc and update the invoice and display
    this.ShowLineItems();

    // *** If Invoice doesn't validate show error and exit
    if (!this.Invoice.Validate() || this.bindingErrors.Count > 0 )
    {
        this.AddValidationErrorsToBindingErrors(this.Invoice.ValidationErrors);
        this.ErrorDisplay.ShowError(this.bindingErrors.ToHtml(),"Please correct the following:");
        return;
    }


    if (this.bindingErrors.Count > 0)
    {
        this.ErrorDisplay.ShowError(this.bindingErrors.ToHtml());
        return;
    }

    // *** Handle PayPal Processing seperately from ProcessCard() since it requires
    // *** passing off to another page on the PayPal Site.
    // *** This request will return to this page Cancel or Success querystring
    if (App.Configuration.CCProcessingType != CCProcessingTypes.None &&
        this.txtCCType.Text == "PP" &&
        !this.PayPalReturnRequest)
    {
        // *** We have to Save Invoice so that IPN confirm can see it!
        // *** We'll mark it as an UNPROCESSED order.
        this.invRow.Ccresult = "UNPROCESSED";
        if (!Invoice.Save(true))
        {
            this.ErrorDisplay.ShowError(this.Invoice.ErrorMessage,
                                        "An error occurred saving the invoice:");
            return;
        }

        // *** Now redirect to PayPal
        this.HandlePayPalRedirection();
    }

    // *** We're processing Credit Cards
    // *** the method decides whether CC processing actually takes place
    if (!this.ProcessCreditCard())
    {
        string Error = Invoice.ErrorMessage;
        int lnAt = Error.IndexOf(";");
        if (lnAt > 0)
            Error = Error.Substring(0, lnAt);

        // *** If we have a FAILED transaction pass it through unprocessed - we handle it offline

        // *** Otherwise echo error back.
        if (invRow.Ccresult != "FAILED")
        {
            this.ErrorDisplay.ShowError(Error, "Credit Card Processing failed: ");
            return;
        }
    }
   
    // *** Let's make sure the Temp LineItems are updated
    // *** Since we may have changed the Promo Code
    Invoice.LineItems.SaveLineItems(false);

    // *** Save the invoice by copynig the Temporary LineItems to the real lineitems
    if (!this.Invoice.Save(true))
    {
        this.ErrorDisplay.ShowError(this.Invoice.ErrorMessage, "An error occurred saving the invoice:");
        return;
    }

    // *** Confirm the order items
    if (invRow.Ccresult.Trim() == "APPROVED" && this.Invoice.CanAutoConfirm())
        this.Invoice.SendEmailConfirmation();

    // *** Clear out the Invoice Session PK so this invoice is 'history'     
    Session.Remove("ShoppingCartItems");
    Session.Remove("ShoppingCartSubTotal");
    Session.Remove("ShippingAddressPk");

    // *** Clear out expired Temporary lineitems
    busTLineItem LineItems = WebStoreFactory.GetbusTLineItem();
    LineItems.ClearExpiredLineItems(7200); // 2 hours

    // *** Show the confirmation page - don't transfer so they can refresh without error
    Response.Redirect("Confirmation.aspx");
}
         
The code starts off with unbinding the data on the form back into the business objects that are loaded on the form. The form's Page_Load() sets up an empty Invoice and Customer object and loads the available data (Invoice Pk, Customer Pk and lineitems) into it. The unbinding the takes the values from the current form and updates the appropriate fields (if you're interested in how this control based two-way databinding works go here).

Once the data's been bound from the controls into the business object, it gets validated. First a few explict page level field checks are done followed by the Invoice object's validation (Invoice.Validate()). If either of these fail, BindingErrors are added and the page is redisplayed with the errors displayed at the top of the form.

If all that goes well, the next step is the payment processing. This form handles both PayPal and Credit Card Processing. For more detail on the PayPal integration in this same mechanism visit this page. The Credit card processing essentially goes out to an internal routine that calls the business object's ValidateCreditCard() method I showed earlier. This method returns true or false, and if false the error message is displayed and the form redisplayed. If successful the order is saved (Invoice.Save()) and written to disk. Finally the application redirects to the confirmation page which then displays the final order information and sends email confirmations.

The internal credit card processing is offloaded to a custom method:

bool ProcessCreditCard()
{
    // *** PayPal shouldn't be procesed
    if (App.Configuration.CCProcessingType ==  CCProcessingTypes.None ||
        this.invRow.Cctype == "PP")
        return true;

    // *** See if we're On to do online processing
    // *** This logic checks to see whether items  are shippable without manual validation
    // *** If all are then the order is processed online. Otherwise it's simply submitted
    // *** and processed offline later.
    if (!App.Configuration.ccProcessCardsOnline)
        return true;

    // *** Check to see if this order can be processed without
    // *** manual confirmation (such as upgrades etc.)
    // *** YOU MAY WANT TO REMOVE THIS LINE IF YOU ALWAYS PROCESS CARDS
    if (!Invoice.CanAutoConfirm())
        return true;

    // *** Process the actual card for this invoice
    if (!Invoice.ProcessCreditCard())
    {
        // *** Let the Page handle the error
        // *** Invoice.ErrorMessage has parsed error info
        return false;
    }

    return true;
}

The core logic in this method decides how credit cards are to be processed, which uses global configuration settings in the App.Configuration object which maps to web.config settings (for more info see Building a better Application Configuration Class). It's a good idea to not hardcode any settings related to credit card processing into the application, so using configuration settings.

Here's the Invoice.ProcessCreditCard() method I showed earlier in the article again this time in context. As you can see this method also uses configuration settings for any of the credit card processing parameters, such as merchant id and password, timeouts and so on. The rest of the properties are set simply from the Invoice object's data members:

/// <summary>
/// Processes credit cards for the provider set in App.Configuration.CCMerchant
/// Works with the WebStoreConfig settings for setting to configure the provider
/// settings.
/// </summary>
/// <remarks>The Invoice is not saved at this point.
/// Make sure to call Save() after this operation.</remarks>
/// <returns></returns>
public bool ProcessCreditCard()
{
    bool Result = false;

    wws_invoiceRow Inv = this.Entity;
    wws_customersRow Cust = this.Customer.Entity;

    ccProcessing CC = null;
    ccProcessors CCType = App.Configuration.CCProcessor;

    try
    {
        if (CCType == ccProcessors.AccessPoint)
        {
            CC = new ccAccessPoint();
        }
        else if (CCType == ccProcessors.AuthorizeNet)
        {
            CC = new ccAuthorizeNet();
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
        }
        else if (CCType == ccProcessors.PayFlowPro)
        {
            CC = new ccPayFlowPro();
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
        }
        else if (CCType == ccProcessors.LinkPoint)
        {
            CC = new ccLinkPoint();
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
            CC.CertificatePath = App.Configuration.CCCertificatePath;   // "d:\app\MyCert.pem"
        }
        else if (CCType == ccProcessors.PayPalWebPaymentsPro)
        {
            CC = new ccPayPalWebPaymentsPro();
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
            ((ccPayPalWebPaymentsPro)CC).PrivateKeyPassword = "";
        }
        else if (CCType == ccProcessors.BluePay)
        {
            CC = new ccBluePay();
            CC.MerchantId = App.Configuration.CCMerchantId;
            CC.MerchantPassword = App.Configuration.CCMerchantPassword;
        }

        CC.MerchantId = App.Configuration.CCMerchantId;

        //CC.UseTestTransaction = true;

        // *** Tell whether we do SALE or Pre-Auth
        CC.ProcessType = App.Configuration.CCProcessType;

        // *** Disable this for testing to get provider response
        CC.UseMod10Check = true;

        CC.Timeout = App.Configuration.CCConnectionTimeout;  // In Seconds
        CC.HttpLink = App.Configuration.CCHostUrl;         

        CC.LogFile = App.Configuration.CCLogFile;
        CC.ReferingUrl = App.Configuration.CCReferingOrderUrl;

        // *** Name can be provided as a single string or as firstname and lastname
        //CC.Name = Cust.Firstname.TrimEnd() + " " + Cust.Lastname.TrimEnd();
        CC.Firstname = Cust.Firstname.TrimEnd();
        CC.Lastname = Cust.Lastname.TrimEnd();

        CC.Company = Cust.Company.TrimEnd();
        CC.Address = Cust.Address.TrimEnd();
        CC.State = Cust.State.TrimEnd();
        CC.City = Cust.City.TrimEnd();
        CC.Zip = Cust.Zip.TrimEnd();
        CC.Country = Cust.Countryid.TrimEnd();  // 2 Character Country ID
        CC.Phone = Cust.Phone.TrimEnd();
        CC.Email = Cust.Email.TrimEnd();

        CC.OrderAmount = Inv.Invtotal;
        CC.TaxAmount = Inv.Tax;                             // Optional
        CC.CreditCardNumber = Inv.Cc.TrimEnd();
        CC.CreditCardExpiration = Inv.Ccexp.TrimEnd();

        CC.SecurityCode = Inv.Ccsecurity.TrimEnd();

        // *** Make this Unique
        CC.OrderId = Inv.Invno.TrimEnd() + "_" + DateTime.Now.ToString();
        CC.Comment = App.Configuration.CompanyName + " Order # " +
                                                     Inv.Invno.TrimEnd();

        Result = CC.ValidateCard();

        Inv.Ccresult = CC.ValidatedResult;
        if (!Result)
        {
            this.ErrorMessage = CC.ValidatedMessage;
            Inv.Ccerror = this.ErrorMessage;
        }

        // *** Always write out the raw response
        if (string.NullOrEmpty(CC.RawProcessorResult))
            Inv.Ccresultx = CC.ValidatedMessage;
        else
            Inv.Ccresultx = CC.RawProcessorResult;
    }
    catch (Exception ex)
    {
        this.SetError(ex.Message);
        Inv.Ccresult = "FAILED";
        Inv.Ccresultx = "Processing Error: " + ex.Message;
        Inv.Ccerror = "Processing Error: " + ex.Message;
        return false;
    }

    return Result;
}

The business object takes care of all the details of dealing with the credit card processing. When the processing is complete, the Invoice's ccResult,ccResultx and ccError properties are set. ccResultx is the raw response and is stored for future reference should there be any problems with the transaction.

When this method returns – true or false – the client code can simply check these 3 properties to determine whether it worked and get an error message to display back on the page on failure.

Ok, so that completes the CC Processing code. This example, is a live application so there are a few application specific details I've shown, but I hope these have given you a realistic view of how you can integrate the basic credit card processing classes I described here.  Of course you don't have to go through this abstraction if you don't want to – you can simply call the appropriate class directly in your ASPX if you choose, but I've found that abstraction of credit card processing code is a good idea in case you need to switch providers later, or more importantly if you need that same credit card processing in another application.

For example, the abstraction also allows me to reuse this credit card processing code in an offline application of the Web Store. Orders can be downloaded from the Web Site via Web Service to a WinForms applications that keeps the order and customer data local. The same Invoice and ccProcessing classes are used in the WinForms application. And in both applications I now only have to fill the invoice properties and call ProcessCreditCard() and check the return value and 3 result values – it becomes really easy to reuse the credit card processing logic in the Invoice object. Even without the business object, the various ccProcessing classes can also be used directly in WinForms applications.

Figure 8: Reusability is good: An offline application of the store can use the same exact credit card processing routines from the business object and/or ccProcessing classes.

Online or Offline Card Processing

The offline application actually raises an interesting point. Should you process cards online or should you process them after the original order entry is complete. Naturally we all want to take credit cards and charge them right away and get the customers money <g>. But there are situations where you might NOT want to charge the customer right away.

For example, on my Web Site I sell primarily software which can be downloaded immediately. For those items you definitely want to do online processing. Or do you? <g> For a while I had major problems with orders from the far east being fraudulent. I now have a filter built into my business object that checks the country where the order is placed from and if it's not within a list of countries allowed the order is not immediately processed and instead completed as unprocessed.

I can then later download the order, manually review it in hopes of catching potential fraud. It's often easy to tell potential fraud when email addresses looks wrong or addresses sound phoney. At that point I can contact the customer and double check. Usually if fraud is involved you'll never hear back.

Another scenario in my business is upgrades. I don't keep invoice information online beyond a couple of days – so the online site does not actually have all the order history for customers. Even if I did, customer companies often change and so verifying upgrades is not something that I have been able to completely automate. So, things like upgrades are flagged in my store's inventory as non-self-confirming items. When there's a non-self-confirming item on the order, the order is not sent to credit card processing immediately.

All of this happens inside of the Invoice business object with this method:

public override bool CanAutoConfirm()
{
    InvoiceEntity Invoice = this.Entity;

    // *** If we have a special order code we need to manually
    // *** process this order as we have to apply a discount
    // *** and verify the order
    string OrderCode = Invoice.Ordercode;
    if (OrderCode != null && OrderCode != "" || OrderCode == "TEST")
        return false;

    // *** Don't process cards online without a security code (PayPal is an exception)
    if (Invoice.Ccsecurity.Trim() == "" && Invoice.Cctype != "PP")
        return false;

    // *** Due to potential fraud don't process foreign cards
    // *** except from common countries - others will
    // *** require offline processing
    string CountryCode = (string) this.Customer.DataRow["CountryId"];
   
    if (CountryCode != "US" && CountryCode != "CA" && CountryCode != "DE" &&
        CountryCode != "GB" && CountryCode != "AU" && CountryCode !="AT" &&
        CountryCode != "CH" && CountryCode != "FR")
        return false;

    return base.CanAutoConfirm();
}

The above is what I call conditional offline processing.

Note that 'offline' processing doesn't have to be done in an 'offline application' like a Windows Forms App either. For example, the store has an Administration area (and a PDA interface) where I can review orders and validate and confirm orders from.

Offline processing gives you a chance to verify orders. If you're dealing in large ticket items, or you are in a business where the fraud potential is high, offline processing might be a good choice. Unless you sell electronic delivery goods or access type services where immediate notification is required, there's not much inconvenience to the customer by not immediately processing the card. But obviously there's inconvenience to you as the validation now becomes a manual process – it's tradeoff but one that might be worthwhile in some situations.

Another downside to offline processing is that you can't immediately get the results from the credit card processing and echo any errors back to the customer. So if an invalid card was entered, or more likely, an invalid address was used, you're not going to catch it until you run the card at a later point. If the card fails you'll have to contact the customer to get her to resubmit the order or otherwise clear up the error. This is obviously a lot more work than having the customer fix it immediately as they are placing the order.

AUTH vs. SALE Transactions         

Another way that you can 'buy a little time' is by using an AUTH as opposed to a SALE or AUTH CAPTURE transaction. In the samples here I've shown SALE transactions, which immediately charge the customers credit card (well at the end of the day or whenever your batches close anyway). But you can also do just an AUTH which reserves funds, but doesn't charge the customer until you go back and do an AUTH CAPTURE. AUTH operation works by returning you an Authorization code that is returned and reserves funds on the customer's credit card. The money is held for some period of time. To capture the actual money you do another credit card transaction and use AUTH CAPTURE passing in the Authorization code (or transaction id – depends on gateway) from the original AUTH procedure.

Using AUTH is required if the vendor is not shipping product to the customer within 48 hours.

Support for later AUTH CAPTURE requests are not supported in the ccProcessing classes except for Authorize.NET. For all others you can run the initial AUTH but the code for later capturing is not available. It should be easy to add if you need it though.

Security Considerations

It's pretty obvious that there are security considerations when you are dealing with customer's credit card data. It's important that the date the customer submits on the Web site is safe while traveling over the wire and that the data captured from the customer stays safe when store with you as the vendor.

SSL Encryption

Your customers will expect your site to be SSL enabled if they are to trust you with their credit card information. SSL ensures that data is encrypted as it travels over the wire and this protects you from potential network sniffing. To hook up SSL you need to get a public SSL certificate from a certificate authority or reseller of certificates. Base certificates have gotten a lot cheaper in recent years and you can get certificates from many providers and hosting companies for under $100. I use DirectNic for all my certificates and domain registrations, but there are plenty of other providers out there that are in that same range. If you use an ISP check with the providers they use as they often get volume deals that may be cheaper than your own shopping.

Displaying Credit Card Information

The next issue is to make sure that you NEVER display full credit card numbers in your Web application back to the customer beyond the initial point of entry. The idea is if for whatever reason your application is compromised or a user account is compromised you are not in any way displaying the card information back to the unauthorized person.

This means, if after the order has been placed you display order information back to the customer, like say on an order status page, make sure you display the credit card number with blacked out numbers except a few of the numbers to let the customer identify the card used. The official rules from the Credit Card companies are that only the last four digits can be displayed.

Here's a routine I use to handle the display consistently as part of the business object that normally displays the value:

public string GetHiddenCC()
{
    InvoiceEntity Inv = this.Entity;

    string CC = Inv.Cc.TrimEnd();

    if (Inv.Cctype == "PP" && CC == "")
        return "<a href='http://www.paypal.com/'>paid with PayPal</a>";

    if (CC.Length == 0)
        return "";
    if (CC.Length < 10)
        return "**** **** **** ****";

    string lcFirst = CC.Substring(0, 2);
    string lcLast = CC.Substring(CC.Length - 4, 4);
    //return "**** **** **** " + lcLast;

    return lcFirst + "** **** **** " + lcLast;
}

So inside of a page I might display the value as an expression like this:

<%= this.Invoice.GetHiddenCC() %>

Notice I cheat a little in displaying the first two digits, so I have an idea what type of card I'm dealing with. I think this makes it easier for anyone to identify a card at a glance. But be the official rules are only to display the last 4 digits.

Storing Credit Cards

Storing credit cards is also an important security consideration. The threat is always that your Web server (or even standalone machine) might be compromised in some way and credit cards might get out. It's highly unlikely that this will happen, but there's always the potential. There are many potential security risks from break ins, your ISP, or even somebody inside the company stealing card numbers.

If at all possible you should not hold on to credit card data of your customers. This is not always possible especially in e-Commerce applications that expect frequent repeat customers and want to avoid having to re-enter credit cards over and over again.

If possible though, it's a good idea to clear credit card data for orders once the order has been processed. Should there be any sort of trouble with the transaction and you need to issue a refund or the customer returns you can just ask for the card again. This is one way to remove any possibility that large amounts of credit card data can be compromised and it limits your liability greatly.

If you absolutely must store credit card data it should be stored in encrypted form.

There are various compliance standards (specifically CSIP and PCI) that vendors are supposed to follow that describe specific rules of how networks need to be secured and data stored. These rules are fairly complex and require very expensive certification. However, these standards are so strict and expensive to get verified for that it's nearly impossible for smaller businesses to comply. While smaller vendors are not likely to be pushed to comply, not complying essentially releases the credit card company of any liability should there be fraud or a security breach. In other words you are fully responsible for the full extent of the damage (realistically you are anyway – I'm only echoing back the rough concepts of these certifications).

Conflict Resolution: Chargebacks, Fraud

While we're at it – as vendor you usually get the short end of the stick if there is any problem with a transaction. If a customer calls the merchant provider and requests his money back this is known as a ChargeBack. If a customer complains and files a chargeback request, chances are greatly in favor of the customer to get his money back unless you can meticulously document the transaction and shipment to the customer. This is especially difficult if your transactions and product delivery are made electronically.

You can and should always fight a chargeback and your best weapon are complete records of the transaction and more importantly the fulfillment of the order. Make sure you keep good documentation on all transactions. Keep all transaction data, have good shipping records if you ship physical product including signature receipts. This gives you the best chance of fighting frivolous chargebacks.

Some merchant banks are also more aggressive about standing up for their vendors than others. My previous merchant provider pretty much never let chargebacks get reversed even though I sent in fairly complete documentation. My current merchant (Synergy) on the other hand has much fewer chargebacks coming back to me – presumably because they are being resolved at the merchant level. And chargebacks that I have received have had a much higher reversal rate after documentation was sent in. The reality is that most chargeback requests are created by customers who can't figure out what they actually bought. Often contacting the customers and verifying what they bought can get them to reverse chargeback.

So the merchant matters in these situations. Unfortunately, there aren't good ways to find out before signing which type you end up with, unless you spend some time online search various merchant forums and paying close attention to which providers are getting good feedback from vendors.

Summary

We've covered a lot of ground in this long article and I hope you find this information useful. If you're starting out with payment processing this article has most of the information you need short of a specific provider list. I obviously have my preferences and I've mentioned them here. However, I recommend that you spend a little time comparing rates, and checking out various merchant forums to see which merchant providers offer the best rates, choices and customer service.

It's time to get busy and start making some money online…


Source Code from this article:
The source code for this article includes the classes described here including all support classes. There's also a small sample application for both ASP.NET 1.1 and 2.0 that you can use to test operation against the supported providers assuming you have an account to test with. The sample also includes the PayPal Classic integration code and sample.

Acknowledgements:

Special thanks to Zachary Smith from MerchantPlus who provided clarification and detail on the backend processing networks.

Related Resources:

Find a cool free stuff everyday

Giveaway of the Day

Hiren Bharadwa's Posts

DotNetJalps