Braintree Payment Gateway Integration With ASP.NET Core 2.1

In this post, we are going to implement the Braintree payment gateway with ASP.NET Core 2.1.

Based on the previous post, this article is extended to implement a payment gateway. We are going to modify/extend the existing sample application by downloading the full source code from GitHub.

GitHub

Let’s get started by opening the existing application. First of all, we are going to add a Braintree package. Go to NuGet to install the Braintree .NET Client Library, which is supported by both the .NET Framework and .NET Core.

NuGet

Configuration

This is where we configure the environment and merchant with the API key for Braintree.

public class BraintreeConfiguration : IBraintreeConfiguration
{
    public string Environment { get; set; }
    public string MerchantId { get; set; }
    public string PublicKey { get; set; }
    public string PrivateKey { get; set; }
    private IBraintreeGateway BraintreeGateway { get; set; }

    public IBraintreeGateway CreateGateway()
    {
        Environment = System.Environment.GetEnvironmentVariable("BraintreeEnvironment");
        MerchantId = System.Environment.GetEnvironmentVariable("BraintreeMerchantId");
        PublicKey = System.Environment.GetEnvironmentVariable("BraintreePublicKey");
        PrivateKey = System.Environment.GetEnvironmentVariable("BraintreePrivateKey");

        if (MerchantId == null || PublicKey == null || PrivateKey == null)
        {
            Environment = "sandbox";
            MerchantId = "9j4ynyf697k9685t";
            PublicKey = "25sy94dv3rqgg355";
            PrivateKey = "b0d5e1b1fa9dc24c263a3e83a148a7b3";
        }
        return new BraintreeGateway(Environment, MerchantId, PublicKey, PrivateKey);
    }
    public IBraintreeGateway GetGateway()
    {
        if (BraintreeGateway == null)
        {
            BraintreeGateway = CreateGateway();
        }
        return BraintreeGateway;
    }
}

Payments Controller

Generate Client-Token

Initially, an HttpGet method named GenerateToken gets called to generate the client token for authorization to initialize the client UI.

[HttpGet, Route("GenerateToken")]
public object GenerateToken()
{
    var gateway = config.GetGateway();
    var clientToken = gateway.ClientToken.Generate();
    return clientToken;
}

Create Transaction

Finally, the transaction is done with Amount and PaymentMethodNonce, which is payment authorization for the customer generated by the client script.

[HttpPost, Route("Checkout")]
public object Checkout(vmCheckout model)
{
    string paymentStatus = string.Empty;
    var gateway = config.GetGateway();
    var request = new TransactionRequest
    {
        Amount = model.Price,
        PaymentMethodNonce = model.PaymentMethodNonce,
        Options = new TransactionOptionsRequest
        {
            SubmitForSettlement = true
        }
    };
    Result<Transaction> result = gateway.Transaction.Sale(request);
    if (result.IsSuccess())
    {
        paymentStatus = "Succeeded";

        // Do Database Operations Here
    }
    else
    {
        string errorMessages = "";
        foreach (ValidationError error in result.Errors.DeepAll())
        {
            errorMessages += "Error: " + (int)error.Code + " - " + error.Message + "\n";
        }
        paymentStatus = errorMessages;
    }
    return paymentStatus;
}

Here is the complete code for the Payments Controller.

[ApiController, Route("api/[controller]"), Produces("application/json")]
public class PaymentsController : ControllerBase
{
    public IBraintreeConfiguration config = new BraintreeConfiguration();
    public static readonly TransactionStatus[] transactionSuccessStatuses =
    {
        TransactionStatus.AUTHORIZED,
        TransactionStatus.AUTHORIZING,
        TransactionStatus.SETTLED,
        TransactionStatus.SETTLING,
        TransactionStatus.SETTLEMENT_CONFIRMED,
        TransactionStatus.SETTLEMENT_PENDING,
        TransactionStatus.SUBMITTED_FOR_SETTLEMENT
    };
    [HttpGet, Route("GenerateToken")]
    public object GenerateToken()
    {
        var gateway = config.GetGateway();
        var clientToken = gateway.ClientToken.Generate();
        return clientToken;
    }
    [HttpPost, Route("Checkout")]
    public object Checkout(vmCheckout model)
    {
        string paymentStatus = string.Empty;
        var gateway = config.GetGateway();
        var request = new TransactionRequest
        {
            Amount = model.Price,
            PaymentMethodNonce = model.PaymentMethodNonce,
            Options = new TransactionOptionsRequest
            {
                SubmitForSettlement = true
            }
        };
        Result<Transaction> result = gateway.Transaction.Sale(request);
        if (result.IsSuccess())
        {
            paymentStatus = "Succeeded";

            // Do Database Operations Here
        }
        else
        {
            string errorMessages = "";
            foreach (ValidationError error in result.Errors.DeepAll())
            {
                errorMessages += "Error: " + (int)error.Code + " - " + error.Message + "\n";
            }
            paymentStatus = errorMessages;
        }
        return paymentStatus;
    }
}

