.NET SDK
Introduction
To understand how to use this SDK it is best to read the following documentation:
API Reference
This SDK wraps the API and (amongst other things) exposes the responses of the webservice calls as .NET objects. Understanding the API will help you understand these SDK objects as well.
The explanation of all the various
features
we offer.
This page will help you understand the global flow when interacting with the Acquiring API using the .NET SDK.
Introduction
To understand how to use this SDK it is best to read the following documentation:
API Reference
This SDK wraps the API and (amongst other things) exposes the responses of the webservice calls as .NET objects. Understanding the API will help you understand these SDK objects as well.The explanation of all the various features we offer.
This page will help you understand the global flow when interacting with the Acquiring API using the .NET SDK.
The .NET SDK helps you to communicate with the Acquiring API . More specifically, it offers a fluent .NET API that provides access to all the functionality of the RESTful Server API. Below, we discuss the following topics in detail.
Initialization of the SDK
Payments
Exceptions
Logging
SSL issues
Advanced use: Connection pooling
Advanced use: Customization of the communication
Notes
The source code of the SDK is available on Github . There you can find installation instructions.
The API documentation of the latest version of the SDK is available here . For a specific major version, replace latest with the actual version in format <major>.x .
Initialization of the .NET SDK
All C# code snippets presented in the API Reference assume you have initialized the .NET SDK before using them in your Development Environment. This section details the initialization of the .NET SDK.
Initializing is simple, and requires only one key task: use our Factory class to create an instance of Client , which contains the actual methods to communicate with the Acquiring API.
The Factory needs the following input information to provide you with an initialized Client .
The OAuth2 client ID and secret
In addition, your app.config or web.config should look like the following:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configsections>
<section name="AcquiringSDK" type="Worldline.Acquiring.Sdk.CommunicatorConfigurationSection, Worldline.Acquiring.Sdk"></section>
</configsections>
<AcquiringSDK connecttimeout="5000" sockettimeout="30000" maxconnections="10" authorizationtype="OAuth2" oauth2TokenUri="https://auth-test-eu-west-1.aws.bambora.com/connect/token" integrator="<your company name>">
<apiendpoint host="api.preprod.acquiring.worldline-solutions.com" scheme="https"></apiendpoint>
</AcquiringSDK>
</configuration>
We recommend keeping the timeout values at these values. See API endpoints for the possible hosts and token URIs.
If a proxy should be used, your app.config or web.config should also include a proxy element:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configsections>
<section name="AcquiringSDK" type="Worldline.Acquiring.Sdk.CommunicatorConfigurationSection, Worldline.Acquiring.Sdk"></section>
</configsections>
<AcquiringSDK connecttimeout="5000" sockettimeout="30000" maxconnections="10" authorizationtype="OAuth2" oauth2TokenUri="https://auth-test-eu-west-1.aws.bambora.com/connect/token" integrator="<your company name>">
<apiendpoint host="api.preprod.acquiring.worldline-solutions.com" scheme="https"></apiendpoint>
<proxy host="api.domain.com" scheme="https" username="$username for the proxy" password="$password"></proxy>
</AcquiringSDK>
</configuration>
The apiEndpoint and proxy elements both support specifying a custom port. For instance, to define a test server as the API endpoint:
<apiendpoint host="testserver" scheme="http" port="8080"></apiendpoint>
You can create an instance of Client using the Factory with this code snippet:
Client client = Factory.CreateClient("oauth2ClientId", "oauth2ClientSecret");
This Client instance offers connection pooling and can be reused for multiple concurrent API calls. Once it is no longer used it should be closed.
Client implements System.IDisposable , which allows it to be used in using statements.
Initializing the SDK without app.config or web.config
In applications that do not use the .NET Framework but instead .NET Core or .NET 5 or up, configuration is not done through app.config or web.config . but instead appsettings.json . The .NET SDK does not natively support this. However, there are two alternatives:
Use one of the Factory methods that takes an IDictionary that contains the configuration instead.
Manually construct a CommunicatorConfiguration instance, set the necessary properties, and use it in one of the Factory methods that takes a CommunicatorConfiguration .
The following table shows the IDictionary keys or CommunicatorConfiguration properties to use for each setting:
app.config / web.config setting |
IDictionary key |
CommunicatorConfiguration property |
---|---|---|
AcquiringSDK.connectTimeout |
acquiring.api.connectTimeout |
ConnectTimeout |
AcquiringSDK.socketTimeout |
acquiring.api.socketTimeout |
SocketTimeout |
AcquiringSDK.maxConnections |
acquiring.api.maxConnections |
MaxConnections |
AcquiringSDK.authorizationType |
acquiring.api.authorizationType |
AuthorizationType |
AcquiringSDK.oauth2TokenUri |
acquiring.api.oauth2.tokenUri |
OAuth2TokenUri |
AcquiringSDK.integrator |
acquiring.api.integrator |
Integrator |
apiEndpoint.host |
acquiring.api.endpoint.host |
ApiEndpoint |
apiEndpoint.scheme |
acquiring.api.endpoint.scheme |
|
apiEndpoint.port |
acquiring.api.endpoint.port |
|
proxy.host |
acquiring.api.proxy.uri |
ProxyUri |
proxy.scheme |
||
proxy.port |
||
proxy.username |
acquiring.api.proxy.username |
ProxyUserName |
proxy.password |
acquiring.api.proxy.password |
ProxyPassword |
The API endpoint and proxy URI have type Uri . This URI should defines the scheme, hostname and port. It should not have any user info, path, query string or fragment. The same goes for the acquiring.api.proxy.uri IDictionary key.
You can create an instance of Client using the Factory with one of these code snippets:
IDictionary<string, string> configurationDictionary = new Dictionary<string, string>
{
{ "acquiring.api.connectTimeout", "5000" },
{ "acquiring.api.socketTimeout", "30000" },
{ "acquiring.api.maxConnections", "10" },
{ "acquiring.api.authorizationType", "OAuth2" },
{ "acquiring.api.oauth2.tokenUri", "https://auth-test-eu-west-1.aws.bambora.com/connect/token" },
{ "acquiring.api.integrator", "<your company name>" },
{ "acquiring.api.endpoint.host", "api.preprod.acquiring.worldline-solutions.com" },
{ "acquiring.api.endpoint.scheme", "https" }
};
Client client = Factory.CreateClient(configurationDictionary, "oauth2ClientId", "oauth2ClientSecret");
CommunicatorConfiguration configuration = new CommunicatorConfiguration()
{
ConnectTimeout = TimeSpan.FromMilliseconds(5000),
SocketTimeout = TimeSpan.FromMilliseconds(30000),
MaxConnections = 10,
AuthorizationType = AuthorizationType.OAuth2,
OAuth2TokenUri = "https://auth-test-eu-west-1.aws.bambora.com/connect/token",
Integrator = "<your company name>",
ApiEndpoint = new Uri("https://api.preprod.acquiring.worldline-solutions.com"),
OAuth2ClientId = "oauth2ClientId",
OAuth2ClientSecret = "oauth2ClientSecret"
};
Client client = Factory.CreateClient(configuration);
Exceptions
Besides the above exceptions, all calls can throw one of the following runtime exceptions:
A ValidationException if the request was not correct and couldn't be processed (HTTP status code 400)
An AuthorizationException if the request was not allowed (HTTP status code 403)
An IdempotenceException if an idempotent request caused a conflict (HTTP status code 409)
A ReferenceException if an object was attempted to be referenced that doesn't exist or has been removed, or there was a conflict (HTTP status code 404, 409 or 410)
A PlatformException if something went wrong on the Worldline platform. The Worldline platform was unable to process a message from a downstream partner/acquirer, or the service that you're trying to reach is temporary unavailable (HTTP status code 500, 502 or 503)
An ApiException if the RESTful Server API returned any other error
A payment attempt can now be handled as follows:
try
{
var response = client.V1()
.WithNewAcquirer(acquiredId)
.WithNewMerchant(merchantId)
.Payments()
.ProcessPayment(request);
}
catch (ValidationException e)
{
System.Console.Out.WriteLine("Input validation error: {0}", e.Detail);
}
catch (AuthorizationException e)
{
System.Console.Out.WriteLine("Authorization error: {0}", e.Detail);
}
catch (ReferenceException e)
{
System.Console.Out.WriteLine("Incorrect object reference: {0}", e.Detail);
}
catch (PlatformException e)
{
System.Console.Out.WriteLine("Error occurred at Worldline or a downstream partner/acquirer: {0}", e.Detail);
}
catch (ApiException e)
{
System.Console.Out.WriteLine("Worldline error: {0}, {1}", e.StatusCode, e.Detail);
}
Exception overview
The following table is a summary that shows when each of these exceptions will be thrown:
HTTP status code |
Meaning |
Description |
Exception Type |
---|---|---|---|
200 |
Successful |
Your request was processed correctly |
N/A |
201 |
Created |
Your request was processed correctly and a new resource was created.
|
N/A |
204 |
No Content |
Your request was processed correctly |
N/A |
400 |
Bad Request |
Your request is not correct and can't be processed. Please correct the mistake and try again. |
ValidationException |
403 |
Not Authorized |
You're trying to do something that is not allowed or that you're not authorized to do. |
AuthorizationException |
404 |
Not Found |
The object you were trying to access could not be found on the server. |
ReferenceException |
409 |
Conflict |
Your idempotent request resulted in a conflict. The first request has not finished yet. |
IdempotenceException |
409 |
Conflict |
Your request resulted in a conflict. Either you submitted a duplicate request or you're trying to create something with a duplicate key. |
ReferenceException |
500 |
Internal Server Error |
Something went wrong on the Worldline platform. |
PlatformException |
502 |
Bad Gateway |
The Worldline platform was unable to process a message from a downstream partner/acquirer. |
PlatformException |
503 |
Service Unavailable |
The service that you're trying to reach is temporary unavailable.
|
PlatformException |
other |
Unexpected error |
An unexpected error has occurred |
ApiException |
HTTP status code 401 responses are automatically handled by the SDK and will not result in an exception if your OAuth2 credentials are valid. The SDK will automatically try to renew the access token if it gets such a response.
Logging
The .NET SDK supports logging of requests, responses and exceptions of the API communication.
In order to start using the logging feature, an implementation of the ICommunicatorLogger interface should be provided. The SDK provides two example implementations for logging to System.Console ( SystemConsoleCommunicatorLogger ) and logging to an NLog logger ( NLogCommunicatorLogger ).
Logging can be enabled by calling the EnableLogging method on a Client object, and providing the logger as an argument. The logger can subsequently be disabled by calling the DisableLogging method.
When logged messages contain sensitive data, this data is obfuscated.
The following code exemplifies the use of adding a logger:
Client client = Factory.CreateClient("oauth2ClientId", "oauth2ClientSecret");
CommunicatorLogger logger = new NLogLogger(Logger.GetCurrentClassLogger(), Level.Info);
client.EnableLogging(logger);
//... Do some calls
client.DisableLogging();
SSL issues
When using the SDK, you may encounter the following message: Could not create SSL/TLS secure channel. The reason is that the SDK, in accordance to Transport Layer Security (TLS) best practices with the .NET Framework , does not specify the TLS version. It instead lest the OS decide on the TLS version. Please refer to the TLS best practices page for more information on how to configure your system.
Advanced use: Connection pooling
A Client created using the Factory class from your app.config or web.config or CommunicatorConfiguration object will use its own connection pool. If multiple clients should share a single connection pool, the Factory class should be used to first create a shared Communicator , then to create Client instances that use that Communicator :
Communicator communicator = Factory.CreateCommunicator("oauth2ClientId", "oauth2ClientSecret");
// create one or more clients using the shared communicator
Client client = Factory.CreateClient(communicator);
Instead of closing these Client instances, you should instead close the Communicator when it is no longer needed. This will close all Client instances that use the Communicator .
If instead, one of the Client instances is closed, the Communicator will be closed as well. As a result, all other Client instances that use the Communicator will also be closed. Attempting to use a closed Client or Communicator will result in an error.
Just like Client , Communicator implements System.IDisposable , and can therefore also be used in using statements.
Connection management
Just like Client , Communicator also has method CloseExpiredConnections that can be used to evict expired HTTP connections. You can call this method on the Communicator instead of on any of the Client instances. The effect will be the same.
Advanced use: Customization of the communication
A Client uses a Communicator to communicate with the RESTful Server API. A Communicator contains all the logic to transform a request object to a HTTP request and a HTTP response to a response object. If needed, you can extend this class. To instantiate a Client that uses your own implementation of Communicator you can use the following code snippet:
Communicator communicator = new YourCommunicator();
Client client = Factory.CreateClient(communicator);
However, for most customizations you do not have to extend Communicator . The functionality of the Communicator is built on the following:
The RESTful Server API endpoint URI.
An IConnection , which represents one or more HTTP connections to the Worldline server.
An IAuthenticator , which is used to sign your requests.
A MetadataProvider , which constructs the header with metadata of your server that is sent in requests for BI and fraud prevention purposes.
An IMarshaller , which is used to marshal and unmarshal request and response objects to and from JSON.
For your convenience, a CommunicatorBuilder is provided to easily replace one or more of these components. For example, to instantiate a Client that uses your own implementation of Connection , you can use the following code snippet:
Connection connection = new YourConnection();
Communicator communicator = Factory.createCommunicatorBuilder("oauth2ClientId", "oauth2ClientSecret")
.WithConnection(connection)
.Build();
Client client = Factory.CreateClient(communicator);
Logging
To facilitate implementing logging in a custom Connection , the SDK provides utility classes RequestLogMessageBuilder and ResponseLogMessageBuilder . These can be used to easily construct request and response messages. For instance:
// In the below code, logger is the CommunicatorLogger set using enableLogging.
// Note that it may be null if enableLogging is not called.
string requestId = Guid.NewGuid().ToString();
RequestLogMessageBuilder requestLogMessageBuilder =
new RequestLogMessageBuilder(requestId, method, uri);
// add request headers to requestLogMessageBuilder
// if present, set the request body on requestLogMessageBuilder
logger.Log(requestLogMessageBuilder.Message);
// send the request
int statusCode = ...;
ResponseLogMessageBuilder responseLogMessageBuilder =
new ResponseLogMessageBuilder(requestId, statusCode);
// add response headers to responseLogMessageBuilder
// if present, set the response body on responseLogMessageBuilder
logger.Log(responseLogMessageBuilder.Message);
Notes
Renaming of properties
The .NET SDK uses .NET Capitalization Conventions . As a result, the first letter of each property is turned into upper case. For example, cardNumber is called CardNumber .
Because the C# compiler does not support classes that contain properties of the same name, the property could be renamed in a few cases. An example could be property products of class Products , which is turned into ListOfProducts .