Platform API: Support for Dependency Injection in the Credit Card Processing Framework
In MYOB Acumatica 2026.1.1, the credit card processing framework has been refactored to support constructor-based dependency injection (DI) for payment plug-ins. This refactoring gives you modern tools for creating more efficient, modular, and testable integrations.
The Big Picture
Previously, credit card processing plug-ins relied on the ServiceLocator
pattern to resolve dependencies. These approaches limited testability and made plug-ins
harder to maintain. The following code shows an example of such an approach.
protected async Task<HttpResponseMessage> ExecuteAsync(HttpRequestMessage request)
{
using (var client = ServiceLocator.Current
.GetInstance<IHttpClientFactory>().CreateClient())
{
var response = await client.SendAsync(request);
return response;
}
}
In Version 2026.1.1, the new framework replaces this pattern with constructor-based dependency injection. As a result, you can implement payment integrations that are scalable and DI-friendly.
Dependency Injection for Plug-In Creation
Plug-in dependencies are now injected directly through constructors. Instead of resolving
plug-ins through ServiceLocator, the framework resolves them through a
factory managed by the DI container.
To create a plug-in object, the framework provides a plug-in factory called CCProcessingPluginFactory in the PX.Objects.CC.Factories namespace. In its constructor, a dictionary of all registered plug-in types is injected, and an instance of a plug-in is received by the plug-in's fully qualified type name. You can use this factory when you need to create plug-in instances explicitly.
The following code snippet shows the implementation of the plug-in factory.
public class CCProcessingPluginFactory: ICCProcessingPluginFactory
{
private readonly IIndex<string, ICCProcessingPlugin> _pluginIndex;
public CCProcessingPluginFactory(IIndex<string,
ICCProcessingPlugin> pluginIndex)
{
_pluginIndex =
pluginIndex ?? throw new ArgumentNullException(nameof(pluginIndex));
}
public ICCProcessingPlugin CreatePluginForProcessingCenter
(CCProcessingCenter processingCenter)
{
try
{
Type pluginType =
CCPluginTypeHelper.GetPluginTypeWithCheck(processingCenter);
return CreatePluginForPluginType(pluginType.FullName);
}
catch (PXException)
{
throw;
}
catch (Exception ex)
{
throw new PXException(ex,
AR.Messages.ERR_ProcessingCenterTypeInstanceCreationFailed,
processingCenter.ProcessingTypeName,
processingCenter.ProcessingCenterID);
}
}
public ICCProcessingPlugin CreatePluginForPluginType(
string pluginTypeFullName)
{
if (string.IsNullOrEmpty(pluginTypeFullName))
{
throw new ArgumentNullException(nameof(pluginTypeFullName));
}
if (!_pluginIndex.TryGetValue(pluginTypeFullName,
out ICCProcessingPlugin plugin))
{
throw new PXException(
AR.Messages.ERR_ProcessingCenterTypeInstanceCreationFailed,
pluginTypeFullName, "Unknown");
}
return plugin;
}
}
Plug-In Registration
The system automatically registers all plug-ins as services in the DI container. So if you develop a new plug-in, no additional registration steps are required.
To register plug-in types, the system checks available assemblies (by using the
PXProviderTypeSelectorAttribute.GetTypesImplementing method) for
implementations of the CCProcessingBase.Interfaces.V2.ICCProcessingPlugin
interface. The system then registers every type as a named service. The following code shows
an example.
using System;
using Autofac;
using PX.CCProcessingBase.Interfaces.V2;
using PX.CCProcessingBase.Logging.V2;
using PX.Objects.CC.Factories;
using PX.Objects.Common;
namespace PX.Objects.AR.CCPaymentProcessing
{
internal class ServiceRegistration : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<CCProcessingPluginFactory>()
.As<ICCProcessingPluginFactory>().SingleInstance();
foreach (var type in PXProviderTypeSelectorAttribute
.GetTypesImplementing(typeof(ICCProcessingPlugin)))
{
builder.RegisterType(type)
.Named<ICCProcessingPlugin>(type.FullName);
}
builder.RegisterDecorator<
LoggingProcessingPlugin, ICCProcessingPlugin>();
}
}
}
Note that this approach works for both built-in plug-ins and third-party plug-ins delivered as part of a customization project.
Key Changes
- Credit card processing is now fully DI-enabled.
- The
ServiceLocatorpattern usages have been replaced with constructor-based dependency injection. -
The
CCProcessingPluginFactoryis used for safe, DI-driven plug-in instantiation.
Upgrade Notes
As a result of the credit card processing framework being refactored to support dependency injection, changes have been made to some data access classes (DACs) and methods.
The PX.Objects.CA.PXProviderTypeSelectorAttribute.ProviderRec DAC has been replaced with PX.Objects.Common.PXProviderTypeSelectorAttribute.ProviderRec.
The following methods have been replaced:
- In the PX.Objects.AR.CCPaymentProcessing.CardsSynchronization namespace:
- CCSynchronizeCardManager.ctor(PXGraph, String, CreditCardReceiverFactory) with CCSynchronizeCardManager.ctor(PXGraph, String, CreditCardReceiverFactory, ICCProcessingPluginFactory)
- In the PX.Objects.AR.CCPaymentProcessing namespace:
- CCCustomerInformationManager.GetCreatePaymentProfileForm(PXGraph, ICCPaymentProfileAdapter) with CCCustomerInformationManager.GetCreatePaymentProfileForm(PXGraph, ICCPaymentProfileAdapter, ICCProcessingPluginFactory)
- CCCustomerInformationManager.GetNewPaymentProfiles(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter) with CCCustomerInformationManager.GetNewPaymentProfiles(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter, ICCProcessingPluginFactory)
- CCCustomerInformationManager.GetManagePaymentProfileForm(PXGraph, ICCPaymentProfile) with CCCustomerInformationManager.GetManagePaymentProfileForm(PXGraph, ICCPaymentProfile, ICCProcessingPluginFactory)
- CCCustomerInformationManager.ProcessProfileFormResponse(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter, String) with CCCustomerInformationManager.ProcessProfileFormResponse(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter, ICCProcessingPluginFactory, String)
- CCCustomerInformationManager.GetOrCreatePaymentProfile(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter) with CCCustomerInformationManager.GetOrCreatePaymentProfile(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter, ICCProcessingPluginFactory)
- CCCustomerInformationManager.GetPaymentProfile(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter) with CCCustomerInformationManager.GetPaymentProfile(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter, ICCProcessingPluginFactory)
- CCCustomerInformationManager.DeletePaymentProfile(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter) with CCCustomerInformationManager.DeletePaymentProfile(PXGraph, ICCPaymentProfileAdapter, ICCPaymentProfileDetailAdapter, ICCProcessingPluginFactory)
- CCCustomerInformationManager.GetCustomerProfile(PXGraph, String, String) with CCCustomerInformationManager.GetCustomerProfile(PXGraph, String, String, ICCProcessingPluginFactory)
- CCCustomerInformationManager.ctor(ProcessingCardsPluginFactory) with CCCustomerInformationManager.ctor(Object)
- In the PX.Objects.AR.CCPaymentProcessing.Helpers namespace:
- CCPluginTypeHelper.GetProcessor<T>(CCProcessingCenter, ICardProcessingReadersProvider, CCProcessingFeature) with CCPluginTypeHelper.GetProcessor<T>(Object, ICardProcessingReadersProvider, CCProcessingFeature)
- CCProcessingFeatureHelper.IsPaymentHostedFormSupported(CCProcessingCenter) with CCProcessingFeatureHelper.IsPaymentHostedFormSupported(CCProcessingCenter, ICCProcessingPluginFactory)
- CCProcessingHelper.CCProcessingCenterNeedsExpDateUpdate(PXGraph, CCProcessingCenter) with CCProcessingHelper.CCProcessingCenterNeedsExpDateUpdate(PXGraph, CCProcessingCenter, ICCProcessingPluginFactory)
- CCProcessingHelper.GetTokenizedPMsString(PXGraph) with CCProcessingHelper.GetTokenizedPMsString(PXGraph, ICCProcessingPluginFactory)
Note that the CCProcessingFeatureHelper class is static now.
- In the PX.Objects.CA namespace:
- PXProviderTypeSelectorAttribute.GetProviderRecs(Type[]) has been replaced with PXProviderTypeSelectorAttribute.GetProviderRecs(Type[]), which is now available in the PX.Objects.Common namespace.
- PXProviderTypeSelectorAttribute+ProviderRec.ctor() has been replaced with PXProviderTypeSelectorAttribute+ProviderRec.ctor(), which is now available in the PX.Objects.Common namespace.
- In the PX.Objects.CC.PaymentProcessing namespace, the following
methods have been replaced:
- Level3Processing.ctor() with Level3Processing.ctor(ICCProcessingPluginFactory)
- Level3Processing.ctor(ICCPaymentProcessingRepository) with Level3Processing.ctor(ICCPaymentProcessingRepository, ICCProcessingPluginFactory)
- MobileTerminalProcessing.ctor(PXGraph, IAuthorizationManager, IApplicationManager) with MobileTerminalProcessing.ctor(PXGraph, IAuthorizationManager, IApplicationManager, ICCProcessingPluginFactory)
- PayLinkProcessing.ctor(ICCPaymentProcessingRepository) with PayLinkProcessing.ctor(ICCPaymentProcessingRepository, ICCProcessingPluginFactory)
- PaymentTransactionGraph<TGraph, TPrimary>.GetClassMethodName() with PaymentTransactionGraph<TGraph, TPrimary>.GetClassMethodName(String)
The following methods have been removed:
- In the PX.Objects.AR.CCPaymentProcessing.Helpers namespace:
- CCPluginTypeHelper.CreatePlugin(CCProcessingCenter)
- CCProcessingFeatureHelper.ctor()
