Magicodes.Pay Now Supports Volo Abp

Magicodes.Pay now supports Volo Abp

Overview

Magicodes.Pay aims to create a unified payment library, with all libraries written using .NET Standard and supporting both .NET Framework and .NET Core. It currently provides encapsulation for Abp and Abp VNext (Volo Abp) modules, allowing immediate use. GitHub: https://github.com/xin-lai/Magicodes.Pay

Nuget

Name Description Nuget
Magicodes.Pay.Alipay Alipay payment library
Magicodes.Pay.Notify General payment callback library
Magicodes.Pay.Wxpay WeChat payment library
Magicodes.Pay.Alipay.Global Global Alipay payment library
Magicodes.Pay.Allinpay Allinpay payment library
Magicodes.Pay.Abp ABP general payment encapsulation library
Magicodes.Pay.Abp.Allinpay ABP Allinpay module
Magicodes.Pay.Abp.Wxpay ABP WeChat payment module
Magicodes.Pay.Abp.Alipay.Global ABP global Alipay module
Magicodes.Pay.Abp.Alipay ABP Alipay module
Magicodes.Pay.Volo.Abp Volo Abp base module
Magicodes.Pay.Volo.Abp.Allinpay Volo Abp Allinpay module
Magicodes.Pay.Volo.Abp.Wxpay Volo Abp WeChat payment module
Magicodes.Pay.Volo.Abp.Alipay Volo Abp Alipay payment module

Key Features

It currantly provides encapsulation for Abp (including Volo Abp), allowing immediate use. It supports the following payment methods and features:

  • Alipay payments
  • APP payments
  • Wap payments
  • Global Alipay payments
  • Supports profit sharing
  • WeChat payments
  • Mini program payments
  • APP payments
  • Order query
  • Corporate transfer (withdrawal)
  • Refund request
  • Regular red envelopes
  • Allinpay
  • Mini program payments
  • WeChat JSAPI payments
  • Unified payment callback handling
  • Supports logging function injection (not dependent on the payment library)
  • Supports payment configuration function injection, enabling custom configuration logic for different scenarios (e.g., retrieving from configuration files, user settings, or multi-tenant support)
  • For ABP, it provides module encapsulation; adding the module dependency allows immediate usage. This includes:
  • Unified payment service encapsulation (see IPayAppService)
  • Payment manager encapsulation (IPaymentManager), including:
  • Payment channel registration (IPaymentRegister)
  • Payment callback logic handling (IPaymentCallbackAction)
  • Unified payment service implementation (IToPayService)
  • Transaction log encapsulation, automatically recording client information and handling and logging exceptions
  • Only one callback logic needs to be written to support multiple payment channels
  • Business parameters support longer lengths (up to 500)

Getting Started (Volo Abp)

This guide is only applicable to Volo Abp. The main steps are as follows:

  1. Reference the corresponding Abp payment Nuget package

If only one payment method is needed, reference that specific package. Here's an example of referencing the Allinpay package:

Name Description Nuget
Magicodes.Pay.Volo.Abp.Allinpay Volo Abp Allinpay module
  1. Add module dependencies

In the relevant Abp module (AbpModule) in your project, add a dependency on "AbpAllinpayModule", like:

    [DependsOn(typeof(AbpAllinpayModule))]


  1. Add a DbSet named "TransactionLogs" in DbContext

Throughout the payment process (whether successful or not), transaction logs will be recorded. These logs store information such as client details, transaction parameters, custom data, and any exceptions. Therefore, you need to add support for TransactionLog in EF. The complete code to add in DbContext is as follows:

public DbSet<TransactionLog> TransactionLogs { get; set; }


  1. Register callback logic

You need to implement the "IPaymentCallbackAction" interface to write custom callback logic. Each logic requires a separate registration, matched by the business key, such as "payment for fees" or "recharge". Here's an example:

    public class TestPaymentCallbackAction : IPaymentCallbackAction
    {
        /// <summary>
        /// Business Key
        /// </summary>
        public string Key { get; set; } = "payment for fees";

        /// <summary>
        /// Execute the callback
        /// </summary>
        /// <returns></returns>
        public async Task Process(IUnitOfWorkManager unitOfWork, TransactionLog transactionLog)
        {
            var data = transactionLog.CustomData.FromJsonString<JObject>();
            // business processing

            await Task.FromResult(0);
        }
    }


Note: Ensure the Key is unique.

  1. Register the callback logic in the container

If automatic registration does not occur, you can manually register it using the following code:

    context.Services.AddTransient<IPaymentCallbackAction, TestPaymentCallbackAction>();


Alternatively, you can inject the IPaymentManager object and use its RegisterCallbackAction method to register the custom callback logic.

  1. Configure payment parameters

Payment parameters can be configured via a configuration file or SettingManager. Here's an example using a configuration file:

  "Allinpay": {
    "IsEnabled": "true",
    "CusId": "testtest",
    "ApiGateWay": "https://vsp.allinpay.com/apiweb/unitorder",
    "AppKey": "testtesttesttest",
    "AppId": "testtesttesttesttesttest",
    "Version": "11",
    "NotifyUrl": "{domain}/PayNotify/{tenantId?}/{payment provider key}",
    "WeChatAppId": "WeChat mini program app ID",
    "JsApiAppId":"JSAPI payment app ID"
  }


As shown above, the configuration node "Allinpay" corresponds to the provider's key. The keys for various payment providers are as follows:

  • Alipay: Alipay
  • Global Alipay: Global.alipay
  • Allinpay: Allinpay
  • WeChat: Wxpay

Notably, by default, the callback is handled by the "PayNotifyController" in the "Magicodes.Pay.Notify" module. Thus, the callback URL format should be:

