首页 > 其他分享 >.Net微信服务商平台ApiV3接口

.Net微信服务商平台ApiV3接口

时间:2024-10-10 16:22:08浏览次数:9  
标签:SetValue ApiV3 string postData 微信 WxPayConfig var Net public

转载:https://www.cnblogs.com/xilen/p/15380183.html

开始

在开始之前建议仔细读微信官方文档,接口规则及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、生成签名

/// <param name="url">微信的接口地址</param>
        /// <param name="method">请求的方式GET,POST,PUT</param>
        /// <param name="jsonParame">post请求的数据,json格式  ,get时传空</param>
        /// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY-----  -----END PRIVATE KEY-----</param>
        /// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
        /// <param name="serialNo">商户证书号</param>
        /// <returns></returns>
        protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, string merchantId, string serialNo)
        {
            var uri = new Uri(url);
            string urlPath = uri.PathAndQuery;
            string nonce = Guid.NewGuid().ToString();
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            //数据签名     HTTP请求方法\n接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n
            method = string.IsNullOrEmpty(method) ? "" : method;
            string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, jsonParame);
            string signTxt = Sign(message, privateKey);

            //Authorization和格式
            string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
                merchantId,
                nonce,
                timestamp,
                serialNo,
                signTxt
                );
            return authorzationTxt;
        }

protected string Sign(string message, string privateKey)
        {
            byte[] keyData = Convert.FromBase64String(privateKey);
            using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
            using (RSACng rsa = new RSACng(cngKey))
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
                return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
            }
        }

  

 2、放到请求头

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

3、完整的请求方法

/// <param name="url">微信的接口地址</param>
/// <param name="postData">post请求的数据,json格式 </param>
/// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY-----  -----END PRIVATE KEY-----</param>
/// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
/// <param name="serialNo">商户证书号</param>
/// <returns></returns>
public string postJson(string url, string postData, string privateKey, string merchantId, string serialNo, string method = "POST")
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = method;
            request.ContentType = "application/json;charset=UTF-8";
            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";
            request.Accept = "application/json";

            string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, serialNo);
            request.Headers.Add("Authorization", Authorization);
            if (!string.IsNullOrEmpty(postData))
            {
                byte[] paramJsonBytes;
                paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
                request.ContentLength = paramJsonBytes.Length;
                Stream writer;
                try
                {
                    writer = request.GetRequestStream();
                }
                catch (Exception)
                {
                    writer = null;
                    Console.Write("连接服务器失败!");
                }
                writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
                writer.Close();
            }

            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = ex.Response as HttpWebResponse;
            }
            Stream resStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(resStream);
            string text = reader.ReadToEnd();
            return text;
        }

  

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

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

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

1、获取证书

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

public static certModel GetCert()
{
    string url = "https://api.mch.weixin.qq.com/v3/certificates";
    string merchantId = WxPayConfig.MCHID;   //商户号
    string serialNo = WxPayConfig.SERIAL_NO;  //证书编号
    string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----

    string transactionsResponse = postJson(url, string.Empty, privateKey, merchantId, serialNo,"GET");
    var result = JsonConvert.DeserializeObject<certModel>(transactionsResponse);
    return result;      
}

GetCert()

  

用到的model

public class certModel
{
public List<Data> data { get; set; }
}

public class Data
{
public string serial_no { get; set; }
public string effective_time { get; set; }
public string expire_time { get; set; }
public Encrypt_certificate encrypt_certificate { get; set; }

}
public class Encrypt_certificate
{
public string algorithm { get; set; }
public string nonce { get; set; }
public string associated_data { get; set; }
public string ciphertext { get; set; }
}

 

复制代码
public class certModel
    {
        public List<Data> data { get; set; }
    }

    public class Data
    {
        public string serial_no { get; set; }
        public string effective_time { get; set; }
        public string expire_time { get; set; }
        public Encrypt_certificate encrypt_certificate { get; set; }

    }
    public class Encrypt_certificate
    {
        public string algorithm { get; set; }
        public string nonce { get; set; }
        public string associated_data { get; set; }
        public string ciphertext { get; set; }
    }
