C#

简介

为了提高客户的接入体验,特提供封装的开发SDK,使用本SDK将极大的简化开发者的工作,开发者将无需考虑通信、签名、验签等,只需要关注业务参数的拼装。

下载地址

SDK下载

版本记录

版本 日期 版本说明
v1.0.0 2021/05/20 初始版本

版本要求

.Net Framework 4.0以上

接入方法

下载 SDK

下载文件里包含 sdk 、 libs 、 BasePayDemo 三个目录。sdk 目录下为待添加到项目中的sdk依赖库,libs 目录下为需要的第三方依赖库, BasePayDemo 目录下为示例项目,供接入时参考使用。

添加 SDK 引用

BasePaySdk.dll

导入第三方依赖库

接入本 SDK 需依赖以下第三方库,参考 libs 文件夹下提供的 dll 文件

Newtonsoft.Json
BouncyCastle.Crypto

使用方法

系统初始化

在使用 SDK 调用汇付接口前,请先进行商户配置,否则可能导致交易异常。

正常情况下只有一套商户配置,如有业务需求向汇付申请了多套配置信息,也可配置多个商户配置,并做好商户配置命名管理,配置名必须唯一

调用示例

// 是否调试模式,默认为false,调试模式会打印调试信息,供开发联调时使用
BasePay.debug = false;
// 是否生产模式,默认为true
BasePay.prodMode = true;

// 单套商户配置
// 配置key默认为default,上送报文时无需指定配置key
MerConfig config = new MerConfig();
config.ProductId = DemoConstants.DEMO_PRODUCT_ID;
config.SysId = DemoConstants.DEMO_SYS_ID;
config.RsaPrivateKey = DemoConstants.RSA_PRIVATE_KEY;
config.RsaPublicKey = DemoConstants.RSA_PUBLIC_KEY;
BasePay.initWithMerConfig(config);

// 下面示例为多套商户配置的情形
// 如商户因特殊需要,申请多套配置,则需自行做好配置管理,上送报文时需明确指定使用哪套商户配置
Dictionary<string, MerConfig> configs = new Dictionary<string, MerConfig>();
MerConfig config1 = new MerConfig();
config1.ProductId = DemoConstants.DEMO_PRODUCT_ID1;
config1.SysId = DemoConstants.DEMO_SYS_ID1;
config1.RsaPrivateKey = DemoConstants.RSA_PRIVATE_KEY1;
config1.RsaPublicKey = DemoConstants.RSA_PUBLIC_KEY1;
// 多套配置的key自行指定,保持唯一即可
configs.Add("merchantKey1", config1);

MerConfig config2 = new MerConfig();
config2.ProductId = DemoConstants.DEMO_PRODUCT_ID2;
config2.SysId = DemoConstants.DEMO_SYS_ID2;
config2.RsaPrivateKey = DemoConstants.RSA_PRIVATE_KEY2;
config2.RsaPublicKey = DemoConstants.RSA_PUBLIC_KEY2;
// 多套配置的key自行指定,保持唯一即可
configs.Add("merchantKey2", config2);
BasePay.initWithMerConfigs(configs);

接口调用

接口调用均由 BasePayClient.postRequest 方法发起,上传文件接口由 BasePayClient.postRequestFile 方法发起

/// <summary>
/// 发送报文请求
/// </summary>
///
/// <param name="funcCode">功能编码</param>
/// <param name="requestParams">请求报文</param>
/// <param name="merchantKey">商户配置key</param>
///
/// <returns>返回报文</returns>
///
public static Dictionary<string, object> postRequest(string funcCode, Dictionary<string, object> requestParams, string merchantKey = "default");

/// <summary>
/// 上传文件请求
/// </summary>
///
/// <param name="funcCode">功能编码</param>
/// <param name="requestParams">请求报文</param>
/// <param name="filePath">上传文件路径</param>
/// <param name="merchantKey">商户配置key</param>
///
/// <returns>返回报文</returns>
///
public static Dictionary<string, object> postRequestFile(string funcCode, Dictionary<string, object> requestParams, string filePath, string merchantKey = "default");

requestParams 为请求报文体BODY中的 data - 「接口规则-参数规定-报文体」 ,需根据调用接口的API说明组装参数。

funcCode 为请求接口的功能编码,请参考 交易接口功能编码商户管理接口功能编码

filePath 为文件上传时文件所在路径。

merchantKey 为上一步初始化时配置的商户配置key。

接口调用实例

以下以聚合反扫接口为例,展示如何使用 SDK 来调用接口。

DateTime dt = DateTime.Now;
string nowStr = DateTime.Now.ToString("yyyyMMddHHmmss");
string nowDate = DateTime.Now.ToString("yyyyMMdd");
string reqSeqId = nowStr + "01234567890";
// merOrdId = nowStr + "1234567890";
string merOrdId = reqSeqId;
string timeExpire = dt.AddMinutes(2).ToString("yyyyMMddHHmmss");

