最近做个对接微信服务商平台的小程序项目,大概要实现的流程是:a)特约商户进件 > b)生成带参数的小程序码 > c)小程序支付 > d)分账,记录一下,希望能对需要的朋友有所帮助

开始

在开始之前建议仔细读微信官方文档,接口规则及api文档

https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay-1.shtml

https://pay.weixin.qq.com/wiki/doc/apiv3_partner/index.shtml

目录

整个流程开发步骤如下:

一、(签名)

二、(获取证书、敏感信息加密)

三、(上传图片)

四、(特约商户进件)

五、(生成小程序码)

六、(微信小程序支付)

七、(分账)

正文

在开始之前请确保你已经获取商户号、证书、秘钥、小程序appid、appsecret

一、签名

文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml

1、生成签名

  1. /// <param name="url">微信的接口地址</param>
  2. /// <param name="method">请求的方式GET,POST,PUT</param>
  3. /// <param name="jsonParame">post请求的数据,json格式 ,get时传空</param>
  4. /// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param>
  5. /// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
  6. /// <param name="serialNo">商户证书号</param>
  7. /// <returns></returns>
  8. protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, string merchantId, string serialNo)
  9. {
  10. var uri = new Uri(url);
  11. string urlPath = uri.PathAndQuery;
  12. string nonce = Guid.NewGuid().ToString();
  13. var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
  14. //数据签名 HTTP请求方法\n接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n
  15. method = string.IsNullOrEmpty(method) ? "" : method;
  16. string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, jsonParame);
  17. string signTxt = Sign(message, privateKey);
  18.  
  19. //Authorization和格式
  20. string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
  21. merchantId,
  22. nonce,
  23. timestamp,
  24. serialNo,
  25. signTxt
  26. );
  27. return authorzationTxt;
  28. }
  29.  
  30. protected string Sign(string message, string privateKey)
  31. {
  32. byte[] keyData = Convert.FromBase64String(privateKey);
  33. using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
  34. using (RSACng rsa = new RSACng(cngKey))
  35. {
  36. byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
  37. return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
  38. }
  39. }

2、放到请求头

  1. string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, serialNo);
  2. request.Headers.Add("Authorization", Authorization);

3、完整的请求方法

  1. /// <param name="url">微信的接口地址</param>
  2. /// <param name="postData">post请求的数据,json格式 </param>
  3. /// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param>
  4. /// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
  5. /// <param name="serialNo">商户证书号</param>
  6. /// <returns></returns>
  7. public string postJson(string url, string postData, string privateKey, string merchantId, string serialNo, string method = "POST")
  8. {
  9. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  10. request.Method = method;
  11. request.ContentType = "application/json;charset=UTF-8";
  12. request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
  13. request.Accept = "application/json";
  14.  
  15. string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, serialNo);
  16. request.Headers.Add("Authorization", Authorization);
  17. if (!string.IsNullOrEmpty(postData))
  18. {
  19. byte[] paramJsonBytes;
  20. paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
  21. request.ContentLength = paramJsonBytes.Length;
  22. Stream writer;
  23. try
  24. {
  25. writer = request.GetRequestStream();
  26. }
  27. catch (Exception)
  28. {
  29. writer = null;
  30. Console.Write("连接服务器失败!");
  31. }
  32. writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
  33. writer.Close();
  34. }
  35.  
  36. HttpWebResponse response;
  37. try
  38. {
  39. response = (HttpWebResponse)request.GetResponse();
  40. }
  41. catch (WebException ex)
  42. {
  43. response = ex.Response as HttpWebResponse;
  44. }
  45. Stream resStream = response.GetResponseStream();
  46. StreamReader reader = new StreamReader(resStream);
  47. string text = reader.ReadToEnd();
  48. return text;
  49. }

二、获取证书、敏感信息加密

调用特约商户进件接口之前需要做三个工作:获取证书、敏感信息加密、上传图片

获取证书的目的是敏感信息加密需要用证书里解密得到的pubkey,然后用pubkey去对敏感信息进行加密

1、获取证书