复制代码

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

var cmodel = GetCert().data.OrderByDescending(t => t.expire_time).FirstOrDefault();
string pubkey = AesGcmHelper.AesGcmDecrypt(cmodel.encrypt_certificate.associated_data, cmodel.encrypt_certificate.nonce, cmodel.encrypt_certificate.ciphertext);
pubkey = pubkey.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", "");

//解密方法
public class AesGcmHelper
    {
        private static string ALGORITHM = "AES/GCM/NoPadding";
        private static int TAG_LENGTH_BIT = 128;
        private static int NONCE_LENGTH_BYTE = 12;
        private static string AES_KEY = WxPayConfig.V3KEY;//你的v3秘钥

        public static string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
        {
            GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
            AeadParameters aeadParameters = new AeadParameters(
                new KeyParameter(Encoding.UTF8.GetBytes(AES_KEY)),
                128,
                Encoding.UTF8.GetBytes(nonce),
                Encoding.UTF8.GetBytes(associatedData));
            gcmBlockCipher.Init(false, aeadParameters);

            byte[] data = Convert.FromBase64String(ciphertext);
            byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
            int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
            gcmBlockCipher.DoFinal(plaintext, length);
            return Encoding.UTF8.GetString(plaintext);
        }
    }

pubkey

  

2、敏感信息加密

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

//text 为要加密的字段值
RSAEncrypt(text, UTF8Encoding.UTF8.GetBytes(pubkey));

public static string RSAEncrypt(string text, byte[] publicKey)
        {
            using (var x509 = new X509Certificate2(publicKey))
            {
                using (var rsa = (RSACryptoServiceProvider)x509.PublicKey.Key)
                {
                    var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);

                    return Convert.ToBase64String(buff);
                }
            }
        }

RSAEncrypt

  

这一步需要注意

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

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

public string UploadImg(string imgPath)
        {
            string filePath = HttpContext.Current.Server.MapPath(imgPath);
            var filename = Path.GetFileName(filePath);
            FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            Byte[] imgBytesIn = new Byte[fs.Length];
            fs.Read(imgBytesIn, 0, imgBytesIn.Length);
            fs.Close();

            byte[] hash = SHA256Managed.Create().ComputeHash(imgBytesIn);

            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < hash.Length; i++)
            {
                builder.Append(hash[i].ToString("x2"));
            }
            var sha256 = builder.ToString();
            string metaStr = "{\"filename\":\""+ filename + "\",\"sha256\":\"" + sha256 + "\"}";
            string media_id = UploadImgApi(metaStr, imgBytesIn, filename);
            return media_id;
        }

public static string UploadImgApi(string metaStr, Byte[] imgBytesIn,string filename)
        {
            string url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
            
            string merchantId = WxPayConfig.MCHID;   //商户号
            string serialNo = WxPayConfig.SERIAL_NO;  //证书编号
            string privateKey = WxPayConfig.PRIVATEKEY;
            #region 定义请求体中的内容 并转成二进制

            string boundary = "lc199aecd61b4653ef";
            string Enter = "\r\n";
            string campaignIDStr1
                = "--" + boundary
                + Enter
                + "Content-Disposition: form-data; name=\"meta\";"
                + Enter
                + "Content-Type:application/json;"
                + Enter
                + Enter
                + metaStr
                + Enter
                + "--" + boundary
                + Enter
                + "Content-Disposition:form-data;name=\"file\";filename=\""+ filename + "\";"
                + Enter
                + "Content-Type:image/jpeg"
                + Enter
                + Enter;
            byte[] byteData2
                = imgBytesIn;
            string campaignIDStr3 
                = Enter
                + "--" + boundary 
                + Enter;
            var byteData1 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr1);

            var byteData3 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr3);
            #endregion

            string transactionsResponse = UploadImg_postJson(url, byteData1, byteData2, byteData3, metaStr, privateKey, merchantId, serialNo, boundary, "POST");
            var result=JsonConvert.DeserializeObject<uploadModel>(transactionsResponse);
            Thread.Sleep(500);
            return result.media_id;
        }

