前言:微信APP支付(两步操作1:唤醒。2:支付完成回调并返回)
微信支付申请:
1. 打开微信开发放平台 https://open.weixin.qq.com/
2. 进入 管理中心 / 创建移动应用 页面(这里的应用包名和签名是一定要写对的,修改正确之后还是错误是因为微信统一下单接口有缓存延迟,第二天重试即可)
3. 填写基本信息
4. 填写平台信息
申请成功之后需要与微信支付商户关联
1:参数配置 WeiXinPayConfig为微信支付参数
public static class WeiXinPayConfig
{
public static string NotifyUrl { get; set; }
public static string APP_ID { get; set; }
public static string MCHID { get; set; }
public static string Key { get; set; }
}
public class WxPayModel
{
/// <summary>
/// 应用ID
/// </summary>
public string appid { set; get; } = "";
/// <summary>
/// 商户号
/// </summary>
public string partnerid { set; get; } = "";
/// <summary>
/// 预支付交易会话ID
/// </summary>
public string prepayid { set; get; } = "";
/// <summary>
/// 扩展字段
/// </summary>
public string package { set; get; } = "Sign=WXPay";
/// <summary>
/// 随机字符串
/// </summary>
public string noncestr { set; get; } = "";
/// <summary>
/// 时间戳
/// </summary>
public string timestamp { set; get; } = "";
/// <summary>
/// 签名
/// </summary>
public string sign { set; get; } = "";
}
2:微信唤醒 唤醒的时候需要注意的是sign签名是需要获取两次的
/// <summary>
/// 微信APP唤醒
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public async Task<MessageModel<WxPayModel>> WeiXinPay(WeChatPayQuery query)
{
try
{
//特别注意****************************************
var timeStamp = TimeUtil.GetCurrentTimestamp(false);
string out_trade_no = query.CustomerId + DateTime.Now.ToString("yyyyMMddHHmmssfff");
logger.LogInformation("微信唤醒开始" + out_trade_no);
var guidstr = Guid.NewGuid().ToString().Replace("-", "");
HttpClient httpClient = new HttpClient();//http对象 //表头参数
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
StringBuilder xml = new StringBuilder() { };
xml.AppendFormat("<xml><appid>" + WeiXinPayConfig.APP_ID + "</appid>");//appid
xml.AppendFormat("<attach>名称</attach>");//你要传送的额外信息,例如订单ID之类的
xml.AppendFormat("<body>名称</body>");//产品描述,也就是支付事由
xml.AppendFormat("<mch_id>" + WeiXinPayConfig.MCHID + "</mch_id>");//你的商户号,需要与open.weixin.qq.com上对应的APP绑定
xml.AppendFormat("<nonce_str>" + guidstr + "</nonce_str>");//生成的随机字符串
xml.AppendFormat("<notify_url>" + WeiXinPayConfig.NotifyUrl + "</notify_url>");//支付成功后通知处理Url,不能带参数
xml.AppendFormat("<out_trade_no>" + out_trade_no + "</out_trade_no>");//订单号,不能重复
xml.AppendFormat("<spbill_create_ip>" + PayInfoQuery.CreateIp + "</spbill_create_ip>");//.net core服务器IP
xml.AppendFormat("<total_fee>" + query.Money * 100 + "</total_fee>");//金额单位是分
xml.AppendFormat("<trade_type>APP</trade_type>");//APP就填写APP
StringBuilder str = new StringBuilder() { };
str.AppendFormat(@"appid={0}&attach=名称&body=名称&mch_id={1}&nonce_str={2}¬ify_url={3}&out_trade_no={4}&spbill_create_ip={5}&total_fee={6}&trade_type=APP&key={7}", WeiXinPayConfig.APP_ID, WeiXinPayConfig.MCHID, guidstr, WeiXinPayConfig.NotifyUrl, out_trade_no, PayInfoQuery.CreateIp, query.Money * 100, WeiXinPayConfig.Key);
xml.AppendFormat("<sign>" + GetSign(str.ToString()) + "</sign></xml>");//生成的sign
HttpContent httpContent = new StringContent(xml.ToString());//转为链接需要的格式
//请求
HttpResponseMessage response = httpClient.PostAsync("https://api.mch.weixin.qq.com/pay/unifiedorder", httpContent).Result;
string result = "";
//这里开始进入第3步了
if (response.IsSuccessStatusCode)
{
Task<string> t = response.Content.ReadAsStringAsync();
if (t != null)
{
result = t.Result;
WxPayModel model = new WxPayModel() { };
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(result);
model.appid = xmlDoc.DocumentElement.GetElementsByTagName("appid")[0].InnerText;
model.noncestr = xmlDoc.DocumentElement.GetElementsByTagName("nonce_str")[0].InnerText;
model.partnerid = xmlDoc.DocumentElement.GetElementsByTagName("mch_id")[0].InnerText;
model.prepayid = xmlDoc.DocumentElement.GetElementsByTagName("prepay_id")[0].InnerText;
StringBuilder str2 = new StringBuilder() { };
str2.AppendFormat(@"appid={0}&noncestr={1}&package=Sign=WXPay&partnerid={2}&prepayid={3}×tamp={4}&key={5}", WeiXinPayConfig.APP_ID, model.noncestr, model.partnerid, model.prepayid, timeStamp, WeiXinPayConfig.Key);
model.sign = GetSign(str2.ToString());
model.timestamp = timeStamp;
logger.LogInformation("微信唤醒成功" + out_trade_no);
_unitOfWork.BeginTran();
//可以添加自己的业务逻辑
if (order > 0)
{
_unitOfWork.CommitTran();
return new MessageModel<WxPayModel>() { success = true, msg = "唤醒成功", response = model };
}
}
}
return new MessageModel<WxPayModel>() { success = false, msg = "操作失败" };
}
catch (Exception ex)
{
_unitOfWork.RollbackTran();
logger.LogInformation("微信唤醒异常" + ex.ToString());
return new MessageModel<WxPayModel>() { success = false, msg = "微信唤醒失败" };
}
}
3:获取签名的方法
/// <summary>
/// 生成签名
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string GetSign(string str)
{
var md5 = MD5.Create();
var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
var sb = new StringBuilder();
foreach (byte b in bs)
{
sb.Append(b.ToString("x2"));
}
//所有字符转为大写
return sb.ToString().ToUpper();
}
4:支付成功回调
/// <summary>
/// 微信回调
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> UnderWeiXinPay()
{
logger.LogInformation("开始回调(微信)");
Stream stream = HttpContext.Request.Body;
byte[] buffer = new byte[HttpContext.Request.ContentLength.Value];
await stream.ReadAsync(buffer, 0, buffer.Length); //.net core 3.1需要用ReadAsync才不会出错
string xml = System.Text.Encoding.UTF8.GetString(buffer);
//上面几行是关键的获取POST过来的xml数据的代码
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
logger.LogInformation("(微信)参数xml" + xmlDoc);
if (xmlDoc.DocumentElement.GetElementsByTagName("return_code")[0].InnerText == "SUCCESS")
{
string Transaction_Id = xmlDoc.DocumentElement.GetElementsByTagName("transaction_id")[0].InnerText;
string out_trade_no = xmlDoc.DocumentElement.GetElementsByTagName("out_trade_no")[0].InnerText;
logger.LogInformation("参数Transaction_Id" + Transaction_Id);
logger.LogInformation("参数out_trade_no" + out_trade_no);
//获取指定节点内容
//这里是进行各种逻辑代码,最好对sign进行下验证
var result = //验证单号是否在苦中
if (result == null)
{
logger.LogInformation("Failure支付结果中微信订单号不存在" + out_trade_no);
return WeChatPayNotifyResult.Failure;
}
if (result != null && result.Status == EnumOrderType.payoff)
{
logger.LogInformation("信回调SUCCESS:" + out_trade_no);
return WeChatPayNotifyResult.Success;
}
var payresult =//处理自己业务逻辑
if (payresult.success == true)
{
logger.LogInformation("微信回调SUCCESS:" + out_trade_no);
return WeChatPayNotifyResult.Success;
}
else
{
return WeChatPayNotifyResult.Failure;
}
}
else
{
return WeChatPayNotifyResult.Failure;
}
}
到这里你就可以放心的去给前端让其支付了
*下期更新苹果虚拟商品必须开启IPA支付
*
*
*
*
*
*
*
*
*
*
*
是不是惊奇的发现安卓唤起OK 但是ios唤不起来呢 报错签名错误
究极解决方案(关于这个问题呢是安卓和ios需求不同)上方时间戳那里生成的时候生成10位时间戳就可以了
下方附上时间戳生成方法
/// <summary>
/// 获取当前时间戳
/// </summary>
/// <param name="millisecond">精度(毫秒)设置 true,则生成13位的时间戳;精度(秒)设置为 false,则生成10位的时间戳;默认为 true </param>
/// <returns></returns>
public static string GetCurrentTimestamp(bool millisecond = true)
{
return DateTime.Now.ToTimestamp(millisecond);
}
/// <summary>
/// 转换指定时间得到对应的时间戳
/// </summary>
/// <param name="dateTime"></param>
/// <param name="millisecond">精度(毫秒)设置 true,则生成13位的时间戳;精度(秒)设置为 false,则生成10位的时间戳;默认为 true </param>
/// <returns>返回对应的时间戳</returns>
public static string ToTimestamp(this DateTime dateTime, bool millisecond = true)
{
return dateTime.ToTimestampLong(millisecond).ToString();
}
/// <summary>
/// 转换指定时间得到对应的时间戳
/// </summary>
/// <param name="dateTime"></param>
/// <param name="millisecond">精度(毫秒)设置 true,则生成13位的时间戳;精度(秒)设置为 false,则生成10位的时间戳;默认为 true </param>
/// <returns>返回对应的时间戳</returns>
public static long ToTimestampLong(this DateTime dateTime, bool millisecond = true)
{
var ts = dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return millisecond ? Convert.ToInt64(ts.TotalMilliseconds) : Convert.ToInt64(ts.TotalSeconds);
}