获取证书接口比较简单,直接调用上边的请求方法

  1. public static certModel GetCert()
  2. {
  3. string url = "https://api.mch.weixin.qq.com/v3/certificates";
  4. string merchantId = WxPayConfig.MCHID; //商户号
  5. string serialNo = WxPayConfig.SERIAL_NO; //证书编号
  6. string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----
  7.  
  8. string transactionsResponse = postJson(url, string.Empty, privateKey, merchantId, serialNo,"GET");
  9. var result = JsonConvert.DeserializeObject<certModel>(transactionsResponse);
  10. return result;
  11. }

GetCert()

用到的model

  1. public class certModel
  2. {
  3. public List<Data> data { get; set; }
  4. }
  5.  
  6. public class Data
  7. {
  8. public string serial_no { get; set; }
  9. public string effective_time { get; set; }
  10. public string expire_time { get; set; }
  11. public Encrypt_certificate encrypt_certificate { get; set; }
  12.  
  13. }
  14. public class Encrypt_certificate
  15. {
  16. public string algorithm { get; set; }
  17. public string nonce { get; set; }
  18. public string associated_data { get; set; }
  19. public string ciphertext { get; set; }
  20. }

certModel

调用成功直接返回证书list,我们需要用v3秘钥解密得到公钥

  1. var cmodel = GetCert().data.OrderByDescending(t => t.expire_time).FirstOrDefault();
  2. string pubkey = AesGcmHelper.AesGcmDecrypt(cmodel.encrypt_certificate.associated_data, cmodel.encrypt_certificate.nonce, cmodel.encrypt_certificate.ciphertext);
  3. pubkey = pubkey.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "");
  4.  
  5. //解密方法
  6. public class AesGcmHelper
  7. {
  8. private static string ALGORITHM = "AES/GCM/NoPadding";
  9. private static int TAG_LENGTH_BIT = 128;
  10. private static int NONCE_LENGTH_BYTE = 12;
  11. private static string AES_KEY = WxPayConfig.V3KEY;//你的v3秘钥
  12.  
  13. public static string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
  14. {
  15. GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
  16. AeadParameters aeadParameters = new AeadParameters(
  17. new KeyParameter(Encoding.UTF8.GetBytes(AES_KEY)),
  18. 128,
  19. Encoding.UTF8.GetBytes(nonce),
  20. Encoding.UTF8.GetBytes(associatedData));
  21. gcmBlockCipher.Init(false, aeadParameters);
  22.  
  23. byte[] data = Convert.FromBase64String(ciphertext);
  24. byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
  25. int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
  26. gcmBlockCipher.DoFinal(plaintext, length);
  27. return Encoding.UTF8.GetString(plaintext);
  28. }
  29. }

pubkey

2、敏感信息加密

我们上一步得到了pubkey,然后对一些敏感信息字段(如用户的住址、银行卡号、手机号码等)进行加密

  1. //text 为要加密的字段值
  2. RSAEncrypt(text, UTF8Encoding.UTF8.GetBytes(pubkey));
  3.  
  4. public static string RSAEncrypt(string text, byte[] publicKey)
  5. {
  6. using (var x509 = new X509Certificate2(publicKey))
  7. {
  8. using (var rsa = (RSACryptoServiceProvider)x509.PublicKey.Key)
  9. {
  10. var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
  11.  
  12. return Convert.ToBase64String(buff);
  13. }
  14. }
  15. }

RSAEncrypt

这一步需要注意

  1. //使用OaepSHA1
  2. var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);

三、上传图片

特约商户进件需要上传身份证、营业执照、银行卡等,这就需要通过图片上传API预先生成MediaID

先看接口文档https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter2_1_1.shtml