public class uploadModel
    {
        public string media_id { get; set; }
    }

UploadImg

  

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

我又单独写了个请求方法

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")
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = method;
            //request.ContentType = "application/json;charset=UTF-8";
            request.ContentType = "multipart/form-data;boundary=" + boundary;
            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";
            request.Accept = "application/json";
            string Authorization = GetAuthorization(url, method, metaStr, privateKey, merchantId, serialNo);
            request.Headers.Add("Authorization", Authorization);

            Stream writer;
            try
            {
                writer = request.GetRequestStream();
            }
            catch (Exception)
            {
                writer = null;
            }
            writer.Write(b1, 0, b1.Length);
            writer.Write(b2, 0, b2.Length);
            writer.Write(b3, 0, b3.Length);
            writer.Close();

            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = ex.Response as HttpWebResponse;
            }
            Stream resStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(resStream);
            string text = reader.ReadToEnd();
            return text;
        }

UploadImg_postJson

  

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

{
"media_id": "H1ihR9JUtVj-J7CJqBUY5ZOrG_Je75H-rKhTG7FUmg9sxNTbRN54dFiUHnhg
rBQ6EKeHoGcHTJMHn5TAuLVjHUQDBInSWXcIHYXOeRa2OHA"
}

四、特约商户进件

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

注意:

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

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

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

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

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

{
  "applyment_id": 2000002124775691
}

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

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

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

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

//storeid是商家唯一Id
public static string CreateQR(string storeid)
{
{
var page = "pages/custom/index";//扫码打开页面
var scene = storeid;//参数
//获取小程序的appid和secret
var appId = WxPayConfig.XCXAPPID;
var secret = WxPayConfig.XCXKEY;
string result = HttpGet($"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={secret}");

tokenModel rb = JsonConvert.DeserializeObject<tokenModel>(result);

var url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + rb.access_token;

var strUrl = url;
var request = (HttpWebRequest)WebRequest.Create(strUrl);
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
var data = new JsonData { ["page"] = page, ["scene"] = scene };

string jso = data.ToJson();
var payload = Encoding.UTF8.GetBytes(jso);
request.ContentLength = payload.Length;
var writer = request.GetRequestStream();
writer.Write(payload, 0, payload.Length);
writer.Close();
var response = (HttpWebResponse)request.GetResponse();
var s = response.GetResponseStream();

var qrCodeImgBase64 = StreamToBytes(s);

//将流保存
string filename= storeid + ".png";
string returnpath= "/UpLoadFiles/StoreQR/" + filename;
string filepath = HttpContext.Current.Server.MapPath("/UpLoadFiles/StoreQR/") + filename;
System.IO.File.WriteAllBytes(filepath, qrCodeImgBase64);
return returnpath;
}
}

CreateQR

复制代码
//storeid是商家唯一Id
public static string CreateQR(string storeid)
        {
            {
                var page = "pages/custom/index";//扫码打开页面
                var scene = storeid;//参数
                //获取小程序的appid和secret
                var appId = WxPayConfig.XCXAPPID;
                var secret = WxPayConfig.XCXKEY;
                string result = HttpGet($"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={secret}");

                tokenModel rb = JsonConvert.DeserializeObject<tokenModel>(result);

                var url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + rb.access_token;

                var strUrl = url;
                var request = (HttpWebRequest)WebRequest.Create(strUrl);
                request.Method = "POST";
                request.ContentType = "application/json;charset=UTF-8";
                var data = new JsonData { ["page"] = page, ["scene"] = scene };

                string jso = data.ToJson();
                var payload = Encoding.UTF8.GetBytes(jso);
                request.ContentLength = payload.Length;
                var writer = request.GetRequestStream();
                writer.Write(payload, 0, payload.Length);
                writer.Close();
                var response = (HttpWebResponse)request.GetResponse();
                var s = response.GetResponseStream();

                var qrCodeImgBase64 = StreamToBytes(s);

                //将流保存
                string filename= storeid + ".png";
                string returnpath= "/UpLoadFiles/StoreQR/" + filename;
                string filepath = HttpContext.Current.Server.MapPath("/UpLoadFiles/StoreQR/") + filename;
                System.IO.File.WriteAllBytes(filepath, qrCodeImgBase64);
                return returnpath;
            }
        }
