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 ...
随机推荐
- python 数据结构之二叉树
二叉树关键在构建和遍历,python实现相对简单,我们在实现需要用到类,分别设置爱左右子树,根节点,然后从根进行遍历,进行判断,若为空进行树的构建,非空则返回到列表中即可,我在进行遍历时产生了一个错误 ...
- NIO编程---通道(Channel)
**版权声明:本文为小斑马伟原创文章,转载请注明出处! 通道(Channel):由java.nio.channels 包定义的.Channel 表示IO 源与目标打开的连接.Channel 类似于传统 ...
- ppt标签打开文件 word标签打开文件 窗口打开文件 粘贴默认方式
ppt标签打开文件 word标签打开文件 word窗口打开文件 ppt粘贴默认方式 word粘贴默认方式 ppt粘贴默认方式 只保留文本 == 通过 视图 切换窗口. == 层叠 样式 如下. == ...
- C#中的集合之ArryList
List泛型集合 集合是OOP中的一个重要概念,C#中对集合的全面支持更是该语言的精华之一. 为什么要用泛型集合? 在C# 2.0之前,主要可以通过两种方式实现集合: a.使用ArrayList 直接 ...
- PHP的json_encode不兼容JSON_UNESCAPED_UNICODE的解决方案
PHP5.4才支持JSON_UNESCAPED_UNICODE这个参数,此参数是让中文字符在json_encode的时候不用转义,减少数据传输量.但在PHP5.3中,就得自己写个函数来实现,以下就是解 ...
- SSH(Spring SpringMVC Hibernate)框架整合
项目说明: 使用SSH(Spring SpringMVC Hibernate)框架整合添加部门功能 项目结构 1.导入依赖jar包 <!--单测--> <dependency&g ...
- 修改mybatis plus Generator模板生成字段注释枚举常量
修改mybatis plus Generator模板生成字段注释枚举常量 本文基于最新的mybatis-plus 3.0.1版本源码修改,如果使用其它版本,处理方式也类似,主要是生成Entity的Fr ...
- C#ConcurrentDictionary源代码
using System; using System.Collections.Generic;using System.Text; using System.Threading; using Syst ...
- bzoj 1005
prufer序列 性质: 1.一棵n个结点的树可表示为长度 n-2 的prufer序列 2.每个结点出现在prufer序列中的次数==该结点的度 -1 公式推出来了,大数模板没有除法..等开学了Jav ...
- 卷积cnn总结
阅读了很多篇文章后,还是觉得有两篇文章很好,所以基本上就吸收搬过来了. 从神经网络到卷积神经网络(CNN) 我们知道神经网络的结构是这样的: 那卷积神经网络跟它是什么关系呢? 其实卷积神经网络依旧是层 ...