diff --git a/MpesaLibrary.sln b/MpesaLibrary.sln
index 402f0e3..fba0b22 100644
--- a/MpesaLibrary.sln
+++ b/MpesaLibrary.sln
@@ -14,7 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9372EA7C-3B1
__JSONSchema =
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MpesaLib.Tests", "MpesaLib.Tests\MpesaLib.Tests.csproj", "{C9FBF83B-0C56-4071-B4F1-B835AE86A026}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MpesaLib.Tests", "src\MpesaLib.Tests\MpesaLib.Tests.csproj", "{D2EFFCF9-1F0B-4A14-AD20-ADDE06A2C885}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -26,17 +26,17 @@ Global
{C780CBA5-DDED-4311-B829-16FDF97F163E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C780CBA5-DDED-4311-B829-16FDF97F163E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C780CBA5-DDED-4311-B829-16FDF97F163E}.Release|Any CPU.Build.0 = Release|Any CPU
- {C9FBF83B-0C56-4071-B4F1-B835AE86A026}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C9FBF83B-0C56-4071-B4F1-B835AE86A026}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C9FBF83B-0C56-4071-B4F1-B835AE86A026}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C9FBF83B-0C56-4071-B4F1-B835AE86A026}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D2EFFCF9-1F0B-4A14-AD20-ADDE06A2C885}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D2EFFCF9-1F0B-4A14-AD20-ADDE06A2C885}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D2EFFCF9-1F0B-4A14-AD20-ADDE06A2C885}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D2EFFCF9-1F0B-4A14-AD20-ADDE06A2C885}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C780CBA5-DDED-4311-B829-16FDF97F163E} = {9372EA7C-3B1B-4E16-A108-6E1F0B7C23BD}
- {C9FBF83B-0C56-4071-B4F1-B835AE86A026} = {9372EA7C-3B1B-4E16-A108-6E1F0B7C23BD}
+ {D2EFFCF9-1F0B-4A14-AD20-ADDE06A2C885} = {9372EA7C-3B1B-4E16-A108-6E1F0B7C23BD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AF2D71E1-E089-4701-96B8-A55DE41A7751}
diff --git a/MpesaLib.Tests/LipaNaMpesaOnlineTest.cs b/src/MpesaLib.Tests/LipaNaMpesaOnlineTest.cs
similarity index 100%
rename from MpesaLib.Tests/LipaNaMpesaOnlineTest.cs
rename to src/MpesaLib.Tests/LipaNaMpesaOnlineTest.cs
diff --git a/MpesaLib.Tests/MpesaLib.Tests.csproj b/src/MpesaLib.Tests/MpesaLib.Tests.csproj
similarity index 86%
rename from MpesaLib.Tests/MpesaLib.Tests.csproj
rename to src/MpesaLib.Tests/MpesaLib.Tests.csproj
index 01770d5..88db7a6 100644
--- a/MpesaLib.Tests/MpesaLib.Tests.csproj
+++ b/src/MpesaLib.Tests/MpesaLib.Tests.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/MpesaLib.Tests/TestData.cs b/src/MpesaLib.Tests/TestData.cs
similarity index 100%
rename from MpesaLib.Tests/TestData.cs
rename to src/MpesaLib.Tests/TestData.cs
diff --git a/src/MpesaLib/Helpers/Exceptions/MpesaApiException.cs b/src/MpesaLib/Helpers/Exceptions/MpesaApiException.cs
new file mode 100644
index 0000000..86c1765
--- /dev/null
+++ b/src/MpesaLib/Helpers/Exceptions/MpesaApiException.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MpesaLib.Helpers.Exceptions
+{
+ ///
+ /// Mpesa Api Exceptions Helper class
+ ///
+ public class MpesaApiException : Exception
+ {
+ ///
+ /// Http Status code
+ ///
+ public int StatusCode { get; set; }
+
+ ///
+ /// Content from response body
+ ///
+ public string Content { get; set; }
+ }
+}
diff --git a/src/MpesaLib/IMpesaClient.cs b/src/MpesaLib/IMpesaClient.cs
index 774fab4..dbb0f27 100644
--- a/src/MpesaLib/IMpesaClient.cs
+++ b/src/MpesaLib/IMpesaClient.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System.Threading;
+using System.Threading.Tasks;
namespace MpesaLib
{
@@ -17,8 +18,9 @@ public interface IMpesaClient
/// ConsumerKey provided by Safaricom in Daraja Portal.
/// ConsumerSecret provided by Safaricom in Daraja Portal.
/// Set to RequestEndPoint.AuthToken
+ /// Cancellation Token
/// A string of characters representing the accesstoken.
- Task GetAuthTokenAsync(string consumerKey, string consumerSecret, string requestEndPoint);
+ Task GetAuthTokenAsync(string consumerKey, string consumerSecret, string requestEndPoint, CancellationToken cancellationToken = default);
///
/// GetAuthTokenAsync is an asynchronous method that requests for and returns an accesstoken from MPESA API Server.
@@ -26,20 +28,22 @@ public interface IMpesaClient
/// ConsumerKey provided by Safaricom in Daraja Portal.
/// ConsumerSecret provided by Safaricom in Daraja Portal.
/// Set to RequestEndPoint.AuthToken
+ /// Cancellation Token
/// A string of characters representing the accesstoken.
- string GetAuthToken(string consumerKey, string consumerSecret, string requestEndPoint);
+ string GetAuthToken(string consumerKey, string consumerSecret, string requestEndPoint, CancellationToken cancellationToken = default);
///
- /// Makes an STK Push payment request to MPESA API Server.
+ /// Makes STK Push payment request to MPESA API Server.
///
///
/// Data trnasfer object containing properties for the Lipa Na Mpesa Online API endpoint.
///
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.LipaNaMpesaOnline
+ /// Cancellation Token
/// A JSON string containing LNMO response data from MPESA API Server
- Task MakeLipaNaMpesaOnlinePaymentAsync(LipaNaMpesaOnlineDto mpesaLipaOnlineDto, string accesstoken, string requestEndPoint);
+ Task MakeLipaNaMpesaOnlinePaymentAsync(LipaNaMpesaOnlineDto mpesaLipaOnlineDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -50,8 +54,9 @@ public interface IMpesaClient
///
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.LipaNaMpesaOnline
+ /// Cancellation Token
/// A JSON string containing data from MPESA API response
- string MakeLipaNaMpesaOnlinePayment(LipaNaMpesaOnlineDto mpesaLipaOnlineDto, string accesstoken, string requestEndPoint);
+ string MakeLipaNaMpesaOnlinePayment(LipaNaMpesaOnlineDto mpesaLipaOnlineDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -60,6 +65,7 @@ public interface IMpesaClient
/// Transaction Query Data transfer object
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryLipaNaMpesaOnlieTransaction
+ /// Cancellation Token
///
/// A JSON string containing data from MPESA API reposnse
///
@@ -67,7 +73,7 @@ public interface IMpesaClient
/// Use only for transactions initiated with MakeLipaNaMpesaOnlinePayment method.
/// For Other transaction based methods (C2B,B2C,B2B) use QueryMpesaTransactionStatusAsync method.
///
- Task QueryLipaNaMpesaTransactionAsync(LipaNaMpesaQueryDto mpesaTransactionQueryDto, string accesstoken, string requestEndPoint);
+ Task QueryLipaNaMpesaTransactionAsync(LipaNaMpesaQueryDto mpesaTransactionQueryDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -76,6 +82,7 @@ public interface IMpesaClient
/// Transaction Query Data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryLipaNaMpesaOnlieTransaction
+ /// Cancellation Token
///
/// A JSON string containing data from MPESA API reposnse.
///
@@ -84,7 +91,7 @@ public interface IMpesaClient
/// For Other transaction based methods (C2B, B2C, B2B, Accountbalance, Reversal)
/// use QueryMpesaTransactionStatusAsync method.
///
- string QueryLipaNaMpesaTransaction(LipaNaMpesaQueryDto mpesaTransactionQueryDto, string accesstoken, string requestEndPoint);
+ string QueryLipaNaMpesaTransaction(LipaNaMpesaQueryDto mpesaTransactionQueryDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -93,8 +100,9 @@ public interface IMpesaClient
/// Account balance query data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryAccountBalance
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- Task QueryAccountBalanceAsync(AccountBalanceDto accountBalanceQueryDto, string accesstoken, string requestEndPoint);
+ Task QueryAccountBalanceAsync(AccountBalanceDto accountBalanceQueryDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -103,8 +111,9 @@ public interface IMpesaClient
/// Account balance query data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryAccountBalance
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- string QueryAccountBalance(AccountBalanceDto accountBalanceQueryDto, string accesstoken, string requestEndPoint);
+ string QueryAccountBalance(AccountBalanceDto accountBalanceQueryDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -113,8 +122,9 @@ public interface IMpesaClient
/// B2B data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.BusinessToBusiness
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- Task MakeB2BPaymentAsync(BusinessToBusinessDto businessToBusinessDto, string accesstoken, string requestEndPoint);
+ Task MakeB2BPaymentAsync(BusinessToBusinessDto businessToBusinessDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -123,8 +133,9 @@ public interface IMpesaClient
/// B2B data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.BusinessToBusiness
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- string MakeB2BPayment(BusinessToBusinessDto businessToBusinessDto, string accesstoken, string requestEndPoint);
+ string MakeB2BPayment(BusinessToBusinessDto businessToBusinessDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
@@ -134,11 +145,12 @@ public interface IMpesaClient
/// B2C data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.BusinessToCustomer
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
///
/// Suitable for refunds, rewards or just about any transaction that involves a business paying a customer.
///
- Task MakeB2CPaymentAsync(BusinessToCustomerDto businessToCustomerDto, string accesstoken, string requestEndPoint);
+ Task MakeB2CPaymentAsync(BusinessToCustomerDto businessToCustomerDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -147,11 +159,12 @@ public interface IMpesaClient
/// B2C data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.BusinessToCustomer
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
///
/// Suitable for refunds, rewards or just about any transaction that involves a business paying a customer.
///
- string MakeB2CPayment(BusinessToCustomerDto businessToCustomerDto, string accesstoken, string requestEndPoint);
+ string MakeB2CPayment(BusinessToCustomerDto businessToCustomerDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -160,13 +173,14 @@ public interface IMpesaClient
/// C2B data transfer object
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.CustomerToBusinessSimulate
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
///
/// Use only for Simulation/testing. In production use RegisterC2BUrlAsync method to register
/// endpoints in your application that receive customer initiated transactions from the MPESA API
/// for confirmation and/or validation
///
- Task MakeC2BPaymentAsync(CustomerToBusinessSimulateDto customerToBusinessSimulateDto, string accesstoken, string requestEndPoint);
+ Task MakeC2BPaymentAsync(CustomerToBusinessSimulateDto customerToBusinessSimulateDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
/// Simulates a Customer to Business payment request.
@@ -174,13 +188,14 @@ public interface IMpesaClient
/// C2B data transfer object
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.CustomerToBusinessSimulate
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
///
/// Use only for Simulation/testing. In production use RegisterC2BUrlAsync method to register
/// endpoints in your application that receive customer initiated transactions from the MPESA API
/// for confirmation and/or validation
///
- string MakeC2BPayment(CustomerToBusinessSimulateDto customerToBusinessSimulateDto, string accesstoken, string requestEndPoint);
+ string MakeC2BPayment(CustomerToBusinessSimulateDto customerToBusinessSimulateDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -189,8 +204,9 @@ public interface IMpesaClient
/// C2B Register URLs data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.RegisterC2BUrl
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- Task RegisterC2BUrlAsync(CustomerToBusinessRegisterUrlDto customerToBusinessRegisterUrlDto, string accesstoken, string requestEndPoint);
+ Task RegisterC2BUrlAsync(CustomerToBusinessRegisterUrlDto customerToBusinessRegisterUrlDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -199,8 +215,9 @@ public interface IMpesaClient
/// C2B Register URLs data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.RegisterC2BUrl
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- string RegisterC2BUrl(CustomerToBusinessRegisterUrlDto customerToBusinessRegisterUrlDto, string accesstoken, string requestEndPoint);
+ string RegisterC2BUrl(CustomerToBusinessRegisterUrlDto customerToBusinessRegisterUrlDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -209,8 +226,9 @@ public interface IMpesaClient
/// Reversal data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.ReverseMpesaTransaction
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- Task ReverseMpesaTransactionAsync(ReversalDto reversalDto, string accesstoken, string requestEndPoint);
+ Task ReverseMpesaTransactionAsync(ReversalDto reversalDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -219,8 +237,9 @@ public interface IMpesaClient
/// Reversal data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.ReverseMpesaTransaction
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- string ReverseMpesaTransaction(ReversalDto reversalDto, string accesstoken, string requestEndPoint);
+ string ReverseMpesaTransaction(ReversalDto reversalDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -229,8 +248,9 @@ public interface IMpesaClient
/// Transaction Status data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryMpesaTransactionStatus
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- Task QueryMpesaTransactionStatusAsync(MpesaTransactionStatusDto mpesaTransactionStatusDto, string accesstoken, string requestEndPoint);
+ Task QueryMpesaTransactionStatusAsync(MpesaTransactionStatusDto mpesaTransactionStatusDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
///
@@ -239,7 +259,8 @@ public interface IMpesaClient
/// Transaction Status data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryMpesaTransactionStatus
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- string QueryMpesaTransactionStatus(MpesaTransactionStatusDto mpesaTransactionStatusDto, string accesstoken, string requestEndPoint);
+ string QueryMpesaTransactionStatus(MpesaTransactionStatusDto mpesaTransactionStatusDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default);
}
}
diff --git a/src/MpesaLib/MpesaClient.cs b/src/MpesaLib/MpesaClient.cs
index 181a8d8..7c7e3dc 100644
--- a/src/MpesaLib/MpesaClient.cs
+++ b/src/MpesaLib/MpesaClient.cs
@@ -1,8 +1,11 @@
-using Newtonsoft.Json;
+using MpesaLib.Helpers.Exceptions;
+using MpesaLib.Responses;
+using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
namespace MpesaLib
@@ -13,14 +16,14 @@ namespace MpesaLib
public class MpesaClient : IMpesaClient
{
private readonly HttpClient _httpclient;
-
+
///
/// MpesaClient takes in an instance of HttpClient
///
- /// HttpClient Instance
+ /// HttpClient Instance
public MpesaClient(HttpClient httpClient)
{
- _httpclient = httpClient;
+ _httpclient = httpClient;
}
///
@@ -29,27 +32,11 @@ public MpesaClient(HttpClient httpClient)
/// ConsumerKey provided by Safaricom in Daraja Portal.
/// ConsumerSecret provided by Safaricom in Daraja Portal.
/// Set to RequestEndPoint.AuthToken
+ /// Cancellation Token
/// A string of characters representing the accesstoken.
- public string GetAuthToken(string consumerKey, string consumerSecret, string requestEndPoint)
+ public string GetAuthToken(string consumerKey, string consumerSecret, string requestEndPoint, CancellationToken cancellationToken = default)
{
- _httpclient.DefaultRequestHeaders.Clear();
-
- HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestEndPoint);
-
- var keyBytes = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{consumerKey}:{consumerSecret}"));
-
- _httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", keyBytes);
-
- var response = _httpclient.SendAsync(request).GetAwaiter().GetResult();
-
- response.EnsureSuccessStatusCode();
-
- var content = response.Content;
-
- var token = JsonConvert.DeserializeObject(content.ReadAsStringAsync().Result);
-
- return token.access_token;
-
+ return RequestAccessToken(consumerKey, consumerSecret, requestEndPoint, cancellationToken).GetAwaiter().GetResult();
}
///
@@ -58,41 +45,28 @@ public string GetAuthToken(string consumerKey, string consumerSecret, string req
/// ConsumerKey provided by Safaricom in Daraja Portal.
/// ConsumerSecret provided by Safaricom in Daraja Portal.
/// Set to RequestEndPoint.AuthToken
+ /// Cancellation Token
/// A string of characters representing the accesstoken.
- public async Task GetAuthTokenAsync(string consumerKey, string consumerSecret, string requestEndPoint)
+ public async Task GetAuthTokenAsync(string consumerKey, string consumerSecret, string requestEndPoint, CancellationToken cancellationToken = default)
{
- _httpclient.DefaultRequestHeaders.Clear();
-
- HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestEndPoint);
-
- var keyBytes = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{consumerKey}:{consumerSecret}"));
+ string token = await RequestAccessToken(consumerKey, consumerSecret, requestEndPoint, cancellationToken);
- _httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", keyBytes);
-
- var response = await _httpclient.SendAsync(request);
-
- response.EnsureSuccessStatusCode();
-
- var content = response.Content;
-
- var token = JsonConvert.DeserializeObject(content.ReadAsStringAsync().Result);
-
- return token.access_token;
+ return token;
}
+
///
/// Makes a Business to Business payment request between Paybill numbers.
///
/// B2B data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.BusinessToBusiness
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- public string MakeB2BPayment(BusinessToBusinessDto businessToBusinessDto, string accesstoken, string requestEndPoint)
+ public string MakeB2BPayment(BusinessToBusinessDto businessToBusinessDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- Task task = Task.Run(async () => await MpesaHttpCall(businessToBusinessDto, accesstoken, requestEndPoint, false));
-
- return task.Result;
+ return MpesaHttpRequest(businessToBusinessDto, accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
@@ -102,10 +76,11 @@ public string MakeB2BPayment(BusinessToBusinessDto businessToBusinessDto, string
/// B2B data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.BusinessToBusiness
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- public async Task MakeB2BPaymentAsync(BusinessToBusinessDto businessToBusinessDto, string accesstoken, string requestEndPoint)
+ public async Task MakeB2BPaymentAsync(BusinessToBusinessDto businessToBusinessDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- return await MpesaHttpCall(businessToBusinessDto, accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(businessToBusinessDto, accesstoken, requestEndPoint,cancellationToken);
}
@@ -115,15 +90,14 @@ public async Task MakeB2BPaymentAsync(BusinessToBusinessDto businessToBu
/// B2C data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.BusinessToCustomer
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
///
/// Suitable for refunds, rewards or just about any transaction that involves a business paying a customer.
///
- public string MakeB2CPayment(BusinessToCustomerDto businessToCustomerDto, string accesstoken, string requestEndPoint)
+ public string MakeB2CPayment(BusinessToCustomerDto businessToCustomerDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- Task task = Task.Run(async () => await MpesaHttpCall(businessToCustomerDto, accesstoken, requestEndPoint, false));
-
- return task.Result;
+ return MpesaHttpRequest(businessToCustomerDto, accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
///
@@ -132,15 +106,14 @@ public string MakeB2CPayment(BusinessToCustomerDto businessToCustomerDto, string
/// B2C data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.BusinessToCustomer
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
///
/// Suitable for refunds, rewards or just about any transaction that involves a business paying a customer.
///
- public async Task MakeB2CPaymentAsync(BusinessToCustomerDto businessToCustomerDto, string accesstoken, string requestEndPoint)
+ public async Task MakeB2CPaymentAsync(BusinessToCustomerDto businessToCustomerDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- HttpClientInit(_httpclient, accesstoken);
-
- return await MpesaHttpCall(businessToCustomerDto,accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(businessToCustomerDto,accesstoken, requestEndPoint,cancellationToken);
}
@@ -150,17 +123,16 @@ public async Task MakeB2CPaymentAsync(BusinessToCustomerDto businessToCu
/// C2B data transfer object
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.CustomerToBusinessSimulate
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
///
/// Use only for Simulation/testing. In production use RegisterC2BUrlAsync method to register
/// endpoints in your application that receive customer initiated transactions from the MPESA API
/// for confirmation and/or validation
///
- public string MakeC2BPayment(CustomerToBusinessSimulateDto customerToBusinessSimulateDto, string accesstoken, string requestEndPoint)
+ public string MakeC2BPayment(CustomerToBusinessSimulateDto customerToBusinessSimulateDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- Task task = Task.Run(async () => await MpesaHttpCall(customerToBusinessSimulateDto,accesstoken, requestEndPoint, false));
-
- return task.Result;
+ return MpesaHttpRequest(customerToBusinessSimulateDto,accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
@@ -170,15 +142,16 @@ public string MakeC2BPayment(CustomerToBusinessSimulateDto customerToBusinessSim
/// C2B data transfer object
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.CustomerToBusinessSimulate
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
///
/// Use only for Simulation/testing. In production use RegisterC2BUrlAsync method to register
/// endpoints in your application that receive customer initiated transactions from the MPESA API
/// for confirmation and/or validation
///
- public async Task MakeC2BPaymentAsync(CustomerToBusinessSimulateDto customerToBusinessSimulateDto, string accesstoken, string requestEndPoint)
+ public async Task MakeC2BPaymentAsync(CustomerToBusinessSimulateDto customerToBusinessSimulateDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- return await MpesaHttpCall(customerToBusinessSimulateDto, accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(customerToBusinessSimulateDto, accesstoken, requestEndPoint,cancellationToken);
}
@@ -190,12 +163,11 @@ public async Task MakeC2BPaymentAsync(CustomerToBusinessSimulateDto cust
///
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.LipaNaMpesaOnline
+ /// Cancellation Token
/// A JSON string containing LNMO response data from MPESA API Server
- public string MakeLipaNaMpesaOnlinePayment(LipaNaMpesaOnlineDto lipaNaMpesaOnlineDto, string accesstoken, string requestEndPoint)
+ public string MakeLipaNaMpesaOnlinePayment(LipaNaMpesaOnlineDto lipaNaMpesaOnlineDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- Task task = Task.Run(async () => await MpesaHttpCall(lipaNaMpesaOnlineDto, accesstoken, requestEndPoint, false));
-
- return task.Result;
+ return MpesaHttpRequest(lipaNaMpesaOnlineDto, accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
///
@@ -206,10 +178,11 @@ public string MakeLipaNaMpesaOnlinePayment(LipaNaMpesaOnlineDto lipaNaMpesaOnlin
///
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.LipaNaMpesaOnline
+ /// Cancellation Token
/// A JSON string containing LNMO response data from MPESA API Server
- public async Task MakeLipaNaMpesaOnlinePaymentAsync(LipaNaMpesaOnlineDto lipaNaMpesaOnlineDto, string accesstoken, string requestEndPoint)
+ public async Task MakeLipaNaMpesaOnlinePaymentAsync(LipaNaMpesaOnlineDto lipaNaMpesaOnlineDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- return await MpesaHttpCall(lipaNaMpesaOnlineDto, accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(lipaNaMpesaOnlineDto, accesstoken, requestEndPoint,cancellationToken);
}
@@ -219,12 +192,11 @@ public async Task MakeLipaNaMpesaOnlinePaymentAsync(LipaNaMpesaOnlineDto
/// Account balance query data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryAccountBalance
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- public string QueryAccountBalance(AccountBalanceDto accountBalanceQueryDto, string accesstoken, string requestEndPoint)
- {
- Task task = Task.Run(async () => await MpesaHttpCall(accountBalanceQueryDto, accesstoken, requestEndPoint, false));
-
- return task.Result;
+ public string QueryAccountBalance(AccountBalanceDto accountBalanceQueryDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
+ {
+ return MpesaHttpRequest(accountBalanceQueryDto, accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
@@ -234,10 +206,11 @@ public string QueryAccountBalance(AccountBalanceDto accountBalanceQueryDto, stri
/// Account balance query data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryAccountBalance
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- public async Task QueryAccountBalanceAsync(AccountBalanceDto accountBalanceQueryDto, string accesstoken, string requestEndPoint)
+ public async Task QueryAccountBalanceAsync(AccountBalanceDto accountBalanceQueryDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- return await MpesaHttpCall(accountBalanceQueryDto,accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(accountBalanceQueryDto,accesstoken, requestEndPoint,cancellationToken);
}
@@ -247,6 +220,7 @@ public async Task QueryAccountBalanceAsync(AccountBalanceDto accountBala
/// Transaction Query Data transfer object
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryLipaNaMpesaOnlieTransaction
+ /// Cancellation Token
///
/// A JSON string containing data from MPESA API reposnse
///
@@ -254,11 +228,9 @@ public async Task QueryAccountBalanceAsync(AccountBalanceDto accountBala
/// Use only for transactions initiated with MakeLipaNaMpesaOnlinePayment method.
/// For Other transaction based methods (C2B,B2C,B2B) use QueryMpesaTransactionStatusAsync method.
///
- public string QueryLipaNaMpesaTransaction(LipaNaMpesaQueryDto lipaNaMpesaQueryDto, string accesstoken, string requestEndPoint)
- {
- Task task = Task.Run(async () => await MpesaHttpCall(lipaNaMpesaQueryDto,accesstoken, requestEndPoint, false));
-
- return task.Result;
+ public string QueryLipaNaMpesaTransaction(LipaNaMpesaQueryDto lipaNaMpesaQueryDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
+ {
+ return MpesaHttpRequest(lipaNaMpesaQueryDto, accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
///
@@ -267,6 +239,7 @@ public string QueryLipaNaMpesaTransaction(LipaNaMpesaQueryDto lipaNaMpesaQueryDt
/// Transaction Query Data transfer object
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.QueryLipaNaMpesaOnlieTransaction
+ /// Cancellation Token
///
/// A JSON string containing data from MPESA API reposnse
///
@@ -274,9 +247,9 @@ public string QueryLipaNaMpesaTransaction(LipaNaMpesaQueryDto lipaNaMpesaQueryDt
/// Use only for transactions initiated with MakeLipaNaMpesaOnlinePayment method.
/// For Other transaction based methods (C2B,B2C,B2B) use QueryMpesaTransactionStatusAsync method.
///
- public async Task QueryLipaNaMpesaTransactionAsync(LipaNaMpesaQueryDto lipaNaMpesaQueryDto, string accesstoken, string requestEndPoint)
+ public async Task QueryLipaNaMpesaTransactionAsync(LipaNaMpesaQueryDto lipaNaMpesaQueryDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- return await MpesaHttpCall(lipaNaMpesaQueryDto,accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(lipaNaMpesaQueryDto,accesstoken, requestEndPoint,cancellationToken);
}
@@ -284,14 +257,13 @@ public async Task QueryLipaNaMpesaTransactionAsync(LipaNaMpesaQueryDto l
/// Queries status of an Mpesa transaction
///
///
- ///
- ///
+ /// Access Token
+ /// Endpoint Url
+ /// Cancellation Token
///
- public string QueryMpesaTransactionStatus(MpesaTransactionStatusDto mpesaTransactionStatusDto, string accesstoken, string requestEndPoint)
+ public string QueryMpesaTransactionStatus(MpesaTransactionStatusDto mpesaTransactionStatusDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- Task task = Task.Run(async () => await MpesaHttpCall(mpesaTransactionStatusDto,accesstoken, requestEndPoint, false));
-
- return task.Result;
+ return MpesaHttpRequest(mpesaTransactionStatusDto,accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
///
@@ -300,10 +272,11 @@ public string QueryMpesaTransactionStatus(MpesaTransactionStatusDto mpesaTransac
///
///
///
+ /// Cancellation Token
///
- public async Task QueryMpesaTransactionStatusAsync(MpesaTransactionStatusDto mpesaTransactionStatusDto, string accesstoken, string requestEndPoint)
+ public async Task QueryMpesaTransactionStatusAsync(MpesaTransactionStatusDto mpesaTransactionStatusDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- return await MpesaHttpCall(mpesaTransactionStatusDto,accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(mpesaTransactionStatusDto,accesstoken, requestEndPoint,cancellationToken);
}
@@ -313,12 +286,11 @@ public async Task QueryMpesaTransactionStatusAsync(MpesaTransactionStatu
/// C2B Register URLs data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.RegisterC2BUrl
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- public string RegisterC2BUrl(CustomerToBusinessRegisterUrlDto customerToBusinessRegisterUrlDto, string accesstoken, string requestEndPoint)
+ public string RegisterC2BUrl(CustomerToBusinessRegisterUrlDto customerToBusinessRegisterUrlDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- Task task = Task.Run(async () => await MpesaHttpCall(customerToBusinessRegisterUrlDto,accesstoken, requestEndPoint, false));
-
- return task.Result;
+ return MpesaHttpRequest(customerToBusinessRegisterUrlDto,accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
@@ -328,10 +300,11 @@ public string RegisterC2BUrl(CustomerToBusinessRegisterUrlDto customerToBusiness
/// C2B Register URLs data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.RegisterC2BUrl
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- public async Task RegisterC2BUrlAsync(CustomerToBusinessRegisterUrlDto customerToBusinessRegisterUrlDto, string accesstoken, string requestEndPoint)
+ public async Task RegisterC2BUrlAsync(CustomerToBusinessRegisterUrlDto customerToBusinessRegisterUrlDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- return await MpesaHttpCall(customerToBusinessRegisterUrlDto,accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(customerToBusinessRegisterUrlDto,accesstoken, requestEndPoint,cancellationToken);
}
@@ -341,14 +314,11 @@ public async Task RegisterC2BUrlAsync(CustomerToBusinessRegisterUrlDto c
/// Reversal data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.ReverseMpesaTransaction
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- public string ReverseMpesaTransaction(ReversalDto reversalDto, string accesstoken, string requestEndPoint)
- {
-
- Task task = Task.Run(async () => await MpesaHttpCall(reversalDto,accesstoken, requestEndPoint, false));
-
- return task.Result;
-
+ public string ReverseMpesaTransaction(ReversalDto reversalDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
+ {
+ return MpesaHttpRequest(reversalDto, accesstoken, requestEndPoint,cancellationToken).GetAwaiter().GetResult();
}
///
@@ -357,12 +327,19 @@ public string ReverseMpesaTransaction(ReversalDto reversalDto, string accesstoke
/// Reversal data transfer object.
/// Acccesstoken retrieved by the GetAuthTokenAsync method.
/// Set to RequestEndPoint.ReverseMpesaTransaction
+ /// Cancellation Token
/// A JSON string containing data from MPESA API reposnse.
- public async Task ReverseMpesaTransactionAsync(ReversalDto reversalDto, string accesstoken, string requestEndPoint)
+ public async Task ReverseMpesaTransactionAsync(ReversalDto reversalDto, string accesstoken, string requestEndPoint, CancellationToken cancellationToken = default)
{
- return await MpesaHttpCall(reversalDto,accesstoken, requestEndPoint, true);
+ return await MpesaHttpRequest(reversalDto,accesstoken, requestEndPoint,cancellationToken);
}
+
+ ///
+ /// Initializes the Httpclient for each handler
+ ///
+ /// httpclient instance
+ /// accesstoken
private static void HttpClientInit(HttpClient httpclient, string accesstoken)
{
httpclient.DefaultRequestHeaders.Clear();
@@ -370,7 +347,51 @@ private static void HttpClientInit(HttpClient httpclient, string accesstoken)
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accesstoken);
}
- private async Task MpesaHttpCall(object Dto,string token, string Endpoint, bool Asynchronous)
+
+
+ ///
+ /// Method makes the accesstoken request to mpesa api
+ ///
+ ///
+ ///
+ ///
+ /// Cancellation Token
+ /// string representing accesstoken
+ private async Task RequestAccessToken(string consumerKey, string consumerSecret, string requestEndPoint, CancellationToken cancellationToken = default)
+ {
+ _httpclient.DefaultRequestHeaders.Clear();
+
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestEndPoint);
+
+ var keyBytes = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{consumerKey}:{consumerSecret}"));
+
+ _httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", keyBytes);
+
+ var response = await _httpclient.SendAsync(request, cancellationToken);
+
+ var content = await response.Content.ReadAsStringAsync();
+
+ if (response.IsSuccessStatusCode == false)
+ {
+ throw new MpesaApiException
+ {
+ StatusCode = (int)response.StatusCode,
+ Content = content
+ };
+ }
+
+ return JsonConvert.DeserializeObject(content).AccessToken;
+ }
+
+ ///
+ /// Makes HttpRequest to mpesa api server
+ ///
+ /// Data transfer object
+ /// Mpesa Accesstoken
+ /// Request endpoint
+ /// Cancellation Token
+ /// Mpesa API response
+ private async Task MpesaHttpRequest(object Dto,string token, string Endpoint, CancellationToken cancellationToken = default)
{
HttpClientInit(_httpclient, token);
@@ -379,20 +400,20 @@ private async Task MpesaHttpCall(object Dto,string token, string Endpoin
Content = new StringContent(JsonConvert.SerializeObject(Dto).ToString(), Encoding.UTF8, "application/json")
};
- HttpResponseMessage response;
+ HttpResponseMessage response = await _httpclient.SendAsync(request, cancellationToken);
- if (Asynchronous)
- {
- response = await _httpclient.SendAsync(request);
- }
- else
+ var content = await response.Content.ReadAsStringAsync();
+
+ if (response.IsSuccessStatusCode == false)
{
- response = _httpclient.SendAsync(request).GetAwaiter().GetResult();
+ throw new MpesaApiException
+ {
+ StatusCode = (int)response.StatusCode,
+ Content = content
+ };
}
- response.EnsureSuccessStatusCode();
-
- return response.Content.ReadAsStringAsync().Result;
+ return content;
}
diff --git a/src/MpesaLib/TokenDto.cs b/src/MpesaLib/Responses/TokenResponse.cs
similarity index 75%
rename from src/MpesaLib/TokenDto.cs
rename to src/MpesaLib/Responses/TokenResponse.cs
index a4d4eae..f12448f 100644
--- a/src/MpesaLib/TokenDto.cs
+++ b/src/MpesaLib/Responses/TokenResponse.cs
@@ -4,23 +4,23 @@
using System.Linq;
using System.Threading.Tasks;
-namespace MpesaLib
+namespace MpesaLib.Responses
{
///
/// Accesstoken data transfer object
///
- public class TokenDto
+ public class TokenResponse
{
///
/// Access token to access other APIs
///
[JsonProperty("access_token")]
- public string access_token { get; set; }
+ public string AccessToken { get; set; }
///
/// time token expires
///
[JsonProperty("expires_in")]
- public string expires_in { get; set; }
+ public string ExpiresIn { get; set; }
}
}