复制代码

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

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

public static string V3Pay(string sub_mchid,string openid,int amount,string ordernumber,string description)
{
string url = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi";

string appid = WxPayConfig.XCXAPPID;
string merchantId = WxPayConfig.MCHID; //商户号
string serialNo = WxPayConfig.SERIAL_NO; //证书编号
string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----

WxPayData postData = new WxPayData();
postData.SetValue("sp_appid", appid);
postData.SetValue("sp_mchid", merchantId);
postData.SetValue("sub_mchid", sub_mchid);
postData.SetValue("description", description);
postData.SetValue("out_trade_no", ordernumber);
postData.SetValue("notify_url", WxPayConfig.NOTIFY_URL);
WxPayData settle_info = new WxPayData();
settle_info.SetValue("profit_sharing",true);
postData.SetValue("settle_info", settle_info);
WxPayData _amount = new WxPayData();
_amount.SetValue("total", amount);
_amount.SetValue("currency", "CNY");
postData.SetValue("amount", _amount);
WxPayData payer = new WxPayData();
payer.SetValue("sp_openid", openid);
postData.SetValue("payer", payer);

var postJson = postData.ToJsonFor();
string result = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
var result = JsonConvert.DeserializeObject<payModel>(result);
return result.prepay_id;
}

V3Pay

复制代码
public static string V3Pay(string sub_mchid,string openid,int amount,string ordernumber,string description)
        {
            string url = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi";
            
            string appid = WxPayConfig.XCXAPPID;
            string merchantId = WxPayConfig.MCHID;   //商户号
            string serialNo = WxPayConfig.SERIAL_NO;  //证书编号
            string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----
            
            WxPayData postData = new WxPayData();
            postData.SetValue("sp_appid", appid);
            postData.SetValue("sp_mchid", merchantId);
            postData.SetValue("sub_mchid", sub_mchid);
            postData.SetValue("description", description);
            postData.SetValue("out_trade_no", ordernumber);
            postData.SetValue("notify_url", WxPayConfig.NOTIFY_URL);
            WxPayData settle_info = new WxPayData();
            settle_info.SetValue("profit_sharing",true);
            postData.SetValue("settle_info", settle_info);
            WxPayData _amount = new WxPayData();
            _amount.SetValue("total", amount);
            _amount.SetValue("currency", "CNY");
            postData.SetValue("amount", _amount);
            WxPayData payer = new WxPayData();
            payer.SetValue("sp_openid", openid);
            postData.SetValue("payer", payer);

            var postJson = postData.ToJsonFor();
            string result = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
            var result = JsonConvert.DeserializeObject<payModel>(result);
            return result.prepay_id;
        }
复制代码

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

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

public static string GetJsApiParameters(string prepay_id)
{
string appid = WxPayConfig.XCXAPPID;
string privateKey = WxPayConfig.PRIVATEKEY;
string timestamp = WxPayApi.GenerateTimeStamp();
string nonceStr = WxPayApi.GenerateNonceStr();
string package = "prepay_id=" + prepay_id;
WxPayData jsApiParam = new WxPayData();
jsApiParam.SetValue("appId", appid);
jsApiParam.SetValue("timeStamp", timestamp);
jsApiParam.SetValue("nonceStr", nonceStr);
jsApiParam.SetValue("package", package);
jsApiParam.SetValue("signType", "RSA");
string message = string.Format("{0}\n{1}\n{2}\n{3}\n", appid, timestamp, nonceStr, package);
string signTxt = Sign(message, privateKey);
jsApiParam.SetValue("paySign", signTxt);

string parameters = jsApiParam.ToJson();
return parameters;
}

GetJsApiParameters

