MVC 微信支付
微信支付方式有好几种,俺研究了跟自己需要的两种,即:JS API网页支付和Native原生支付,这两个名词实在是有目的难懂。JS API网页支付:我的理解是在微信浏览器里面可以调用微信支付控件的支付方式;Native 原生支付则是在其他浏览器里面通过扫描二维码进行支付的方式。相关技术文档和术语有很多是地球人比较难理解的,需要试验,我把我的试验成功贴一下。
第一步,首先在公众账号配置微信支付,如下图,并把微信号添加到测试白名单。建议测试目录里面的文字全部小写,腾讯居然要求网址的大小写也要匹配。
第二步,统一下单。就是在微信支付服务后台生成预支付交易单,返回正确的预支付交易标识后再按扫码、JSAPI、APP等不同场景生成交易串调起支付。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using Zmm.Wx.HttpUtility; namespace Zmm.Wx.MP.TenPay
{
public class UnifierOrderResult
{
public string return_code { get; set; }
public string return_msg { get; set; }
public string appid { get; set; }
public string mch_id { get; set; }
public string device_info { get; set; }
public string nonce_str { get; set; }
public string sign { get; set; }
public string result_code { get; set; }
public string err_code { get; set; }
public string err_code_des { get; set; }
public string trade_type { get; set; }
public string prepay_id { get; set; }
public string code_url { get; set; } public override string ToString()
{
List<string> items = new List<string>();
var props = this.GetType().GetProperties();
foreach (var prop in props)
{
var val = prop.GetValue(this);
if (val != null && !string.IsNullOrEmpty(val.ToString()))
items.Add(prop.Name + "=" + val);
}
return string.Join(";", items);
}
class RequirePara
{
public string appid { get; set; }
public string mch_id { get; set; }
public string nonce_str { get; set; }
public string body { get; set; }
public string detail { get; set; }
public string attach { get; set; }
public string out_trade_no { get; set; }
public int total_fee { get; set; }
public string spbill_create_ip { get; set; }
public string notify_url { get; set; }
public string trade_type { get; set; }
public string product_id { get; set; }
public string openid { get; set; }
public string GetXml()
{
List<string> items = new List<string>();
var props = this.GetType().GetProperties();
foreach (var prop in props)
{
var val = prop.GetValue(this);
if (val != null && !string.IsNullOrEmpty(val.ToString()))
items.Add(prop.Name + "=" + val);
}
items.Sort();
StringBuilder sb = new StringBuilder();
foreach (var item in items)
sb.Append(item + "&");
sb.Append("key=keyvalue");
string sign = MD5Util.GetMD5(sb.ToString()).ToUpper();
return string.Format("<xml>{0}<sign>{1}</sign></xml>", ToXml(), sign);
} string ToXml()
{
List<string> items = new List<string>();
var props = this.GetType().GetProperties();
foreach (var prop in props)
{
var val = prop.GetValue(this);
if (val != null && !string.IsNullOrEmpty(val.ToString()))
items.Add(string.Format("<{0}>{1}</{0}>", prop.Name, val));
}
items.Sort();
return string.Join("", items); } }
/// <summary>
///
/// </summary>
/// <param name="body">商品描述</param>
/// <param name="detail">商品详情</param>
/// <param name="attach">附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据</param>
/// <param name="out_trade_no">商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号</param>
/// <param name="total_fee">订单总金额,只能为整数,单位为分</param>
/// <param name="spbill_create_ip">APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。</param>
/// <param name="notify_url">接收微信支付异步通知回调地址</param>
/// <param name="trade_type">交易类型,取值如下:JSAPI,NATIVE,APP,WAP</param>
/// <param name="product_id">trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。 </param>
/// <param name="openid">trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。</param>
/// <returns></returns>
public static UnifierOrderResult Get(string body, string detail, string attach, string out_trade_no, int total_fee, string spbill_create_ip, string notify_url, string trade_type, string product_id, string openid)
{ const string url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; RequirePara para = new RequirePara()
{
appid = "appid",
mch_id = "partnerid",
nonce_str = DateTime.Now.Ticks.ToString(),
body = body,
detail = detail,
attach = attach,
out_trade_no = out_trade_no,
total_fee = total_fee,
spbill_create_ip = spbill_create_ip,
notify_url = notify_url,
trade_type = trade_type,
product_id = product_id,
openid = openid
}; string retval = HttpUtility.RequestUtility.HttpPost(url, para.GetXml());
UnifierOrderResult ret = new UnifierOrderResult();
ret.FillEntityWithXml(retval);
return ret;
}
} }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Zmm.Wx.MP.TenPay
{
public class TenpayData
{
const string appId = "appid";
public string nonceStr { get; set; }
public string package { get; set; }
const string signType = "MD5";
public string timeStamp { get; set; }
public string paySign { get; set; } public void Execute(string prepay_id)
{
nonceStr = DateTime.Now.Ticks.ToString();
package = "prepay_id=" + prepay_id; TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
timeStamp = Convert.ToInt64(ts.TotalSeconds).ToString(); var str = string.Format("appId={0}&nonceStr={1}&package={2}&signType={3}&timeStamp={4}&key=154f138bf4407a9c07ac7240a2b7135f", appId, nonceStr, package, signType, timeStamp); paySign = MD5Util.GetMD5(str); } }
}
using System;
using System.Security.Cryptography;
using System.Text; namespace Zmm.Wx.MP.TenPay
{
/// <summary>
/// MD5Util 的摘要说明。
/// </summary>
public class MD5Util
{
public MD5Util()
{
//
// TODO: 在此处添加构造函数逻辑
//
} /** 获取大写的MD5签名结果 */
public static string GetMD5(string encypStr)
{
string retStr;
MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider(); //创建md5对象
byte[] inputBye;
byte[] outputBye; //使用GB2312编码方式把字符串转化为字节数组.
try
{
inputBye = Encoding.UTF8.GetBytes(encypStr);
}
catch
{
inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
}
outputBye = m5.ComputeHash(inputBye); retStr = System.BitConverter.ToString(outputBye);
retStr = retStr.Replace("-", "").ToUpper();
return retStr;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Zmm.Wx.MP.TenPay
{
public class OrderResult
{
//Help:http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_7
/// <summary>
/// 返回状态码 SUCCESS/FAIL 此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
/// </summary>
public string return_code { get; set; }
/// <summary>
///
/// </summary>
public string return_msg { get; set; }
public string appid { get; set; }
public string mch_id { get; set; }
public string device_info { get; set; }
public string nonce_str { get; set; }
public string sign { get; set; }
public string result_code { get; set; }
public string err_code { get; set; }
public string err_code_des { get; set; }
public string openid { get; set; }
public string is_subscribe { get; set; }
public string trade_type { get; set; }
public string bank_type { get; set; }
public string CMC { get; set; }
public string total_fee { get; set; }
public string fee_type { get; set; }
public string cash_fee { get; set; }
public string cash_fee_type { get; set; }
public string coupon_fee { get; set; }
public string coupon_count { get; set; }
//public string coupon_batch_id_$n {get;set;}
//public string coupon_id_$n {get;set;}
//public string coupon_fee_$n {get;set;}
public string transaction_id { get; set; }
public string out_trade_no { get; set; }
public string attach { get; set; }
public string time_end { get; set; } public override string ToString()
{
List<string> items = new List<string>();
var props = this.GetType().GetProperties();
foreach (var prop in props)
{
var val = prop.GetValue(this);
if (val != null && !string.IsNullOrEmpty(val.ToString()))
items.Add(prop.Name + "=" + val);
}
return string.Join(";", items);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq; namespace Zmm.Wx.MP.TenPay
{
public static class XmlToClass
{
public static void FillEntityWithXml<T>(this T entity, string xml) where T : /*MessageBase*/ class, new()
{ XElement xe = XElement.Parse(xml);
entity.FillEntityWithXml(xe); }
public static void FillEntityWithXml<T>(this T entity, XElement xe) where T : /*MessageBase*/ class, new()
{
entity = entity ?? new T(); var props = entity.GetType().GetProperties();
foreach (var prop in props)
{
var propName = prop.Name;
if (xe.Element(propName) != null)
{
prop.SetValue(entity, xe.Element(propName).Value);
}
} }
}
}
Action如下:
public ActionResult Pay()
{
var ret = Zmm.Wx.MP.TenPay.UnifierOrderResult.Get("衢州旅游特惠卡", "DetailTest", "AttachTest", DateTime.Now.Ticks + "1", 1, "218.244.138.166", "http://www.xuduovip.com/wzf/home/notify", "JSAPI", "Id1", "oLcmxt0gWL5nhdsgPAYB2iBM-IMs");
if (ret.return_code == "FAIL")
{
return Content(ret.return_msg);
}
if (ret.result_code == "FAIL")
{
return Content(ret.err_code + "," + ret.err_code_des);
}
Zmm.Wx.MP.TenPay.TenpayData data = new Wx.MP.TenPay.TenpayData();
data.Execute(ret.prepay_id);
return View(data);
}
public ActionResult Notify()
{
XElement xe = XElement.Load(Request.InputStream);
OrderResult ret = new Wx.MP.TenPay.OrderResult();
ret.FillEntityWithXml(xe);
Zmm.BLL.AppLogService.Info("Notify:" + ret);
return Content(@"<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
}
view 如下:
@model Zmm.Wx.MP.TenPay.TenpayData
@{
ViewBag.Title = "Pay";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Pay</h2>
<script language="javascript" type="text/javascript">
function onBridgeReady() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": "appid", //公众号名称,由商户传入
"timeStamp": "@Model.timeStamp", //时间戳,自1970年以来的秒数
"nonceStr": "@Model.nonceStr", //随机串
"package": "@Model.package",
"signType": "MD5", //微信签名方式:
"paySign": "@Model.paySign" //微信签名
},
function (res) {
alert("callback:" + res.err_msg);
if (res.err_msg == "get_brand_wcpay_request:ok") { } // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
}
);
}
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}
</script>
jsapi方式测试成功,主要打开微信网页的时候一定要全部小写。
native方式:
action:
var ret = Zmm.Wx.MP.TenPay.UnifierOrderResult.Get("衢州旅游特惠卡", "DetailTest", "AttachTest", DateTime.Now.Ticks + "1", 20000, "218.244.138.166", "http://www.xuduovip.com/wzf/home/notify", "NATIVE", "Id1", "oLcmxt0gWL5nhdsgPAYB2iBM-IMs");
ViewBag.Code = Zmm.Common.QRCode.Create(ret.code_url);
return View();
view:
@{
ViewBag.Title = "测试网页";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>公众号Native支付测试网页</h2>
<div class="WCPay">
<a href="@Url.Action("Pay", new {showwxpaytitle=1})">点击提交可体验微信支付</a>
<img src="@ViewBag.Code" />
</div>
二维码生成类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZXing;
using ZXing.QrCode;
using System.Drawing;
using System.IO;
namespace Zmm.Common
{
public class QRCode
{
public static string Create(string s)
{
var options = new QrCodeEncodingOptions
{
DisableECI = true,
CharacterSet = "UTF-8",
Width = 300,
Height = 300
};
var writer = new BarcodeWriter();
writer.Format = BarcodeFormat.QR_CODE;
writer.Options = options;
var image = writer.Write(s);
MemoryStream ms = new MemoryStream(); //新建内存流
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return "data:image/jpeg;base64," + Convert.ToBase64String(ms.GetBuffer());
}
}
}
native测试成功。
乱写,凑合着看。写文档确实比较麻烦,也理解腾讯的那些兄弟了。
MVC 微信支付的更多相关文章
- 【原创分享·微信支付】C# MVC 微信支付教程系列之现金红包
微信支付教程系列之现金红包 最近最弄这个微信支付的功能,然后扫码.公众号支付,这些都做了,闲着无聊,就看了看微信支付的其他功能,发现还有一个叫“现金红包”的玩意,想 ...
- 【原创分享·微信支付】 C# MVC 微信支付教程系列之扫码支付
微信支付教程系列之扫码支付 今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添 ...
- 【原创分享·微信支付】 C# MVC 微信支付教程系列之公众号支付
微信支付教程系列之公众号支付 今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后再通 ...
- 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送
微信支付之微信模板消息推送 今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...
- C# MVC 微信支付教程系列之公众号支付
微信支付教程系列之公众号支付 今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后 ...
- 【分享·微信支付】 C# MVC 微信支付教程系列之公众号支付
微信支付教程系列之公众号支付 今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后 ...
- C# MVC 微信支付之微信模板消息推送
微信支付之微信模板消息推送 今天我要跟大家分享的是"模板消息"的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信 ...
- .net mvc 微信支付
一.微信第三方登录 通过微信打开链接:http://www.hzm.com/Entry/Login 微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server ...
- asp.net mvc 微信支付代码分析(根据沐雪微信平台3.1商城业务来分析)
开发微信应用,微信支付是永远要面对的.现在的微信支付相对以往已经很稳定,很少出现诡异情况.再加上无数人开发的经验分享,现在开发微信支付已经没什么难度了. 我这次主要是想基于沐雪微信平台的微商城业务来分 ...
随机推荐
- cargo failed to finish deploying within the timeout period [120000]
cargo插件,报错:failed to finish deploying within the timeout period [120000] 解决方法:配置timeout为0 <plugin ...
- 初识Python第二天(1)
在Python中,一切事物都是对象,对象是基于类创建的,对象继承了类的属性,方法等. 一.传递参数 1.1新建python文件,名为twoday_args.py,输出以下代码 import sys p ...
- zigbee学习之路(五):定时器1(查询方式)
一.前言 今天,我们来学习几乎所有单片机都有的功能,定时器的使用,定时器对单片机来说是相当重要的,有了它,单片机就可以进行一些复杂的工作. 二.原理与分析 谈到定时器的控制,我们最先想到的是要给它赋初 ...
- LA 3523 圆桌骑士
题目链接:http://vjudge.net/contest/141787#problem/A http://poj.org/problem?id=2942 此题很经典 知识点:DFS染色,点-双连通 ...
- php入门
最近公司招了几个应届毕业生,他们对前端的了解还挺多,但是对后端的技术一无所知,我觉得,作为一个前端攻城狮,如果你有远大的抱负,就应该雨露均沾... 今天我就跟大家讲一讲PHP最基本的入门,至少别人问起 ...
- Codeforces Round #356 (Div. 2)
A. Bear and Five Cards time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- CSS基础介绍
CSS介绍 CSS是指层叠样式表,CSS样式表极大的提高了工作效率 CSS基础语法 1. 首先选择一个属性 2. 选择了属性以后,用大括号括起来 3. 括号里面是对应的属性和属性值,如: select ...
- Android Studio教程从入门到精通
最新2.0系列文章参考: Android Studio2.0 教程从入门到精通Windows版 - 安装篇Android Studio2.0 教程从入门到精通Windows版 - 入门篇Android ...
- MFC编程入门之七(对话框:为对话框添加控件)
创建对话框资源需要创建对话框模板.修改对话框属性.为对话框添加各种控件等步骤,前面一讲中已经讲了创建对话框模板和修改对话框属性,本节继续讲如何为对话框添加控件. 上一节中创建了一个名为"A ...
- Java防盗链机制
对于防盗链技术,网上提供了很多很多的相关技术,但是不是特别复杂就是效果不好. 这里在网上找到一种思路,就是关于HTTP协议响应头中包含的Referer,告诉服务器我是从哪个页面链接过来的,服务器籍此可 ...