我封装了一个方法,直接上代码

  1. public string UploadImg(string imgPath)
  2. {
  3. string filePath = HttpContext.Current.Server.MapPath(imgPath);
  4. var filename = Path.GetFileName(filePath);
  5. FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
  6. Byte[] imgBytesIn = new Byte[fs.Length];
  7. fs.Read(imgBytesIn, 0, imgBytesIn.Length);
  8. fs.Close();
  9.  
  10. byte[] hash = SHA256Managed.Create().ComputeHash(imgBytesIn);
  11.  
  12. StringBuilder builder = new StringBuilder();
  13. for (int i = 0; i < hash.Length; i++)
  14. {
  15. builder.Append(hash[i].ToString("x2"));
  16. }
  17. var sha256 = builder.ToString();
  18. string metaStr = "{\"filename\":\""+ filename + "\",\"sha256\":\"" + sha256 + "\"}";
  19. string media_id = UploadImgApi(metaStr, imgBytesIn, filename);
  20. return media_id;
  21. }
  22.  
  23. public static string UploadImgApi(string metaStr, Byte[] imgBytesIn,string filename)
  24. {
  25. string url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
  26.  
  27. string merchantId = WxPayConfig.MCHID; //商户号
  28. string serialNo = WxPayConfig.SERIAL_NO; //证书编号
  29. string privateKey = WxPayConfig.PRIVATEKEY;
  30. #region 定义请求体中的内容 并转成二进制
  31.  
  32. string boundary = "lc199aecd61b4653ef";
  33. string Enter = "\r\n";
  34. string campaignIDStr1
  35. = "--" + boundary
  36. + Enter
  37. + "Content-Disposition: form-data; name=\"meta\";"
  38. + Enter
  39. + "Content-Type:application/json;"
  40. + Enter
  41. + Enter
  42. + metaStr
  43. + Enter
  44. + "--" + boundary
  45. + Enter
  46. + "Content-Disposition:form-data;name=\"file\";filename=\""+ filename + "\";"
  47. + Enter
  48. + "Content-Type:image/jpeg"
  49. + Enter
  50. + Enter;
  51. byte[] byteData2
  52. = imgBytesIn;
  53. string campaignIDStr3
  54. = Enter
  55. + "--" + boundary
  56. + Enter;
  57. var byteData1 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr1);
  58.  
  59. var byteData3 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr3);
  60. #endregion
  61.  
  62. string transactionsResponse = UploadImg_postJson(url, byteData1, byteData2, byteData3, metaStr, privateKey, merchantId, serialNo, boundary, "POST");
  63. var result=JsonConvert.DeserializeObject<uploadModel>(transactionsResponse);
  64. Thread.Sleep(500);
  65. return result.media_id;
  66. }
  67.  
  68. public class uploadModel
  69. {
  70. public string media_id { get; set; }
  71. }

UploadImg

上传图片api需要注意请求主体类型、参与签名的字符串及body格式

我又单独写了个请求方法

  1. public string UploadImg_postJson(string url, byte[] b1, byte[] b2, byte[] b3, string metaStr, string privateKey, string merchantId, string serialNo, string boundary, string method = "POST")
  2. {
  3. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  4. request.Method = method;
  5. //request.ContentType = "application/json;charset=UTF-8";
  6. request.ContentType = "multipart/form-data;boundary=" + boundary;
  7. request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
  8. request.Accept = "application/json";
  9. string Authorization = GetAuthorization(url, method, metaStr, privateKey, merchantId, serialNo);
  10. request.Headers.Add("Authorization", Authorization);
  11.  
  12. Stream writer;
  13. try
  14. {
  15. writer = request.GetRequestStream();
  16. }
  17. catch (Exception)
  18. {
  19. writer = null;
  20. }
  21. writer.Write(b1, 0, b1.Length);
  22. writer.Write(b2, 0, b2.Length);
  23. writer.Write(b3, 0, b3.Length);
  24. writer.Close();
  25.  
  26. HttpWebResponse response;
  27. try
  28. {
  29. response = (HttpWebResponse)request.GetResponse();
  30. }
  31. catch (WebException ex)
  32. {
  33. response = ex.Response as HttpWebResponse;
  34. }
  35. Stream resStream = response.GetResponseStream();
  36. StreamReader reader = new StreamReader(resStream);
  37. string text = reader.ReadToEnd();
  38. return text;
  39. }

UploadImg_postJson