复制代码
public static string GetJsApiParameters(string prepay_id)
        {
            string appid = WxPayConfig.XCXAPPID;
            string privateKey = WxPayConfig.PRIVATEKEY;
            string timestamp = WxPayApi.GenerateTimeStamp();
            string nonceStr = WxPayApi.GenerateNonceStr();
            string package = "prepay_id=" + prepay_id;
            WxPayData jsApiParam = new WxPayData();
            jsApiParam.SetValue("appId", appid);
            jsApiParam.SetValue("timeStamp", timestamp);
            jsApiParam.SetValue("nonceStr", nonceStr);
            jsApiParam.SetValue("package", package);
            jsApiParam.SetValue("signType", "RSA");
            string message = string.Format("{0}\n{1}\n{2}\n{3}\n", appid, timestamp, nonceStr, package);
            string signTxt = Sign(message, privateKey);
            jsApiParam.SetValue("paySign", signTxt);

            string parameters = jsApiParam.ToJson();
            return parameters;
        }
复制代码

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

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

public class V3Notify
{

public callbackViewModel GetNotifyData()
{
//接收从微信后台POST过来的数据
System.IO.Stream s = System.Web.HttpContext.Current.Request.InputStream;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();

var ReadStr = builder.ToString();

notifyModel wxPayNotify = Newtonsoft.Json.JsonConvert.DeserializeObject<notifyModel>(ReadStr);
//开始解密
string WxPayResourceDecryptModel = AesGcmHelper.AesGcmDecrypt(wxPayNotify.resource.associated_data, wxPayNotify.resource.nonce, wxPayNotify.resource.ciphertext);
var decryptModel= Newtonsoft.Json.JsonConvert.DeserializeObject<WxPayResourceDecryptModel>(WxPayResourceDecryptModel);

var viewModel = new callbackViewModel();
if (decryptModel != null)
{
//查询
var model = queryOrder(decryptModel.out_trade_no, decryptModel.sp_mchid, decryptModel.sub_mchid);//订单查询接口
viewModel.code = model.trade_state;
viewModel.message = model.trade_state_desc;
}
else
{
viewModel.code = "FAIL";
viewModel.message = "数据解密失败";
}
return viewModel;
}
}

V3Notify

复制代码
public class V3Notify
    {
        
        public callbackViewModel GetNotifyData()
        {
            //接收从微信后台POST过来的数据
            System.IO.Stream s = System.Web.HttpContext.Current.Request.InputStream;
            int count = 0;
            byte[] buffer = new byte[1024];
            StringBuilder builder = new StringBuilder();
            while ((count = s.Read(buffer, 0, 1024)) > 0)
            {
                builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
            }
            s.Flush();
            s.Close();
            s.Dispose();

            var ReadStr = builder.ToString();

            notifyModel wxPayNotify = Newtonsoft.Json.JsonConvert.DeserializeObject<notifyModel>(ReadStr);
            //开始解密
            string WxPayResourceDecryptModel = AesGcmHelper.AesGcmDecrypt(wxPayNotify.resource.associated_data, wxPayNotify.resource.nonce, wxPayNotify.resource.ciphertext);
            var decryptModel= Newtonsoft.Json.JsonConvert.DeserializeObject<WxPayResourceDecryptModel>(WxPayResourceDecryptModel);

            var viewModel = new callbackViewModel();
            if (decryptModel != null)
            {
                //查询
                var model = queryOrder(decryptModel.out_trade_no, decryptModel.sp_mchid, decryptModel.sub_mchid);//订单查询接口
                viewModel.code = model.trade_state;
                viewModel.message = model.trade_state_desc;
            }
            else
            {
                viewModel.code = "FAIL";
                viewModel.message = "数据解密失败";
            }
            return viewModel;
        }
    }
复制代码

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

七、分账

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

1、首先添加分账接收方

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