Html View

In index.html, we need to add a drop-in library reference.

<script src="//js.braintreegateway.com/web/dropin/1.9.4/js/dropin.min.js" type="text/javascript"></script>

The below code snippet is where (<div id="drop-in"></div>) to render Drop-in UI in payment.html where a user can input card information. After providing valid card information, checkout action is performed by clicking on the Checkout button.

<div class="container-fluid">
    <div class="row">
        <h3>{{title}} - {{cartmodel.Price}}$</h3>
        <div id="dropin"></div>
        <button type="submit" id="checkout" class="btn btn-sm btn-success button">
            Checkout <i class="fa fa-shopping-cart"></i>
        </button>
        <h5>{{paymentresult}}</h5>
    </div>
</div>

AngularJS Controller

Get client token

To create the Drop-in UI, we need to provide the client token generated by the server for authorization.

// Generate View
braintree.dropin.create({
    authorization: client_token,
    container: '#dropin',
    card: {
        overrides: {
            styles: {
                input: {
                    color: 'blue',
                    'font-size': '18px'
                },
                '.number': {
                    'font-family': 'monospace'
                },
                '.invalid': {
                    color: 'red'
                }
            },
            fields: {
                number: {
                    // placeholder: 'Card Number',
                    formatInput: true // Turn off automatic formatting
                }
            }
        }
    }
}, function (createErr, instance) {
    // Handle creation errors or use the instance
});

Request Payment Method

This is where a client requests payment method information (PaymentMethodNonce). Later, the PaymentMethodNonce method is used in the server to charge a card.

// Checkout Submit
document.getElementById("checkout").addEventListener('click', function () {
    // event.preventDefault();
    instance.requestPaymentMethod(function (err, payload) {
        if (err) {
            console.log('Error', err);
            return;
        }
        // Token Braintree
        $scope.cartmodel.PaymentMethodNonce = payload.nonce;
        $scope.checkOut();
    });
});

The full Client Script.

templatingApp.controller('PaymentController', ['$scope', '$http', function ($scope, $http) {
    $scope.title = "Braintree Payment";
    $scope.paymentresult = null;
    $scope.cartmodel = {
        FirstName: "Shashangka",
        LastName: "LastName",
        Email: "[email protected]",
        Street: "Bejpara, Jessore",
        Price: 50
    };
    // Generate Token PaymentGateway
    PaymentGateway();
    function PaymentGateway() {
        $http({
            method: 'GET',
            url: '/api/Payments/GenerateToken'
        }).then(function successCallback(response) {
            // console.log(response.data);
            var client_token = response.data;

            // Generate View
            braintree.dropin.create({
                authorization: client_token,
                container: '#dropin',
                card: {
                    overrides: {
                        styles: {
                            input: {
                                color: 'blue',
                                'font-size': '18px'
                            },
                            '.number': {
                                'font-family': 'monospace'
                            },
                            '.invalid': {
                                color: 'red'
                            }
                        },
                        fields: {
                            number: {
                                // placeholder: 'Card Number',
                                formatInput: true // Turn off automatic formatting
                            }
                        }
                    }
                }
            }, function (createErr, instance) {
                // Checkout Submit
                document.getElementById("checkout").addEventListener('click', function () {
                    // event.preventDefault();
                    instance.requestPaymentMethod(function (err, payload) {
                        if (err) {
                            console.log('Error', err);
                            return;
                        }
                        // Token Braintree
                        $scope.cartmodel.PaymentMethodNonce = payload.nonce;
                        $scope.checkOut();
                    });
                });
            });

        }, function errorCallback(response) {
            console.log(response);
        });
    };

    // CheckOut
    $scope.checkOut = function () {
        console.log($scope.cartmodel);
        $http({
            method: 'POST',
            url: '/api/Payments/Checkout',
            data: $scope.cartmodel
        }).then(function successCallback(response) {
            console.log(response.data);
            $scope.paymentresult = response.data;
        }, function errorCallback(response) {
            console.log(response);
        });
    };
}]);

Testing

Here is the created payment Drop-in UI with Test Card No: 378282246310005 or 4111111111111111.

 Test Card

After a successful transaction, the below screen will appear.

Transaction

Braintree

As we can see, this is the list of transactions in Braintree.

Braintree

I hope this will help. Thanks!

References