/**
* 聚合反扫调用实例
**/
Dictionary<string, Object> transParam = new Dictionary<string, Object>();
// 请求流水号,需保证当天商户下唯一,推荐采用日期时间+几位流水号的形式
transParam.Add("req_seq_id", reqSeqId);
// 请求日期,请求接口的日期,因服务器时间可能有差异,允许前后1天
transParam.Add("req_date", nowDate);
// 系统号,由汇付分配
transParam.Add("sys_id", DemoConstants.DEMO_SYS_ID);
// 商户订单号,需保证商户下唯一,推荐采用日期时间+几位流水号的形式,可与req_seq_id相同
transParam.Add("mer_ord_id", merOrdId);
// 分配商户号
transParam.Add("huifu_id", DemoConstants.DEMO_HUIFU_ID);
// 渠道号,若需使用自有渠道请联系业务对接人
transParam.Add("bank_channel_no", "");
// 交易金额
transParam.Add("trans_amt", "0.02");
// 商品描述
transParam.Add("goods_desc", "测试商品");
// 支付二维码
transParam.Add("auth_code" , "用户展示的付款二维码");
// 设备信息
Dictionary<string, Object> terminalDeviceInfo = new Dictionary<string, Object>();
terminalDeviceInfo.Add("device_type", "4");
terminalDeviceInfo.Add("device_ip", "139.207.19.246");
transParam.Add("terminal_device_info", terminalDeviceInfo);

// 风控信息
Dictionary<string, Object> riskCheckInfo = new Dictionary<string, Object>();
riskCheckInfo.Add("ipAddr", "139.207.19.246");
Dictionary<string, Object> riskMngInfo = new Dictionary<string, Object>();
riskMngInfo.Add("subTradeType" , "4300");
riskCheckInfo.Add("riskMngInfo", riskMngInfo);
// 注意,风控信息为JSON字符串
transParam.Add("risk_check_info", JsonConvert.SerializeObject(riskCheckInfo, Formatting.None));

// 异步通知地址
transParam.Add("notify_url" , "virgo://http://www.xxx.com");

// 交易有效期
transParam.Add("time_expire" , timeExpire);
// 指定支付方式 是否禁止用户使用信用卡支付。默认不禁用,若禁止请填1
transParam.Add("limit_pay" , "1");
// 延时标志 1为延迟 0为不延迟
transParam.Add("is_delay_acct" , "0");
// 传入分帐遇到优惠的处理规则 1-按比例分 2-按顺序保障 3-只给交易商户
transParam.Add("term_div_coupon_type" , "3");
// 分账串
// 注意只有真实分账场景才需要传入分账串,请避免传入多个分账方为同一商户的分账串
Dictionary<string, Object> acctSplitBunch = new Dictionary<string, Object>();
List<Dictionary<string, Object>> acctInfos = new List<Dictionary<string, Object>>();
// 分账方1
Dictionary<string, Object> acctInfo1 = new Dictionary<string, Object>();
acctInfo1.Add("huifu_id", DemoConstants.DEMO_HUIFU_ID);
acctInfo1.Add("div_amt" , "0.01");
acctInfos.Add(acctInfo1);
// 分账方2
Dictionary<string, Object> acctInfo2 = new Dictionary<string, Object>();
acctInfo2.Add("huifu_id", DemoConstants.DIV_HUIFU_ID);
acctInfo2.Add("div_amt" , "0.01");
acctInfos.Add(acctInfo2);
acctSplitBunch.Add("acct_infos", acctInfos);
transParam.Add("acct_split_bunch", acctSplitBunch);

// 商户私有域
transParam.Add("mer_priv", "");
// 微信扩展参数集合
transParam.Add("wx_data" , "");
// 支付宝扩展参数集合
transParam.Add("alipay_data" , "");
// 银联扩展参数集合
transParam.Add("unionpay_data" , "");
// 手续费类型 01:标准费率线上,02:标准费率线下,03:非盈利费率,04:缴费费率,05:保险费率,06:行业活动费率,07:校园餐饮费率,08:K12中小幼费率
// 不送时取业务入驻配置的默认费率
transParam.Add("pay_scene" , "02");

// 调用接口,使用默认商户配置时可省略配置key
Dictionary<string, Object> result = null;
try {
    result = BasePayClient.postRequest("top.trans.authCodePay" , transParam);
    // 使用指定配置调用接口
    // result = Dictionary<string, Object> result = BasePayClient.postRequest("top.trans.authCodePay", dataParams, "merchantKey2");
} catch (Exception ex) {
    Console.WriteLine(ex.Message);
}

object subRespCode = null;
result.TryGetValue("sub_resp_code", out subRespCode);
if (string.Equals("00000000", (string)subRespCode))
{
    // 处理成功
    // 获取交易状态
    object transStat = null;
    result.TryGetValue("trans_stat", out transStat);
    Console.WriteLine("交易状态:" + transStat);
    // 微信反扫时获取用户openid
    object wxData = null;
    if (result.TryGetValue("wx_response", out wxData)) {
        Console.WriteLine(wxData);
        JObject wxResponse = (JObject)wxData;

        Console.WriteLine("wx_response:" + JsonConvert.SerializeObject(wxResponse, Formatting.None));
        JToken openid = null;
        if (wxResponse.TryGetValue("openid", out openid)) {
            Console.WriteLine("openid:=" + openid);
        }
    }
}
else if (string.Equals("00000100", (string)subRespCode))
{
    // 处理中
    object transStat = null;
    result.TryGetValue("trans_stat", out transStat);
    Console.WriteLine("交易状态:" + transStat);
    // 后续可调用交易查询获取处理中状态的最终支付结果
}
else
{
    // 失败
    object subRespDesc = null;
    result.TryGetValue("sub_resp_desc", out subRespDesc);
    Console.WriteLine("sub_resp_desc" + subRespDesc);
}