public static receiverModel AddReceivers(string sub_mchid,string type,string account,string relation_type)
{
string url = "https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add";

string appid = WxPayConfig.XCXAPPID;
string merchantId = WxPayConfig.MCHID; //商户号
string serialNo = WxPayConfig.SERIAL_NO; //证书编号
string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----

WxPayData postData = new WxPayData();
postData.SetValue("sub_mchid", sub_mchid);
postData.SetValue("appid", appid);
postData.SetValue("type", type);
postData.SetValue("account", account);
postData.SetValue("relation_type", relation_type);
string postJson = postData.ToJson();

string transactionsResponse = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
var result = JsonConvert.DeserializeObject<receiverModel>(transactionsResponse);
return result;
}

AddReceivers

复制代码
public static receiverModel AddReceivers(string sub_mchid,string type,string account,string relation_type)
        {
            string url = "https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add";
            
            string appid = WxPayConfig.XCXAPPID;
            string merchantId = WxPayConfig.MCHID;   //商户号
            string serialNo = WxPayConfig.SERIAL_NO;  //证书编号
            string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----
            
            WxPayData postData = new WxPayData();
            postData.SetValue("sub_mchid", sub_mchid);
            postData.SetValue("appid", appid);
            postData.SetValue("type", type);
            postData.SetValue("account", account);
            postData.SetValue("relation_type", relation_type);
            string postJson = postData.ToJson();

            string transactionsResponse = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
            var result = JsonConvert.DeserializeObject<receiverModel>(transactionsResponse);
            return result;
        }
复制代码

2、请求分账

public static receiverModel PayReceivers(string sub_mchid, string transaction_id, string out_order_no,List<WxPayData> receivers)
{
string url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders";

string appid = WxPayConfig.XCXAPPID;
string merchantId = WxPayConfig.MCHID; //商户号
string serialNo = WxPayConfig.SERIAL_NO; //证书编号
string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----

WxPayData postData = new WxPayData();
postData.SetValue("sub_mchid", sub_mchid);
postData.SetValue("appid", appid);
postData.SetValue("transaction_id", transaction_id);
postData.SetValue("out_order_no", out_order_no);
postData.SetValue("unfreeze_unsplit", true);
postData.SetValue("receivers", receivers);
string postJson = postData.ToJsonFor();
LogHelper.WriteLogToFile("PayReceivers-postJson:" + postJson);

string transactionsResponse = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
var result = JsonConvert.DeserializeObject<receiverModel>(transactionsResponse);
return result;
}

PayReceivers

复制代码
public static receiverModel PayReceivers(string sub_mchid, string transaction_id, string out_order_no,List<WxPayData> receivers)
        {
            string url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders";
            
            string appid = WxPayConfig.XCXAPPID;
            string merchantId = WxPayConfig.MCHID;   //商户号
            string serialNo = WxPayConfig.SERIAL_NO;  //证书编号
            string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY-----

            WxPayData postData = new WxPayData();
            postData.SetValue("sub_mchid", sub_mchid);
            postData.SetValue("appid", appid);
            postData.SetValue("transaction_id", transaction_id);
            postData.SetValue("out_order_no", out_order_no);
            postData.SetValue("unfreeze_unsplit", true);
            postData.SetValue("receivers", receivers);
            string postJson = postData.ToJsonFor();
            LogHelper.WriteLogToFile("PayReceivers-postJson:" + postJson);

            string transactionsResponse = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
            var result = JsonConvert.DeserializeObject<receiverModel>(transactionsResponse);
            return result;
        }
复制代码

用到的model

public class receiverModel
{
public string sub_mchid { get; set; }
public string type { get; set; }
public string account { get; set; }
public string name { get; set; }
public string relation_type { get; set; }
public string custom_relation { get; set; }
}

receiverModel

复制代码
public class receiverModel
    {
        public string sub_mchid { get; set; }
        public string type { get; set; }
        public string account { get; set; }
        public string name { get; set; }
        public string relation_type { get; set; }
        public string custom_relation { get; set; }
    }
复制代码

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

标签:SetValue,ApiV3,string,postData,微信,WxPayConfig,var,Net,public
From: https://www.cnblogs.com/flms/p/18456616

