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