{domain}/PayNotify/{tenantId?}/

  1. Initiate Payment

After configuration, you can use the unified IPayAppService to initiate a payment. Simply inject IPayAppService and call the Pay method. You can also further encapsulate it, as shown in the following code:

        public async Task<object> Payment(PaymentInput input)
        {
            return await _payAppService.Pay(new PayInputBase()
            {
                Body = $"{input.Name} {input.ChargeProjectName}",
                CustomData = input.ToJsonString(),
                Key = "payment for fees",
                OpenId = input.OpenId,
                Subject = input.ChargeProjectName,
                TotalAmount = input.Amount,
                PayChannel = input.PayChannel
            });
        }


Using IPayAppService offers several advantages:

  • Unified payment (regardless of whether it's Alipay or WeChat across different platforms)
  • Automatic recording of transaction logs and related processing
  • Custom data is stored based on transaction logs, independent of the payment channel, thus supporting payment channels without business parameters and storing more custom data

Old Abp Integration Guide

If you're using Abp modules, the integration is straightforward. You can refer to the unit tests for guidance. The main steps are as follows:

  1. Reference the corresponding Abp payment Nuget package

If only one payment method is needed, reference that specific package. Here's an example of referencing the Allinpay package:

Name Description Nuget
Magicodes.Pay.Abp.Allinpay Abp Allinpay module
  1. Add module dependencies

In the relevant Abp module (AbpModule) in your project, add a dependency on "AbpAllinpayModule", like:

    [DependsOn(typeof(AbpAllinpayModule))]


  1. Add a DbSet named "TransactionLogs" in DbContext

Throughout the payment process (whether successful or not), transaction logs will be recorded. These logs store information such as client details, transaction parameters, custom data, and any exceptions. Therefore, you need to add support for TransactionLog in EF. The complete code to add in DbContext is as follows:

public DbSet<TransactionLog> TransactionLogs { get; set; }


  1. Register callback logic

You need to implement the "IPaymentCallbackAction" interface to write custom callback logic. Each logic requires a separate registration, matched by the business key, such as "payment for fees" or "recharge". Here's an example:

    public class TestPaymentCallbackAction : IPaymentCallbackAction
    {
        /// <summary>
        /// Business Key
        /// </summary>
        public string Key { get; set; } = "payment for fees";

        /// <summary>
        /// Execute the callback
        /// </summary>
        /// <returns></returns>
        public async Task Process(IUnitOfWorkManager unitOfWork, TransactionLog transactionLog)
        {
            var data = transactionLog.CustomData.FromJsonString<JObject>();
            // business processing

            await Task.FromResult(0);
        }
    }


Note: Insure the Key is unique.

  1. Register the callback logic in the container

You can place the callback logic in a shared assembly and then register it using the following code:

            IocManager.IocContainer.Register(
                // Register custom payment callback logic
                Classes.FromAssembly(typeof(ApplicationCoreModule).GetAssembly())
                    .BasedOn<IPaymentCallbackAction>()
                    .LifestyleTransient()
                    .Configure(component => component.Named(component.Implementation.FullName))
                    .WithServiceFromInterface()
            );


Alternatively, you can inject the IPaymentManager object and use its RegisterCallbackAction method to register the custom callback logic.

  1. Configure payment parameters

Payment parameters can be configured via a configuration file or SettingManager. Here's an example using a configuration file:

  "Allinpay": {
    "IsEnabled": "true",
    "CusId": "testtest",
    "ApiGateWay": "https://vsp.allinpay.com/apiweb/unitorder",
    "AppKey": "testtesttesttest",
    "AppId": "testtesttesttesttesttest",
    "Version": "11",
    "NotifyUrl": "{domain}/PayNotify/{tenantId?}/{payment provider key}",
    "WeChatAppId": "WeChat mini program app ID",
    "JsApiAppId":"JSAPI payment app ID"
  }


As shown above, the configuration node "Allinpay" corresponds to the provider's key. The keys for various payment providers are as follows:

  • Alipay: Alipay
  • Global Alipay: Global.alipay
  • Allinpay: Allinpay
  • WeChat: Wxpay

Notably, by default, the callback is handled by the "PayNotifyController" in the "Magicodes.Pay.Notify" module. Thus, the callback URL format should be:

{domain}/PayNotify/{tenantId?}/

  1. Initiate Payment

After configuration, you can use the unified IPayAppService to initiate a payment. Simply inject IPayAppService and call the Pay method. You can also further encapsulate it, as shown in the following code:

        public async Task<object> Payment(PaymentInput input)
        {
            return await _payAppService.Pay(new PayInputBase()
            {
                Body = $"{input.Name} {input.ChargeProjectName}",
                CustomData = input.ToJsonString(),
                Key = "payment for fees",
                OpenId = input.OpenId,
                Subject = input.ChargeProjectName,
                TotalAmount = input.Amount,
                PayChannel = input.PayChannel
            });
        }


Using IPayAppService offers several advantages:

  • Unified payment (regardless of whether it's Alipay or WeChat across different platforms)
  • Automatic recording of transaction logs and related processing
  • Custom data is stored based on transaction logs, independent of the payment channel, thus supporting payment channels without business parameters and storing more custom data

Non-ABP Integration

Refer to the encapsulation of the Abp modules or previous code.

Troubleshooting

Check the logs, as most processes have log outputs. During system initialization, registered payment services and callback logic are printed. When a callback occurs, progress is logged. If a payment has been initiated, check the transaction log table in the database to help troubleshoot issues.

Related QQ Groups

Programming Exchange Group<85318032>

Official Blog/Documentation Site

Posted on Mon, 08 Jun 2026 16:36:52 +0000 by shoutdots