Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#6.0

Extending the PayPal .NET API to Detect Errors

5.00/5 (3 votes)
12 Oct 2015CPOL3 min read 12K  
This short tip will show you how to extend PayPal's .NET API by adding new members to their objects and page-level functions that will help provide a smooth error-handling experience.

Introduction

Here, I will show you how to accurately detect and display any errors generated by the PayPal .NET API. As any seasoned developer knows, you need to do all you can to make sure you know what's going on with your code, especially when dealing with user's credit cards. The examples use Visual Studio 2015, ASP.NET 4.6 and C# 6.

This tip assumes that you have downloaded the API from https://github.com/paypal/PayPal-NET-SDK and that you have a web application that's ready to use the API and that you have copied the relavent files to your web application's directory. This tip will NOT show you how to create a website and then integrate the API to the site. The relevant files (at least in my case) would include Common.cs, Configuration.cs, PayFlow,cs, RequestFLow.cs and RequestFlowItem.cs.

PayFlow Error Architecture

In the diagram, you'll see at the bottom that PayPal's messages are three levels down and they come in three flavors: General, Success and Error.

Adding the Properties

Open the RequestFlowItem.cs file and add a new readonly public property that will tell you if there are any errors, I use “HasFlowItemErrors” for the name. Add a getter accessor that will check the Messages collection (a List of RequestFlowItemMessage objects) and using the “Any” linq extension provides a lambda expression that interrogates the Type property of every item and looks for a type that equals RequestFlowItemMessageType.Error:

C#
public bool HasFlowItemErrors
{
       get
       {
            return Messages.Any(x => x.Type == RequestFlowItemMessageType.Error);
       }
}

On the PayFLow.cs file, add a new readonly public property that will tell you if there are any errors, I use “HasErrors” for the name. Add a getter accessor that will check the Items property (a List of RequestFlowItem objects) and using the Any linq extention provide a lambda expression that interrogates the HasFlowItemErrors property of every item:

C#
public bool HasErrors
{
      get
      {
            return flow.Items.Any(x => x.HasFlowItemErrors);
      }
}

As you can see, this property only has a getter, no need for a setter since the information we’re looking for is already contained within the framework.

Implementing the New Properties

On your web form’s code behind, add a click event handler for the button that submits a payment (if you don’t already have one). After your payment is processed, add a conditional statement that checks the new HasErrors property of the PayFlow object. If HasErrors returns true, then you need to iterate through the Items collection and check the Messages property of each one and check for an error on those.

To implement this check, I’ve created a page level function that does the first check using the ForEach LINQ extension:

C#
private void displayErrors(List<RequestFlowItem> items)
{
     items.ForEach(x => getError(x));
}

As you can see, the lambda expression contains a call to a method named getError which does the job of iterating through the Messages property of each RequestFlowItem:

C#
private void getError(RequestFlowItem item)
{
      item.Messages.ForEach(y => getErrorMarkup(y));
}

A third function named getErrorMarkup takes in the RequestFlowItemMessage object that is passed in and checks to see if its Type property is equal to RequestFlowItemMessageType.Error:

C#
private void getErrorMarkup(RequestFlowItemMessage message)
{
     if (message.Type == RequestFlowItemMessageType.Error)
     {
          ErrorMessages.Text = String.Format("<div>{0}</div>", message.Message);
     }
}

If the message is an Error, then it wraps the message inside a div and adds it to the Text property of a Literal control that I have placed on the page. To simplify the readability of my code, I went ahead and added a new boolean property to the RequestFlowItemMessage class: IsError. With this new property, I can replace the value equality check with a simple property value check, this makes for less clutter in my code and better readability:

C#
///the property definition in RequestFlowItemMessage.cs:
public bool IsError
{
      get
      {
          return (Type == RequestFlowItemMessageType.Error);
      }
}

///implementation in web form:
private void getErrorMarkup(RequestFlowItemMessage message)
{
      if (message.IsError)
      {
          ErrorMessages.Text = String.Format("<div>{0}</div>", message.Message);
      }
}

Finally, I replaced my String.Format with the use of the new string interpolation feature of CSharp 6 (https://github.com/dotnet/roslyn/wiki/New-Language-Features-in-C%23-6). So now I have:

C#
ErrorMessages.Text = $"<div>{message.Message}</div>";

So, in the end, you should end up with something similar to this on your web forms code behind page:

protected void SubmitPayemnt_Click(object sender, EventArgs e)
{

      payFlow.MakePayment();
      if (payFlow.HasErrors)
      {
          displayErrors(payFlow.flow.Items);
          return;
      }
      else
      {
          Messages.Text = "Payment posted successfuly!";
      }
}

private void displayErrors(List<RequestFlowItem> items)
{
       items.ForEach(x => getError(x));
}


private void getError(RequestFlowItem item)
{
       item.Messages.ForEach(y => getErrorMarkup(y));
}


private void getErrorMarkup(RequestFlowItemMessage message)
{
      if (message.IsError)
      {
            ErrorMessages.Text = $"<div>{message.Message}</div>";
      }
}

I hope this tip will help anyone struggling with the PayPal's .NET API, as I work with the framework myself I will attempt to provide more tips/tricks or articles to help the fellow developer.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)