Summary
The Nop.Plugin.Payments.PayPalCommerce plugin currently uses a custom HttpClient-based implementation to interact with PayPal REST APIs. This involves manually constructing HTTP requests, handling OAuth2 authentication, serializing/deserializing JSON payloads, and parsing error responses.
PayPal now provides an official .NET SDK (PayPalServerSDK) that handles all of this out of the box. Migrating to the official SDK would improve maintainability, security, and alignment with PayPal's recommended best practices.
Motivation
- Maintainability: The current implementation manually builds HTTP requests, manages access tokens, and parses error responses. The official SDK abstracts all of this, reducing the surface area for bugs.
- Security: The SDK handles OAuth2 client credentials flow internally, eliminating the need to manually manage and cache access tokens.
- Alignment with PayPal best practices: Using the official SDK ensures the plugin stays compatible with PayPal API changes and follows their recommended integration patterns.
- Reduced code complexity: Error handling, request serialization, and authentication are all managed by the SDK.
Proposed Changes
Architecture
Use an adapter pattern inside PayPalCommerceHttpClient to route supported operations through the official SDK while preserving the existing RequestAsync<TRequest, TResponse> interface. This ensures zero changes are needed in PayPalCommerceServiceManager (~3700 lines) or any other consumers.
SDK-Routed Operations
- Orders: Create, Get, Patch, Authorize, Capture, Tracking
- Payments: Capture Authorization, Void, Refund
- Vault: Create Setup Token, Create/Get/List/Delete Payment Tokens
HTTP-Fallback Operations (not available in the SDK)
- Webhooks (create, list, delete, verify signature)
- Identity/Access Tokens
- Onboarding Credentials
Files to Change
| File |
Change |
Nop.Plugin.Payments.PayPalCommerce.csproj |
Add PayPalServerSDK v2.0.0 NuGet package, enable CopyLocalLockFileAssemblies |
Services/PayPalSdkClientFactory.cs |
New file — thread-safe factory that caches PaypalServerSdkClient instances per credential/environment |
Services/PayPalCommerceHttpClient.cs |
Rewrite as adapter — route supported request types through SDK, fall back to direct HTTP for the rest |
Infrastructure/NopStartup.cs |
Register PayPalSdkClientFactory as singleton; remove PayPal SDK assembly from MVC ApplicationPartManager to prevent Autofac conflicts |
Important: Autofac Compatibility
The PayPal SDK assembly contains types named BaseController, OrdersController, PaymentsController, etc. NopCommerce loads all plugin reference DLLs as MVC ApplicationPart entries. When AddControllersAsServices() runs, MVC's naming convention discovers these SDK types and Autofac attempts to register them — but BaseController only has an internal constructor, causing a NoConstructorsFoundException at startup.
The fix is to remove the PayPalServerSDK assembly from ApplicationPartManager.ApplicationParts in the plugin's NopStartup.ConfigureServices, which runs before AddControllersAsServices.
Model Conversion Approach
Both the internal plugin models and the SDK models use Newtonsoft.Json with [JsonProperty] attributes that map to the same PayPal REST API JSON schema. This enables a reliable JSON round-trip conversion (serialize internal model → JSON → deserialize to SDK model, and vice versa) without needing explicit property-by-property mapping code.
Acceptance Criteria
Summary
The
Nop.Plugin.Payments.PayPalCommerceplugin currently uses a customHttpClient-based implementation to interact with PayPal REST APIs. This involves manually constructing HTTP requests, handling OAuth2 authentication, serializing/deserializing JSON payloads, and parsing error responses.PayPal now provides an official .NET SDK (PayPalServerSDK) that handles all of this out of the box. Migrating to the official SDK would improve maintainability, security, and alignment with PayPal's recommended best practices.
Motivation
Proposed Changes
Architecture
Use an adapter pattern inside
PayPalCommerceHttpClientto route supported operations through the official SDK while preserving the existingRequestAsync<TRequest, TResponse>interface. This ensures zero changes are needed inPayPalCommerceServiceManager(~3700 lines) or any other consumers.SDK-Routed Operations
HTTP-Fallback Operations (not available in the SDK)
Files to Change
Nop.Plugin.Payments.PayPalCommerce.csprojPayPalServerSDKv2.0.0 NuGet package, enableCopyLocalLockFileAssembliesServices/PayPalSdkClientFactory.csPaypalServerSdkClientinstances per credential/environmentServices/PayPalCommerceHttpClient.csInfrastructure/NopStartup.csPayPalSdkClientFactoryas singleton; remove PayPal SDK assembly from MVCApplicationPartManagerto prevent Autofac conflictsImportant: Autofac Compatibility
The PayPal SDK assembly contains types named
BaseController,OrdersController,PaymentsController, etc. NopCommerce loads all plugin reference DLLs as MVCApplicationPartentries. WhenAddControllersAsServices()runs, MVC's naming convention discovers these SDK types and Autofac attempts to register them — butBaseControlleronly has an internal constructor, causing aNoConstructorsFoundExceptionat startup.The fix is to remove the
PayPalServerSDKassembly fromApplicationPartManager.ApplicationPartsin the plugin'sNopStartup.ConfigureServices, which runs beforeAddControllersAsServices.Model Conversion Approach
Both the internal plugin models and the SDK models use
Newtonsoft.Jsonwith[JsonProperty]attributes that map to the same PayPal REST API JSON schema. This enables a reliable JSON round-trip conversion (serialize internal model → JSON → deserialize to SDK model, and vice versa) without needing explicit property-by-property mapping code.Acceptance Criteria