最终返回media_id,存入合适的位置,方便使用

  1. {
  2. "media_id": "H1ihR9JUtVj-J7CJqBUY5ZOrG_Je75H-rKhTG7FUmg9sxNTbRN54dFiUHnhg
  3. rBQ6EKeHoGcHTJMHn5TAuLVjHUQDBInSWXcIHYXOeRa2OHA"
  4. }

四、特约商户进件

上边步骤通了之后,到这就很简单了,这一步的主要难点是请求参数太多了,很容易出错

注意:

• 商户上送敏感信息时使用微信支付平台公钥加密,证书序列号包含在请求HTTP头部的Wechatpay-Seria

需要在请求接口helder里加入Wechatpay-Seria

  1. request.Headers.Add("Wechatpay-Serial", serial_no);

另外一点注意的这里的serial_no是GetCert()接口里获取到的serial_no

调用成功返回微信支付申请单号

  1. {
  2. "applyment_id": 2000002124775691
  3. }

这一步完成之后可以拿到applyment_id请求查询申请单接口获取结果

成功返回sign_url签约连接发给特约商户相应负责人完成签约,即结束商户进件流程

五、生成带参数的小程序码

特约商户签约完成之后,服务商平台便可以代商户发起收款,此时我们需要分别给不同的商户生成不同的收款码,其实只需要传入商家的id即可区别处理

  1. //storeid是商家唯一Id
  2. public static string CreateQR(string storeid)
  3. {
  4. {
  5. var page = "pages/custom/index";//扫码打开页面
  6. var scene = storeid;//参数
  7. //获取小程序的appid和secret
  8. var appId = WxPayConfig.XCXAPPID;
  9. var secret = WxPayConfig.XCXKEY;
  10. string result = HttpGet($"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={secret}");
  11.  
  12. tokenModel rb = JsonConvert.DeserializeObject<tokenModel>(result);
  13.  
  14. var url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + rb.access_token;
  15.  
  16. var strUrl = url;
  17. var request = (HttpWebRequest)WebRequest.Create(strUrl);
  18. request.Method = "POST";
  19. request.ContentType = "application/json;charset=UTF-8";
  20. var data = new JsonData { ["page"] = page, ["scene"] = scene };
  21.  
  22. string jso = data.ToJson();
  23. var payload = Encoding.UTF8.GetBytes(jso);
  24. request.ContentLength = payload.Length;
  25. var writer = request.GetRequestStream();
  26. writer.Write(payload, 0, payload.Length);
  27. writer.Close();
  28. var response = (HttpWebResponse)request.GetResponse();
  29. var s = response.GetResponseStream();
  30.  
  31. var qrCodeImgBase64 = StreamToBytes(s);
  32.  
  33. //将流保存
  34. string filename= storeid + ".png";
  35. string returnpath= "/UpLoadFiles/StoreQR/" + filename;
  36. string filepath = HttpContext.Current.Server.MapPath("/UpLoadFiles/StoreQR/") + filename;
  37. System.IO.File.WriteAllBytes(filepath, qrCodeImgBase64);
  38. return returnpath;
  39. }
  40. }

CreateQR

六、小程序支付JSAPI下单接口

有了商家码就能分别为商家发起支付申请,签约商户都有一个分配的商户号sub_mchid,注意请求参数里的商户号即这个,需要根据二维码的参数去获取

  1. public static string V3Pay(string sub_mchid,string openid,int amount,string ordernumber,string description)
  2. {
  3. string url = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi";
  4.  
  5. string appid = WxPayConfig.XCXAPPID;
  6. string merchantId = WxPayConfig.MCHID; //商户号
  7. string serialNo = WxPayConfig.SERIAL_NO; //证书编号
  8. string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----
  9.  
  10. WxPayData postData = new WxPayData();
  11. postData.SetValue("sp_appid", appid);
  12. postData.SetValue("sp_mchid", merchantId);
  13. postData.SetValue("sub_mchid", sub_mchid);
  14. postData.SetValue("description", description);
  15. postData.SetValue("out_trade_no", ordernumber);
  16. postData.SetValue("notify_url", WxPayConfig.NOTIFY_URL);
  17. WxPayData settle_info = new WxPayData();
  18. settle_info.SetValue("profit_sharing",true);
  19. postData.SetValue("settle_info", settle_info);
  20. WxPayData _amount = new WxPayData();
  21. _amount.SetValue("total", amount);
  22. _amount.SetValue("currency", "CNY");
  23. postData.SetValue("amount", _amount);
  24. WxPayData payer = new WxPayData();
  25. payer.SetValue("sp_openid", openid);
  26. postData.SetValue("payer", payer);
  27.  
  28. var postJson = postData.ToJsonFor();
  29. string result = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
  30. var result = JsonConvert.DeserializeObject<payModel>(result);
  31. return result.prepay_id;
  32. }