相关文章

  • 游戏革命!Series AI获2800万美元融资,携手Netflix、戴尔打造GenAI游戏开发平台
     一句话定位Series是一家通过生成式AI技术,为游戏开发者提供全栈游戏创作平台的公司,致力于革新未来的游戏开发模式。一、数据概览成立时间:2023年种子轮融资:790万美元,由a16z领投A轮融资:2800万美元,投资方包括Netflix、DellTechnologiesCapital、a16z、BITKRAFT和F4Fu......
  • 【原创】微信自动回复工具(下篇)
    全文离第一篇文章已经不知不觉过去3年多了,这段时间有空重新重构了一套消息回传模式,工具介绍官网:→→ http://message.fuyue.xyz/ ←← 视频演示:观看视频功能列表本微信助手工具目前已经实现如下功能:接收微信好友消息接收微信群组消息接收系统消息(添加好友、退群、......
  • 机器学习之神经网络Neural Network
    第一部分:基本含义神经网络(NeuralNetwork)是一种模仿人脑神经元连接方式的机器学习模型,用于处理复杂的非线性问题。通过大量的参数和层级结构,神经网络可以学习数据中的特征,应用于分类、回归等任务。机器学习和人类实现人生巅峰的例子对比:如果把人比作神经网络,一次次摔倒就是......
  • 网络最常用的几个命令(arp ,net view,tracert)
    除非了ping常用外,其实命令行,dos命令,还是很多时候可以检查出一个局域网的情况,特别排查问题,找到情况。网络最好用的几个命令arp  显示和修改地址解析协议(ARP)使用的“IP到物理”地址转换表。ARP-sinet_addreth_addr[if_addr]ARP-dinet_addr[if_addr]ARP-a[inet_a......
  • 微信公众号开发---获取用户信息(第⑧篇)
    如果是零基础的小白,建议从本人微信公众号开发栏目的第一篇开始看:微信公众号开发-接口配置信息(第①篇)_微信公众号接口配置信息怎么设置-CSDN博客本文章讲解的是如何获取用户的信息,只要用户关注了,自动获取,并且可以把某些需要的字段存入数据库。代码:<?php//获取用户基本......
  • 【关注可白嫖源码】springboot基于微信小程序的二手书籍交易平台
    摘 要国内的京东商城、天猫、苏宁易购等大型网站在图书销售等商品零售领域已经十分成熟完善,但是以高校学生二手书为主的二手图书资源目前还没有得到合理的开发利用。本人设计和实现的基于微信小程序的二手书籍交易平台是通过合理的市场调查然后才着手实施的。系统分前端和......
  • 【精品毕设推荐】基于微信小程序的电影订票系统设计与实现
    点击下载原文及代码,可辅助在本地配置运行......
  • .NET 实现的交互式 OA 系统
    前言近期,我们在后台收到了粉丝们的留言,需要一个高效办公自动化(OA)系统。为了回应大家的期待,今天我们推荐一款既灵活又强大的OA系统解决方案,帮助提升日常办公效率和团队协作水平。在日常工作中,我们经常遇到各种表单。传统的系统开发中,多一个录入界面就意味着要设计一个新的输入......
  • 福建联通吉比特H80g进telnet获取超级密码改桥接
    本人博客原文链接:福建联通吉比特H80g进telnet获取超级密码改桥接最近福建联通宽带换了一个光猫,型号是吉比特H80G,自己尝试了获取管理员密码,大致流程是:1、记录自己的loid、宽带帐号、密码等配置信息;2、长按光猫reset键回复出场设置,此时管理员账户和密码是CUAdminCUAdmin,在高级......
  • 在 ASP.NET Core 中编写高性能 Web API 的4个小技巧
    WebAPI通常用来与外部模块进行通信、发送和接收数据,作为后端开发人员,应该把写出高性能的应用作为目标。下面4个技巧是我在编写WebAPI的小技巧。1、大量数据使用分页查询接口传输大量数据可能会导致严重的性能问题、过多的内存消耗和速度减慢。为了缓解这些可能的瓶颈,强......