asp.net mvc 微信支付代码分析(根据沐雪微信平台3.1商城业务来分析)
开发微信应用,微信支付是永远要面对的。现在的微信支付相对以往已经很稳定,很少出现诡异情况。再加上无数人开发的经验分享,现在开发微信支付已经没什么难度了。
我这次主要是想基于沐雪微信平台的微商城业务来分析微信支付到底该怎么做。主要讲思路,代码也同时会献上。
一、思考:1、支付前系统该做什么?2、支付的时候该怎么处理业务?3、同步和异步回调该怎么处理业务逻辑?4、安全性,稳定性,数据一致性如何保证?
分析:第1个问题:支付前的一个页面一般来说是订单确认页面,在支付前,必须把该订单的所有数据(订单编号等基本数据,用户信息,订单商品信息,物流信息等)都保存到数据库,状态设置为“待支付”;再跳转到微信支付页面,微信支付页面接收到参数(订单编号,wid,业务模块编号)立即处理逻辑:
public class PayController : BaseController
{
string module = "支付页面"; /// <summary>
/// 微信支付
/// </summary>
/// <param name="wid"></param>
/// <param name="moduletype">业务分类</param>
/// <param name="orderNo"></param>
/// <returns></returns>
public ActionResult WXPaySubmit(int wid,string moduletype,string orderNo)
{
string parameters = string.Format("wid:{0},moduletype:{1},orderNo:{2}", wid,moduletype, orderNo);
string operating = "微信支付页面"; bool isWeiXin = false;
ViewBag.errorInfo = "";
ViewBag.pay_json = "";
string pay_uri = "";
string userAgent = base.Request.UserAgent; try
{
LogHelper.Info(parameters, 0, fromplat, module, operating); if (userAgent.ToLower().IndexOf("micromessenger") > -1)
{
isWeiXin = true;
}
ViewBag.isWeiXin = isWeiXin;
ViewBag.pay_uri = pay_uri; if (string.IsNullOrWhiteSpace(orderNo))
{
ViewBag.errorInfo = "订单号为空,不能进行支付!";
return View();
}
ViewBag.orderNo = orderNo; BLL.orders otBll = new BLL.orders();
Model.orders orderEntity = otBll.GetModel(orderNo, wid);
if (orderEntity == null)
{
ViewBag.errorInfo = "错误的订单号,不能进行支付!";
return View();
}
if (orderEntity.payment_status != 1 || orderEntity.status != 1)
{
ViewBag.errorInfo = "订单状态错误,不能进行支付!";
return View();
}
BLL.wx_crm_users userBll = new BLL.wx_crm_users();
Model.wx_crm_users user = userBll.GetModel(orderEntity.user_id, wid); if (orderEntity.payment_id == 1)
{
//线下付款
ViewBag.isOfflineOrder = true;
}
else
{
ViewBag.isOfflineOrder = false;
}
ViewBag.IsServiceOrder = false;//服务订单
ViewBag.isFightGroup = false;//团购的订单
ViewBag.Wid = wid; string packageValue = "";
if (orderEntity.payment_id == 3)
{//微信支付
packageValue = WxPayDataV3(wid, orderEntity.order_amount, orderEntity.orderSubject, orderEntity.order_no, orderEntity.id, orderEntity.user_id, user.openid);
} ViewBag.packageValue = packageValue;
}
catch (Exception ex)
{ LogHelper.Error(parameters + ",message:" + ex.Message, ex, wid , fromplat, module, operating);
} return View();
} /// <summary>
/// 微信支付最新接口调用
/// 2018-9-20 搬家
/// </summary>
/// <param name="wid">微账号</param>
/// <param name="ttFee">支付金额(单位元)</param>
/// <param name="busiBody">订单内容</param>
/// <param name="out_trade_no">订单号</param>
/// <param name="code"></param>
protected string WxPayDataV3(int wid, decimal ttFee, string busiBody, string out_trade_no, int order_id,int user_id,string openid)
{
string operating = "微信支付最新接口调用";
string parameters = string.Format("wid:{0},ttFee:{1},busiBody:{2},out_trade_no:{3},order_id:{4},user_id:{5},openid:{6}", wid, ttFee, busiBody, out_trade_no, order_id, user_id, openid); try
{
LogHelper.Info(parameters, 0, fromplat, module, operating); JsApiConfig jsapiConfig = new JsApiConfig(wid, SysModuleNameEnum.微商城); if (jsapiConfig == null)
{
LogHelper.Warn("微信支付没有配置正确(wid=" + wid + ")", user_id, fromplat, module, operating);
return null;
} string packageValue = ""; //先设置基本信息
string MchId = jsapiConfig.MchId;
string partnerKey = jsapiConfig.Key;// 商户支付密钥Key。登录微信商户后台,进入栏目【账户设置】【密码安全】【API 安全】【API 密钥】
string notify_url = jsapiConfig.Notify_url;// MyCommFun.getAppSettingValue("webapi_url") + "/api/Pay/notify_url";//回调函数 string timeStamp = "";
string nonceStr = "";
string paySign = ""; string sp_billno = out_trade_no;
//当前时间 yyyyMMdd
string date = DateTime.Now.ToString("yyyyMMdd"); if (null == sp_billno)
{
//生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一
sp_billno = DateTime.Now.ToString("HHmmss") + TenPayV3Util.BuildRandomStr(28);
} timeStamp = TenPayV3Util.GetTimestamp();
nonceStr = TenPayV3Util.GetNoncestr();
string attach = wid + "|" + order_id +"|" + user_id;
int price = (int)(ttFee * 100);//商品金额,以分为单位(money * 100).ToString()
var xmlDataInfo = new TenPayV3UnifiedorderRequestData(jsapiConfig.AppId, MchId, busiBody, sp_billno, price, Request.UserHostAddress, notify_url, TenPayV3Type.JSAPI, openid, partnerKey, nonceStr, "vshop", null, null, "", attach); LogHelper.Info(parameters + ",xmlDataInfo=" + xmlDataInfo.ToString(), 0, fromplat, module, operating);
var result = TenPayV3.Unifiedorder(xmlDataInfo);//调用统一订单接口 string prepayId = result.prepay_id; LogHelper.Info(parameters + ",预支付的prepayId=" + prepayId, 0, fromplat, module, operating); //设置支付参数
paySign = TenPayV3.GetJsPaySign(jsapiConfig.AppId, timeStamp, nonceStr, string.Format("prepay_id={0}", prepayId), partnerKey); packageValue = "";
packageValue += " \"appId\": \"" + jsapiConfig.AppId + "\", ";
packageValue += " \"timeStamp\": \"" + timeStamp + "\", ";
packageValue += " \"nonceStr\": \"" + nonceStr + "\", ";
packageValue += " \"package\": \"" + string.Format("prepay_id={0}", prepayId) + "\", ";
packageValue += " \"signType\": \"MD5\", ";
packageValue += " \"paySign\": \"" + paySign + "\""; LogHelper.Info(parameters + ",packageValue=" + packageValue, 0, fromplat, module, operating);
return packageValue;
}
catch (Exception ex)
{ LogHelper.Error(parameters + ",message:" + ex.Message, ex, wid, fromplat, module, operating);
throw;
} } }
将数据给试图里处理,jssdk调起微信支付。试图页里只有一段Js,其他的都不需要放。
<script type="text/javascript">
var orderNo = "@ViewBag.orderNo";
var IsServiceOrder = "@ViewBag.IsServiceOrder";
var isFightGroup = "@ViewBag.isFightGroup";
var isOfflineOrder = "@ViewBag.isOfflineOrder";
//调用微信JS api 支付
function jsApiCall() {
WeixinJSBridge.invoke('getBrandWCPayRequest', { @Html.Raw(ViewBag.packageValue) }, function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
alert("订单支付成功!点击确认进入我的订单中心"); location.replace("/VShop/Order/OrderDetail/@ViewBag.Wid?orderno=" + orderNo);
}
else {
//alert(res.err_code + res.err_desc + res.err_msg); if (res.err_msg.indexOf("cancel") != -1) {
//主动取消支付
}
else {
alert("支付取消或者失败res.err_msg=" + res.err_msg);
}
location.replace("/VShop/Order/OrderDetail/@ViewBag.Wid?orderno=" + orderNo); }
//alert("订单支付成功!点击确认进入我的订单中心");
});
} function callpay() {
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
}
else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
}
else {
jsApiCall();
}
}
callpay();
</script>
有人肯定会问,为啥不把微信支付功能与订单确认页放在同一个页面?或者是微信支付页面是否要显示支付的金额然后再加个确认支付按钮?
沐雪微信平台之所以这么做,原因有几点:1、订单确认页面逻辑相当庞杂,2、而微信支付跟订单其实是两块业务逻辑,3、支付业务可以抽出来作为公共的方法页面;4、随着业务模块增多,支付页面的逻辑也会越来越复杂;5、代码隔离带来无限的好处;6、个人不喜欢一个页面承担太多东西,宁愿牺牲点用户体验,也不喜欢吧代码融合在一起;7、根据以往经验,代码融合在一个页面,一个页面代码越多,出错的概率越是成倍的增长,排查问题的难度也越大,非常不利于代码迭代更新与的长期维护;
支付完成后,就跳转到用户中心的订单详情页面查看信息;一般是间隔2,3秒才跳,等待异步回调处理;
异步回调函数里,一定要验证签名:
asp.net mvc 微信支付代码分析(根据沐雪微信平台3.1商城业务来分析)的更多相关文章
- asp微信支付代码证书文件post_url.aspx和post_url.aspx.cs源码下载
很多朋友在网上找的asp支付代码中都没有这两个证书文件,只能是用别人的,但是如果别人把他的网站这个文件删了,你的支付也就不能用了,今天我就把大家需要的这两个asp微信支付代码证书文件post_url. ...
- Asp.net mvc 5 CRUD代码自动生成工具- vs.net 2013 Saffolding功能扩展
Asp.net mvc 5 CRUD代码自动生成工具 -Visual Studio.net2013 Saffolding功能扩展 上次做过一个<Asp.net webform scaffoldi ...
- DELPHI微信支付代码
DELPHI微信支付代码 不管是微信支付还是支付宝支付, 3个最棘手的问题是:1,如何生成签名2,支付请求如何提交3, 如何验证签名 下面就围绕这二个问题来讲. 我使用的是XE3. 先看微信支付: ...
- asp微信支付代码v4.1无需证书版,带回调入库的asp支付源码
昨天帮一个客户写的,他的程序是老的asp,想实现微信在手机上下单付款,让帮忙给写一份asp微信支付的接口代码,昨天晚上闲着没事,搞了一个晚上才搞好,其实asp支付并不需要安装证书,其实asp支付也很好 ...
- ASP.NET MVC Display Mode 移动端视图 配置对微信内置浏览器的识别
最近在捣鼓一个稍微有点low的商城网站,没有计划做app却要求有个wap版,而前端又没有做成响应式,时间WTF,直接利用了asp.net mvc的Display Mode Provider. 使用方式 ...
- JAVA微信支付代码(WeChatPay.java 才是调用类)
微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/index.html MD5Util.java package weixin; import java.se ...
- ASP.NET MVC 简单分页代码
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- vue-cli中进行微信支付代码详解
最近做微信支付,颇经历一番波折,这里总结一下,便于以后少走弯路: 在进行微信支付,除了需要公众号之外,你还需要一个微信商户.根据商户规则进行商户申请 这是公众号的基本开发配置,这里在微信授权的时候就已 ...
- 新建 ASP.NET MVC 项目快速代码
视图模型- PagingInfo 类: public class PagingInfo { public int TotalItems { get; set; } public int ItemsPe ...
随机推荐
- ps选区的两种复制方法
1.选区选中之后,利用移动工具,按住alt键,拖动即可复制所选区域. ps:再一个图层上操作. 2.选区选中之后,Ctrl+c .Ctrl+v复制粘贴,按Ctrl+T移动. ps:新建一个图层操作,不 ...
- 【C#】用委托(Delegate)的BeginInvoke和EndInvoke方法操作线程
让我们首先了解下什么时候用到C#异步调用: .NET Framework 允许您C#异步调用任何方法.定义与您需要调用的方法具有相同签名的委托:公共语言运行库将自动为该委托定义具有适当签名的Begin ...
- .NET Framework 4 与.NET Framework 4 Client Profile有什么区别?
.net framework 自从 2002 年发展至今,已经历了好几个版本,1.0, 1.1, 2.0, 3.0, 3.5 等不同的版本更替,.net framework 的Redistributa ...
- c/c++保存日志程序模板
//输出日志 int PrintRunInfo(char *fmt, ...) { FILE* fp; fp = fopen("cgi_log.txt","a+&qu ...
- HDU.4700.Flow(构造 最小割树)
题目链接 \(Description\) 给定\(n\)以及\(n\)个点任意两点之间的最大流,求一张无向图满足给定条件. \(n\leq100\). \(Solution\) 有些类似最小割树. 我 ...
- vue动态切换视图
big.vue <template> <div> big <p>{{view}}</p> <!--标准规范--> <component ...
- python学习—几个简单小程序
1. 输出1到100的偶数 #!/usr/bin/env python # -*- coding:utf-8 -*- #定义初始值 start=1 while True: #判断start的值若其为5 ...
- BZOJ5100 : [POI2018]Plan metra
若$1$到$n$之间没有其它点,则$1$到$n$的距离为任意一点到它们距离的差值,按照距离关系判断每个点是挂在$1$上还是挂在$n$上即可. 否则$1$到$n$的距离只可能为任意一点到它们距离和的最小 ...
- 考前停课集训 Day3 匪
Day3——作死不可活的一天 Day3 今天下午才考 晚上时间少 下午网每断 因此我是PY的 然后被抓了 成绩做0分处理. 是啊,我只会抄题解. 其他什么都不会. 一无是处. 真的. 真实能力:ran ...
- keras用vgg16做图像分类
实际上我只是提供一个模版而已,代码应该很容易看得懂,label是存在一个csv里面的,图片是在一个文件夹里面的 没GPU的就不用尝试了,训练一次要很久很久... ## import libaries ...