V3Pay

请求参数按照自己的方法去构建,json格式

通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的小程序方法调起小程序支付

  1. public static string GetJsApiParameters(string prepay_id)
  2. {
  3. string appid = WxPayConfig.XCXAPPID;
  4. string privateKey = WxPayConfig.PRIVATEKEY;
  5. string timestamp = WxPayApi.GenerateTimeStamp();
  6. string nonceStr = WxPayApi.GenerateNonceStr();
  7. string package = "prepay_id=" + prepay_id;
  8. WxPayData jsApiParam = new WxPayData();
  9. jsApiParam.SetValue("appId", appid);
  10. jsApiParam.SetValue("timeStamp", timestamp);
  11. jsApiParam.SetValue("nonceStr", nonceStr);
  12. jsApiParam.SetValue("package", package);
  13. jsApiParam.SetValue("signType", "RSA");
  14. string message = string.Format("{0}\n{1}\n{2}\n{3}\n", appid, timestamp, nonceStr, package);
  15. string signTxt = Sign(message, privateKey);
  16. jsApiParam.SetValue("paySign", signTxt);
  17.  
  18. string parameters = jsApiParam.ToJson();
  19. return parameters;
  20. }

GetJsApiParameters

返回给小程序调用wx.requestPayment(OBJECT)发起微信支付

注意回调URL:该链接是通过基础下单接口中的请求参数“notify_url”来设置的,要求必须为https地址。请确保回调URL是外部可正常访问的,且不能携带后缀参数,否则可能导致商户无法接收到微信的回调通知信息。回调URL示例: “https://pay.weixin.qq.com/wxpay/pay.action”

  1. public class V3Notify
  2. {
  3.  
  4. public callbackViewModel GetNotifyData()
  5. {
  6. //接收从微信后台POST过来的数据
  7. System.IO.Stream s = System.Web.HttpContext.Current.Request.InputStream;
  8. int count = 0;
  9. byte[] buffer = new byte[1024];
  10. StringBuilder builder = new StringBuilder();
  11. while ((count = s.Read(buffer, 0, 1024)) > 0)
  12. {
  13. builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
  14. }
  15. s.Flush();
  16. s.Close();
  17. s.Dispose();
  18.  
  19. var ReadStr = builder.ToString();
  20.  
  21. notifyModel wxPayNotify = Newtonsoft.Json.JsonConvert.DeserializeObject<notifyModel>(ReadStr);
  22. //开始解密
  23. string WxPayResourceDecryptModel = AesGcmHelper.AesGcmDecrypt(wxPayNotify.resource.associated_data, wxPayNotify.resource.nonce, wxPayNotify.resource.ciphertext);
  24. var decryptModel= Newtonsoft.Json.JsonConvert.DeserializeObject<WxPayResourceDecryptModel>(WxPayResourceDecryptModel);
  25.  
  26. var viewModel = new callbackViewModel();
  27. if (decryptModel != null)
  28. {
  29. //查询
  30. var model = queryOrder(decryptModel.out_trade_no, decryptModel.sp_mchid, decryptModel.sub_mchid);//订单查询接口
  31. viewModel.code = model.trade_state;
  32. viewModel.message = model.trade_state_desc;
  33. }
  34. else
  35. {
  36. viewModel.code = "FAIL";
  37. viewModel.message = "数据解密失败";
  38. }
  39. return viewModel;
  40. }
  41. }

