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.
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.
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.
After a successful transaction, the below screen will appear.
Braintree
As we can see, this is the list of transactions in Braintree.
I hope this will help. Thanks!
References