抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

开发流程

  1. 创建预订单,同时传递回调地址参数
  2. 订单创建成功后返回一个 URL 地址
  3. 将 URL 地址生成二维码显示在用户界面
  4. 执行扫码支付
  5. 后台执行回调事件,更改订单状态,同时返回通知给微信服务端

接入准备

请参考:

开发平台

.Net 微信第三方 SDK 这里选用 SKIT.FlurlHttpClient.Wechat,其它类似的还有盛派微信 SDK(Senparc.Weixin),SKIT.FlurlHttpClient.Wechat 官方文档是这样介绍的:基于 Flurl.Http 的微信 API HTTP 客户端,支持公众平台、开放平台、商户平台、企业微信、广告平台、对话开放平台等模块。

特性:

  • 基于 Flurl.Http,可与 IHttpClientFactory 集成。
  • 支持 .NET Framework 4.6.1+、.NET Standard 2.0+、.NET Core 2.0+、.NET 5、.NET 6。
  • 支持 Windows / Linux / macOS 多平台部署。
  • 支持 System.Text.Json(默认)和 Newtonsoft.Json 两种序列化方式。
  • 异步式编程。
  • 强类型接口模型。
  • 提供拦截器功能。
  • 包含 SourceLink 符号文件,可在项目中无源代码调试。
  • 完整、完善、完全的微信 API 封装。

安装

如果使用 Visual Studio NuGet 管理器图形化界面,请在搜索结果中勾选“包括预发行版”。

# 通过 NuGet 安装
> Install-Package SKIT.FlurlHttpClient.Wechat.TenpayV3

# 通过 dotnet-tools 安装
> dotnet add package SKIT.FlurlHttpClient.Wechat.TenpayV3

配置

配置 Client 实例:

internal class WechatPayClients
{
    public static readonly WechatTenpayClient Instance;
    static WechatPayClients()
    {
        var certificateManager = new SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings.InMemoryCertificateManager();
        Instance = new WechatTenpayClient(new WechatTenpayClientOptions()
        {
            MerchantId = "",
            MerchantV3Secret = "",
            MerchantCertificateSerialNumber = "",
            MerchantCertificatePrivateKey =System.IO.File.ReadAllText("apiclient_key.pem"), 
            PlatformCertificateManager = certificateManager,
            AutoEncryptRequestSensitiveProperty = true,
            AutoDecryptResponseSensitiveProperty = true,
        });
    }

    internal static async Task InitializeCertificateManagerAsync()
    {
        var request = new SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.QueryCertificatesRequest();
        var response = await Instance.ExecuteQueryCertificatesAsync(request);

        response = Instance.DecryptResponseSensitiveProperty(response);
        foreach (var certificateModel in response.CertificateList)
        {
            Instance.PlatformCertificateManager.AddEntry(new SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings.CertificateEntry(certificateModel));
        }
    }
}

MerchantId、MerchantV3Secret、MerchantCertificateSerialNumber 和 MerchantCertificatePrivateKey 这几个参数均为第 1 步“接入准备”中获取的。

API接口

创建预订单

public async Task CreatePrePayOrder()
{
    var request = new CreatePayTransactionNativeRequest()
    {
        OutTradeNumber = "or123456",    //生成订单号
        AppId = "",    //配置AppId
        Description = "Payment for or123456",//订单描述,显示在支付界面
        ExpireTime = DateTime.Now.AddMinutes(15),    //过期时间
        NotifyUrl = "https://www.zerow.cn/notification",    //回调地址,需外网可以访问
        Amount = new CreatePayTransactionNativeRequest.Types.Amount()
        {
            Total = 100    //支付金额,单位为“分”
        },

    };
    var response= await WechatPayClients.Instance.ExecuteCreatePayTransactionNativeAsync(request);
    if (response.IsSuccessful())
    {
        //返回支付二维码链接,类似:weixin://wxpay/bizpayurl?pr=p4lpSuKzz,需将该链接生成二维码供用户扫码
        Console.WriteLine($"QRCode URL:{response.QrcodeUrl}");
    }
    else
    {
        Console.WriteLine($"错误代码:{response.ErrorCode}");
        Console.WriteLine($"错误描述:{response.ErrorMessage}");
    }
}

官方支付成功回调,SDK 已实现解密:

{
    "id": "xxxx-xxxx-xxxx-xxxx",
    "create_time": "2022-04-25T17:04:47+08:00",
    "resource_type": "encrypt-resource",
    "event_type": "TRANSACTION.SUCCESS",
    "summary": "支付成功",
    "resource": {
        "original_type": "transaction",
        "algorithm": "AEAD_AES_256_GCM",
        "ciphertext": "xxxxxx",
        "associated_data": "transaction",
        "nonce": "xxxxxx"
    }
}

支付回调

创建订单的请求参数中提供了 NotifyUrl 回调地址参数,所以需要有一个回调函数:

public async Task PrePayCallback()
{
    //回调签名验证
    var sr= new StreamReader(Request.InputStream, Encoding.UTF8);
    bool valid = WechatPayClients.Instance.VerifyEventSignature(
        callbackTimestamp: Request.Headers.GetValues("Wechatpay-Timestamp").First(),
        callbackNonce: Request.Headers.GetValues("Wechatpay-Nonce").First(),
        callbackBody: sr.ReadToEnd(),
        callbackSignature: Request.Headers.GetValues("Wechatpay-Signature").First(),
        callbackSerialNumber: Request.Headers.GetValues("Wechatpay-Serial").First(), out Exception e
    );
    var callbackModel = WechatPayClients.Instance.DeserializeEvent(sr.ReadToEnd());
    var callbackResource = WechatPayClients.Instance.DecryptEventResource<SKIT.FlurlHttpClient.Wechat.TenpayV3.Events.TransactionResource>(callbackModel);
    //验证成功
     if (valid)
     {
         //交易成功
        if ("TRANSACTION.SUCCESS".Equals(callbackModel.EventType))
        {
            //获取交易数据
            Console.WriteLine(callbackResource.TransactionId);
            Console.WriteLine(callbackResource.OutTradeNumber);
        }
     }
}     

查询交易状态

public async Task QueryTransactionStatus(string outTradeNumber)
{
    var request = new GetPayTransactionByOutTradeNumberRequest()
    {
        OutTradeNumber = outTradeNumber
    };
    var response = await WechatPayClients.Instance.ExecuteGetPayTransactionByOutTradeNumberAsync(request);
    if (response.IsSuccessful())
    {
        //交易状态
        Console.WriteLine(response.TradeState);
        Console.WriteLine(response.TransactionId);
        Console.WriteLine(response.OutTradeNumber);
    }
    else
    {
        Console.WriteLine(response.ErrorMessage);
    }
}

查询交易状态 API:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_2.shtml

交易状态枚举值:
SUCCESS:支付成功
REFUND:转入退款
NOTPAY:未支付
CLOSED:已关闭
REVOKED:已撤销(仅付款码支付会返回)
USERPAYING:用户支付中(仅付款码支付会返回)
PAYERROR:支付失败(仅付款码支付会返回)

申请退款

public async Task CreateRefund(string outTradeNumber)
{
    var request = new CreateRefundDomesticRefundRequest()
    {
        OutTradeNumber = outTradeNumber,    //订单号
        OutRefundNumber = "",    //生成退款单号
        Amount = new CreateRefundDomesticRefundRequest.Types.Amount()
        {
            Total = 100,    //原订单金额
            Refund = 100    //退款金额
        },
        Reason = “”    //退款原因
    };
    var response = await WechatPayClients.Instance.ExecuteCreateRefundDomesticRefundAsync(request);
    if(response.IsSuccessful)
    {
        //退款状态
        Console.WriteLine(response.Status);
    }
    else
    {
        Console.WriteLine(response.ErrorMessage);
    }
}

申请退款 API:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_9.shtml

退款状态枚举值:
SUCCESS:退款成功
CLOSED:退款关闭
PROCESSING:退款处理中
ABNORMAL:退款异常

关闭订单

public async Task CloseTransaction(string outTradeNumber)
{
    var request = new ClosePayTransactionRequest()
    {
        OutTradeNumber = outTradeNumber
    };
    var response = await WechatPayClients.Instance.ExecuteClosePayTransactionAsync(request);
    if (!response.IsSuccessful())
    {
        Console.WriteLine(response.ErrorMessage);
    }
}

关闭订单 API:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_3.shtml

参考

评论