V3Notify

整个下单没有牵涉到业务方面的代码,你可以把你的业务代码写在合适的位置处理

七、分账

在请求分账之前先在微信服务商后台邀约商户授权分账并指定分账比例(最大30%),并且发起支付申请时请求参数指定profit_sharing为true

1、首先添加分账接收方

接收方必须先调用接口添加才能在下一步请求分账时使用,注意不允许重复的openid

  1. public static receiverModel AddReceivers(string sub_mchid,string type,string account,string relation_type)
  2. {
  3. string url = "https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add";
  4.  
  5. string appid = WxPayConfig.XCXAPPID;
  6. string merchantId = WxPayConfig.MCHID; //商户号
  7. string serialNo = WxPayConfig.SERIAL_NO; //证书编号
  8. string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----
  9.  
  10. WxPayData postData = new WxPayData();
  11. postData.SetValue("sub_mchid", sub_mchid);
  12. postData.SetValue("appid", appid);
  13. postData.SetValue("type", type);
  14. postData.SetValue("account", account);
  15. postData.SetValue("relation_type", relation_type);
  16. string postJson = postData.ToJson();
  17.  
  18. string transactionsResponse = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
  19. var result = JsonConvert.DeserializeObject<receiverModel>(transactionsResponse);
  20. return result;
  21. }

AddReceivers

2、请求分账

  1. public static receiverModel PayReceivers(string sub_mchid, string transaction_id, string out_order_no,List<WxPayData> receivers)
  2. {
  3. string url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders";
  4.  
  5. string appid = WxPayConfig.XCXAPPID;
  6. string merchantId = WxPayConfig.MCHID; //商户号
  7. string serialNo = WxPayConfig.SERIAL_NO; //证书编号
  8. string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----
  9.  
  10. WxPayData postData = new WxPayData();
  11. postData.SetValue("sub_mchid", sub_mchid);
  12. postData.SetValue("appid", appid);
  13. postData.SetValue("transaction_id", transaction_id);
  14. postData.SetValue("out_order_no", out_order_no);
  15. postData.SetValue("unfreeze_unsplit", true);
  16. postData.SetValue("receivers", receivers);
  17. string postJson = postData.ToJsonFor();
  18. LogHelper.WriteLogToFile("PayReceivers-postJson:" + postJson);
  19.  
  20. string transactionsResponse = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
  21. var result = JsonConvert.DeserializeObject<receiverModel>(transactionsResponse);
  22. return result;
  23. }

PayReceivers

用到的model

  1. public class receiverModel
  2. {
  3. public string sub_mchid { get; set; }
  4. public string type { get; set; }
  5. public string account { get; set; }
  6. public string name { get; set; }
  7. public string relation_type { get; set; }
  8. public string custom_relation { get; set; }
  9. }

receiverModel

至此完整流程全部走完,总结下来技术难度并不大,就是步骤多,并且要把握好调用的时机,再一个就是请求参数多,容易出错,要耐心。

如有问题请在评论区留言或私信我

