The Migration Guide to Upgrading to Adyen .NET Library 10.0.0
Tags: adyen, dotnet, library, sdk
Published: 2023-06-08 15:40:32

This migration guide is intended for developers who are planning to upgrade to **.NET Adyen Library version 10.0.0**. We'll cover new features and breaking changes from **9.x.x** to ensure your upgrade goes as smoothly as possible. 


The new version allows for an easy integration of new products and features as they become available on the Adyen platform, and it introduces naming conventions that are consistent across other libraries and our Adyen endpoints.

The goal is to make the library **comprehensive** (all API versions are updated to the latest release, there is support for Adyen for Platforms and Embedded Financial Services), **fast** (providing built-in methods for JSON processing) and **easy** (added adapter classes mapping each payment method).

> **TL;DR:** In this migration guide, we'll go over what has changed and why we've made these changes to ensure that developers can migrate as smoothly as possible.

## Coding Conventions
The following changes have been implemented to better align with [Microsoft's C# Coding Conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions).

**1. Interface support on service-level**
It's common practice to use names with an `I`-prefix to indicate that they are interfaces. This helps to distinguish interfaces from classes and other types, and makes it clear that the type represents an interface. For example: `IPaymentsService.cs` indicates that the type represents an interface for the _Payments_ API. We've introduced these interfaces in our service classes. Developers can make use of these interfaces, which expose only the set of public methods required for integration purposes.

**2. Service classes**
It's also common practice to suffix classes with `-Service` on service-level. This helps developers distinguish service classes from other classes such as requests, responses, other models and types. For example: Recurring is now renamed to RecurringService, which now inherits from the IRecurringService interface.

**3. Asynchronous methods**
To handle asynchronous requests, we've added the `-Async()`-suffix to all asynchronous methods. On top of that, we allow developers to pass on cancellation tokens to these methods. This enables cooperative cancellation between threads, thread pool work items, or Task objects, freeing up remaining resources if a request is canceled manually or unexpectedly.

**4. HttpClient support**
`System.Net.Http.HttpClient` has replaced [`System.Net.HttpWebRequest`](https://learn.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest?view=net-7.0#remarks) to conform to [Microsoft's best practices](https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines). The `System.Net.Http.HttpClient` class sends and receives HTTP requests and handles these responses from a resource that can be identified by a URI. An `HttpClient` instance consists of a collection of settings that are applied to all requests executed by that instance. Additionally, each instance operates its own connection pool, which isolates its requests from others. Starting in .NET Core 2.1, the The underlying SocketsHttpHandler class provides the implementation, making behavior consistent across all platforms when using the HttpClient.

When creating the AdyenClient, developers can now inject their own `HttpClient` on the constructor level. If a custom `HttpClient` is not provided, a default one will be provided by the `HttpClientFactory`. We have also marked username and password authentication as obsolete to ensure best practices when working with our APIs. Instead, it's recommended to pass the API-Key as part of the `Config` class in the constructor. Here's what the initial client configuration looks like when working with our APIs in .NET:

_Example of using direct object instantiation in C#:_

```csharp
var httpClient = new HttpClient(); // Reuse the HttpClient, see below why.

var adyenClient = new Adyen.Client(
   new Config()
   {
      XApiKey = "ADYEN_API_KEY",
      HmacKey = "ADYEN_HMAC_KEY",
      MerchantAccount = "ADYEN_MERCHANT_ACCOUNT",
      Environment = Environment.Test
 },
   httpClient // Do not instantiate a new one for every request.
);

Adyen.Service.Checkout.IPaymentsService service = new Adyen.Service.Checkout.PaymentsService(adyenClient);
```


_Note:_ Please keep in mind that it's best practice to [reuse the HttpClient](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netframework-4.8#examples). To prevent socket exhaustion, the HttpClient is intended to be instantiated once per application, rather than per-use. We highly recommend using the HttpClientFactory for this reason and have the factory provide the client. You can read more details here on [StackOverflow](https://stackoverflow.com/questions/58427764/httpclient-and-socket-exhaustion-clarification). We recommend the following for Dependency Injection:

_Example instantiation using Dependency Injection in ASP.NET Core:_

```csharp
string httpClientName = "YourCustomHttpClientName";

// Register the Adyen.Client with the HttpClientFactory in ASP.NET Core.

services.AddSingleton(
   new Adyen.Client(
      new Config()
      {
         XApiKey = "ADYEN_API_KEY",,
         HmacKey = "ADYEN_HMAC_KEY",
         MerchantAccount = "ADYEN_MERCHANT_ACCOUNT",
         Environment = Environment.Test
      }, 
      provider.GetRequiredService<IHttpClientFactory>(),
      httpClientName
   )
);

// Add the named HttpClient.
services.AddHttpClient(httpClientName, httpClient =>
{
    /// Customize your HttpClient here.
    //using Microsoft.Net.Http.Headers;
    //httpClient.DefaultRequestHeaders.Add("accept", "application/json");
    //httpClient.DefaultRequestHeaders.Add("user-agent", "YourUserAgent");
});

services.AddSingleton<Adyen.Service.Checkout.IPaymentsService, Adyen.Service.Checkout.PaymentsService>();
```

**5. Models generation from OpenAPI specifications**
Another significant change is the adoption of OpenAPI-driven code generation.

The models are now generated from the latest [OpenAPI specifications](https://github.com/Adyen/adyen-openapi). C# classes that map the request and response payloads are now generated using [OpenAPI Generator](https://openapi-generator.tech/), ensuring that the code complies with the contract, and avoiding errors and inconsistencies. This also ensures that other Ayden libraries will have consistent naming amongst them.

To improve the maintainability of the library easier for the long run, we've removed several properties that are no longer there and reduced boilerplate code. You can find them in our [release notes](https://github.com/Adyen/adyen-dotnet-api-library/releases/tag/10.0.0).

With the automation project, our team at Adyen can now deliver faster to our developers. They can use the latest endpoints when including the latest version of the library in their application.

Feel free to take a look at the following model and service-generation. The following new services and respective endpoints have been generated using the OpenAPI specifications:

## New endpoints support
- [BalancePlatform](https://docs.adyen.com/marketplaces-and-platforms/create-balance-accounts)
- [LegalEntityManagement](https://docs.adyen.com/api-explorer/legalentity/latest/overview)
- [Management](https://docs.adyen.com/api-explorer/Management/1/overview)
- [Transfers](https://docs.adyen.com/api-explorer/transfers/3/overview)
- [StoredValue](https://docs.adyen.com/payment-methods/gift-cards/stored-value-api)
- [BalanceControl](https://docs.adyen.com/api-explorer/BalanceControl/1/overview)
- [Data Protection](https://docs.adyen.com/development-resources/data-protection-api)

## Deprecated
[Hosted Payment Pages (HPP)](https://docs.adyen.com/online-payments/classic-integrations/hosted-payment-pages) has been deprecated and are no longer available. The classic Hosted Payment Pages integration has reached end-of-life and we are no longer processing transactions through HPP.

## Quick Cheat Sheet
Most of the services, some examples "Balance", "Payout" or "BinLookup" have been renamed to "BalanceService", "PayoutService" and "BinLookupService" respectively. Because they're quite straightforward to find when applying the above mentioned naming conventions, they're not listed in the table below.

We've highlighted a couple of commonly used services, models and methods that have been moved, and are less trivial to find.
```csharp
// Before (.NET 9.x.x)
Checkout.cs

// After (.NET 10.x.x) - Renamed
Adyen.Services.Checkout.PaymentsService.cs  // Service
Adyen.Services.Checkout.IPaymentsService.cs // Interface
```

```csharp
// Before (.NET 9.x.x)
Checkout.PaymentLinks(…) // Method

// After (.NET 10.x.x) - This has been moved to its own service
Adyen.Services.Checkout.PaymentLinksService.cs  // Service
Adyen.Services.Checkout.IPaymentLinksService.cs // Interface
```

```csharp
// Before (.NET 9.x.x)
Recurring.cs

// After (.NET 10.x.x) - Renamed
Adyen.Services.RecurringService.cs  // Service
Adyen.Services.IRecurringService.cs // Interface
```

```csharp
// Before (.NET 9.x.x)
Checkout.PaymentsAsync(…) method

// After (.NET 10.x.x)
// Adyen.Model.Checkout.PaymentRequest contains a PaymentMethod parameter.
// When making a payment, using the recurringDetailReference retrieved from tokenization, use: 
PaymentMethod = new CheckoutPaymentMethod(new StoredPaymentMethodDetails(storedPaymentMethodId: recurringDetailReference));
```

```csharp
// Before (.NET 9.x.x)
Adyen.Model.Checkout.Details.IPaymentMethodDetails

// After (.NET 10.x.x) - Have a look at our .NET checkout-example-advanced flow 
// on github.com/adyen-examples to see how you can pass this as part of its request.
Adyen.Model.Checkout.CheckoutPaymentMethod
```

```csharp
// Before (.NET 9.x.x)
namespace Adyen.Model.Enum.Environment

// After (.NET 10.x.x) - Moved to another namespace
namespace Adyen.Model.Environment
```

```csharp
// Before (.NET 9.x.x)
Adyen.Model.Checkout.PaymentsDetailsRequest.cs

// After (.NET 10.x.x) - Renamed
// This will be correctly renamed to PaymentDetailsRequest in a later release
// A `PaymentDetailRequest` model should have an equivalent `PaymentDetailResponse` for consistency
Adyen.Model.Checkout.DetailsRequest.cs
```

```csharp
// Before (.NET 9.x.x)
new Adyen.Client(username, password, environment) // or
new Adyen.Client(xapikey, environment)

// After (.NET 10.x.x)
var httpClient = new HttpClient(); // Reuse the HttpClient, we explained the why above.

var client = new Client(
   new Config()
   {
      XApiKey = "ADYEN_API_KEY",
      HmacKey = "ADYEN_HMAC_KEY",
      MerchantAccount = "ADYEN_MERCHANT_ACCOUNT",
      Environment = Environment.Test
 },
   httpClient // Do not instantiate a new one for every request.
);

var adyenClient = new Adyen.Client(config);
```

```csharp
// Before (.NET 9.x.x)
Adyen.Service.PosPaymentLocalApi
Adyen.Service.PosPaymentCloudApi

// After (.NET 10.x.x) - Using POS with HttpClient:
var httpClient = new HttpClient(
   // See Adyen.HttpClient.HttpClientExtension.cs to configure the certificate.
   HttpClientExtensions.ConfigureHttpMessageHandler(config)
); 

// You can also  optionally configure your HttpClient timeouts here.
// httpClient.Timeout = …;

IPosPaymentLocalApi = new PosPaymentLocalApi(new Client(config, httpClient)); // or
IPosPaymentCloudApi = new PosPaymentCloudApi(new Client(config, httpClient));
```

```csharp
// After (.NET 10.x.x) - Setting Local Terminal API endpoint
new Config() {
   // ...
   LocalTerminalApiEndpoint = "https://192.168.1.10:8443/nexo"
   // ...
}
```

If you have an existing integration implementing one of the _Checkout_ (sessions / payments endpoints), _Subscription_ (tokenization), _Pay by Link_ or _Gift Card_ use cases, you can have a look at the [this pull request](https://github.com/adyen-examples/adyen-dotnet-online-payments/pull/80/files) to see a detailed list of all changes necessary to migrate to v10.0.0.

Feel free to open an issue on GitHub if you're encountering any problems or ping us on [Twitter (@AdyenDevs)](https://twitter.com/AdyenDevs).

Happy migration! 🛠️