.Net微信服务商平台ApiV3接口的更多相关文章

  1. PHP玩转微信公众平台自定义接口

    从微信公众平台开通自定义回复后,就一直在关注微信接口这一块,很想用自定义回复这块做个站长工具的查询,例如PR查询,备案查询等,输入网址信息,就能自动获取PR,获取备案信息,应该是一个不错的想法.不过以 ...

  2. 微信公众平台API接口

    简介 微信公众平台消息接口为开发者提供了一种新的消息处理方式.微信公众平台消息接口为开发者提供与用户进行消息交互的能力.对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使 ...

  3. 微信公众平台消息接口API指南

    简介 微信公众平台消息接口为开发者提供了一种新的消息处理方式.微信公众平台消息接口为开发者提供与用户进行消息交互的能力.对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使 ...

  4. 微信公众平台消息接口开发-封装weixin.class.php

    原文:微信公众平台消息接口开发-封装weixin.class.php 一.封装weixin.class.php 由于微信公众平台的通信使用的是特定格式的XML数据,每次接受和回复都要去做一大堆的数据处 ...

  5. 微信公众平台消息接口PHP版开发教程

    原文:微信公众平台消息接口PHP版开发教程  一.写好接口程序 在你的服务器上上传好一个接口程序文件,如http://www.yourdomain.com/weixin.php  内容如下: &l ...

  6. 微信公众平台开发接口PHP SDK

    以前没接触过微信公众平台开发,前几天刚找到实习公司就要求我做一个微信公众平台的应用,于是乎开始学习微信公众平台开发接口的调用,看开发文档之后还是不知道从何入手,只好上网找入门资料,终于在方倍工作室找到 ...

  7. 微信公众平台消息接口PHP版

    使用前提条件:拥有一个公网上的HTTP服务器主机空间,具有创建目录.上传文件等权限.推荐新浪的SAE.http://sae.sina.com.cn/ 首先请注册微信公众平台的账号,注册地址:http: ...

  8. 微信公众平台消息接口开发-封装weixin.class.php(转)

    一.封装weixin.class.php 由于微信公众平台的通信使用的是特定格式的XML数据,每次接受和回复都要去做一大堆的数据处理. 我们就考虑在这个基础上做一次封装,weixin.class.ph ...

  9. 微信公众平台消息接口开发(26)从Hello2BizUser文本到subscribe事件

    微信公众平台 微信公众平台开发模式 消息接口 企业微信公众平台 Hello2BizUser subscribe 订阅事件 作者:方倍工作室 原文:http://www.cnblogs.com/txw1 ...

随机推荐

  1. centos7 shell 计算器 bc 命令

    2021-08-03 1. 安装 yum -y install bc 2. 简介 bc 命令是任意精度计算器语言,通常在 linux 下当计算器使用 类似基本的计算器, 使用这个计算器可以做基本的数学 ...

  2. 【MIT6.S081/6.828】手把手教你搭建开发环境

    目录 1. 简介 2. 安装ubuntu20.04 3. 更换源 3.1 更换/etc/apt/sources.list文件里的源 3.2 备份源列表 3.3 打开sources.list文件修改 3 ...

  3. JDK和环境配置,eclipse安装与使用

    本博客部分参照https://blog.csdn.net/PGY0000/article/details/79256720 (记住要尊重别人的劳动产品) 原博客给的链接和后面的安装过程有点不一样,不能 ...

  4. noip模拟测试18

    打开比赛第一眼--超级树? 点开--原题 百感交集-- 欣喜于发现是半年前做过两遍的原题 紧张于如果A不了比较尴尬 绝望于发现根本不会做了 瞟了一眼t1,瞅了一眼t2,嗯--开始搞t3 10分钟打完暴 ...

  5. noip模拟40

    \(\color{white}{\mathbb{名之以:海棠}}\) 考场 \(t1\) 看见题意非常简单,觉得可能是个简单题 暴力算出几个小样例右端点右移的时候左端点都是单调右移的,以为具有单调性, ...

  6. 2021-06-14 BZOJ4919:大根堆

    BZOJ4919:大根堆 Description: 题目描述   给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你 ...

  7. Appium自动化(3) - adb无线连接手机的方法

    如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 前言 除了USB方式连接Andro ...

  8. ICCV2021 | MicroNet:以极低的 FLOPs 改进图像识别

    ​前言:这篇论文旨在以极低的计算成本解决性能大幅下降的问题.提出了微分解卷积,将卷积矩阵分解为低秩矩阵,将稀疏连接整合到卷积中.提出了一个新的动态激活函数-- Dynamic Shift Max,通过 ...

  9. 数组字符串json之间的相互转换

    数组转字符串 var arr = [1,2,3,4,'巴德','merge']; var str = arr.join(','); console.log(str); // 1,2,3,4,巴德,me ...

  10. 一键配置tomcat定期日志清理功能

    概述 日志文件包含了关于系统中发生的事件的有用信息,在排障过程中或者系统性能分析时经常被用到.对于忙碌的服务器,日志文件大小会增长极快,服务器会很快消耗磁盘空间,这成了个问题.除此之外,处理一个单个的 ...