【移动支付】.NET支付宝App支付接入
一、前言
最近也是为了新产品忙得起飞,博客都更新的慢了。新产品为了方便用户支付,需要支付宝扫码接入。这活落到了我的身上。产品是Windows系统下的桌面软件,通过软件生成二维码支付。界面以原生的MVVM编写,下面叙述一下基本的过程,做过的老司机可以直接点关闭了。
二、申请接口
申请接口是第一步,首先有这么几件事:
- 公司具有支付宝账户
- 公司具有营业资质(废话)
- 创建应用,签约电脑网站支付,手机支付,App支付。
- 创建私钥、公钥、支付宝公钥
- 配置网关及回调地址
需要注意的是以下几点:
- 创建应用时,名称不要带有“支付”、“pay”等字样,图片建议高清
- 创建应用时,签约支付需要一些申请材料,如:营业资质照片,公司照片4张,应用的介绍(名称,下载地址,公司网站是否有该应用,该应用出现支付宝支付的界面样式)
- 签约后需要审核,大致一天,(阿里确实快,腾讯微信要4天),审核通过会发送一份邮件,里面有链接,点击链接完成签约
- 创建私钥、公钥、支付宝公钥,在支付宝接口网站上有官方工具,下载使用即可
- 网关与回调地址要与公司网站形成关联,比如是二级域名;如果网关、回调地址与公司网站没什么联系,恐怕不行。
三、代码流程
有三个构成元素。客户端软件,商户服务器后台,支付宝后台
客户端软件点击“获取支付二维码”去获得一个可支付的二维码:
封装客户端的一些必要信息发送给商户服务器后台形成一个商户订单
/// <summary>
/// 获取二维码信息
/// </summary>
/// <param name="packageClientInfo">封装信息</param>
/// <param name="serverAddress">商户产品服务器地址</param>
/// <returns></returns>
public static void GetQRCodeInfo(string packageClientInfo, string serverAddress, Action<string> getQRCodeAction)
{
if (!string.IsNullOrEmpty(packageClientInfo))
{
try
{
HttpClient httpsClient = new HttpClient
{
BaseAddress = new Uri(serverAddress),
Timeout = TimeSpan.FromMinutes()
}; if (DsClientOperation.ConnectionTest(httpsClient))
{
StringContent strData = new StringContent(
packageClientInfo,
Encoding.UTF8,
RcCommonNames.JasonMediaType);
string PostUrl = httpsClient.BaseAddress + "api/AlipayForProduct/GetQRCodeString";
Uri address = new Uri(PostUrl);
Task<HttpResponseMessage> response = httpsClient.PostAsync(address, strData);
response.ContinueWith(
(postTask) =>
{
if (postTask.IsFaulted)
{
throw postTask.Exception;
}
HttpResponseMessage postResponse = postTask.Result;
postResponse.EnsureSuccessStatusCode();
var result = postResponse.Content.ReadAsStringAsync().Result;
getQRCodeAction(JsonConvert.DeserializeObject<string>(result)); //注意这个委托
return result;
});
}
}
catch
{
// ignored
}
}
}
这里的委托方法是用来生成二维码的,当你从这个“api/AlipayForProduct/GetQRCodeString”返回一些字符串(result),比如返回的是:
"http://xxx.xxx.com/AlipayForProduct/SendInfoToAlipay?ordernumber=" + $"{orderNumber}";(orderNumber为商户订单号)
然后使用ThoughtWorks.QRCode.dll去生成二维码
/// <summary>
/// 根据字符串得到相应的二维码
/// </summary>
/// <param name="qrInfo"></param>
/// <param name="productName"></param>
/// <param name="version"></param>
/// <returns></returns>
public static Image CreateQRCodeImage(string qrInfo, string productName, string version)
{
try
{
if (!string.IsNullOrEmpty(qrInfo))
{
QRCodeEncoder encoder = new QRCodeEncoder
{
QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE,
QRCodeScale = ,
QRCodeVersion = ,
QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M
};
//编码方式(注意:BYTE能支持中文,ALPHA_NUMERIC扫描出来的都是数字)
//大小(值越大生成的二维码图片像素越高)
//版本(注意:设置为0主要是防止编码的字符串太长时发生错误)
//错误效验、错误更正(有4个等级) Image image = encoder.Encode(qrInfo, Encoding.GetEncoding("utf-8"));
string filename = $"{productName}_{version}.png";
var userLocalPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
var docPath = Path.Combine(userLocalPath, @"YourProduct\QRCode");
if (!Directory.Exists(docPath))
{
Directory.CreateDirectory(docPath);
}
string filepath = Path.Combine(docPath, filename);
using (FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write))
{
image.Save(fs, System.Drawing.Imaging.ImageFormat.Png);
fs.Close();
image.Dispose();
}
return image;
}
}
catch (Exception)
{
return null;
}
return null;
}
这样就产生了二维码,说白了,就是把一个服务的api由字符串变成了图片,当用户使用支付宝app去扫这个二维码时,会去请求这个api:
"http://xxx.xxx.com/AlipayForProduct/SendInfoToAlipay?ordernumber=" + $"{orderNumber}";(orderNumber为商户订单号)
public string SendInfoToAlipay()
{
string orderNumber = Request["orderNumber"];
if (!string.IsNullOrEmpty(orderNumber))
{
var matchedItem = db.OrderInfoForProduct.FirstOrDefault(x => x.OrderNumber == orderNumber); //验证下商户服务器后台有没有这个订单
if (matchedItem != null && matchedItem.IsPaid == false)
{
//公共参数
var alipayServerURL = "https://openapi.alipay.com/gateway.do";
var app_id = appID;
var privateKeyPem = applicationPrivateKey;
var format = "json";
var version = "1.0";
var signType = "RSA2"; //请求参数
var out_trade_no = orderNumber; //商家订单号
var product_code = "FAST_INSTANT_TRADE_PAY"; //销售产品码
var total_amount = "Your Money"; //订单总金额
var subject = "Your Title"; //订单标题
var body = "Your Body"; //订单描述 IAopClient client = new DefaultAopClient(
alipayServerURL,
app_id,
privateKeyPem,
format,
version,
signType); var returnurl = $"http://xxx.xxx.com/AlipayForProduct/AlipayResult";
var notifyurl = $"http://xxx.xxx.com/AlipayForProduct/UpdatePayStatus";
AlipayTradeWapPayRequest requestWap = new AlipayTradeWapPayRequest
{
BizContent = "{" +
" \"body\":\"" + body + "\"," +
" \"subject\":\"" + subject + "\"," +
" \"out_trade_no\":\"" + out_trade_no + "\"," +
" \"total_amount\":" + total_amount + "," +
" \"product_code\":\"" + product_code + "\"" +
" }"
}; requestWap.SetNotifyUrl(notifyurl); //异步请求
requestWap.SetReturnUrl(returnurl); //同步请求 AlipayTradeWapPayResponse responseWap = client.pageExecute(requestWap); string divNone = "<div style='display:none'>" + responseWap.Body + "</div>";
return divNone;
}
}
return string.Empty;
}
异步请求一般需要做这么几件事:
- 用户扫码支付完之后,支付宝后台会把所有需要验证的信息发给你,除了一个参数不需要验签完,其余都需要验签;
- 如果验签成功且支付状态也是成功交易后,你需要更新商户服务器后台关于此条商户订单的状态,比如将其支付状态变成已支付,填充支付时间等等;
/// <summary>
/// 回调函数
/// </summary>
[HttpPost]
public void UpdatePayStatus()
{
SortedDictionary<string, string> sPara = GetRequestPost(); if (sPara.Count > )
{
//非验签参数
var sign_type = Request.Form["sign_type"]; //接收参数并排序
var seller_id = Request.Form["seller_id"]; //卖家支付宝用户号
var trade_status = Request.Form["trade_status"]; //交易状态
var notify_time = Request.Form["notify_time"]; //通知时间
var app_id = Request.Form["app_id"]; //开发者AppId
var out_trade_no = Request.Form["out_trade_no"]; //交易订单号
var total_amount = Request.Form["total_amount"]; //订单金额
var receipt_amount = Request.Form["receipt_amount"]; //实收金额
var invoice_amount = Request.Form["invoice_amount"]; //开票金额
var buyer_pay_amount = Request.Form["buyer_pay_amount"]; //付款金额
var body = Request.Form["body"]; //商品描述
var gmt_payment = Request.Form["gmt_payment"]; //交易付款时间 var tradeGuid = new Guid(out_trade_no);
//验签
try
{
var isVerfied = AlipaySignature.RSACheckV1(sPara, alipayPublicKey, "utf-8", sign_type, false);
if (isVerfied)
{
if (app_id == appID && seller_id == sellerID)
{
var isTradeSuccess = string.Equals(trade_status, "TRADE_SUCCESS") || string.Equals(trade_status, "TRADE_FINISHED");
if (isTradeSuccess)
{
//商户验证逻辑及数据更新逻辑
}
}
}
}
catch (Exception)
{ }
}
else
{ }
} /// <summary>
/// 参数排序字典
/// </summary>
/// <returns></returns>
private SortedDictionary<string, string> GetRequestPost()
{
SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();
NameValueCollection coll = Request.Form;
String[] requestItem = coll.AllKeys;
foreach (string t in requestItem)
{
sArray.Add(t, Request.Form[t]);
}
return sArray;
}
同步请求一般需要做这么几件事:
1. 当异步调用完后,如果支付成功而且商户服务器后台对此条订单号处理也正确的话;同步请求可以再做一次验证
2. 如果验证成功,跳转支付成功页面;如果失败,跳转支付失败页面。
public ActionResult AlipayResult()
{
SortedDictionary<string, string> sPara = GetRequestGet();
if (sPara.Count > )
{
//非验签参数
var sign_type = Request.QueryString["sign_type"]; //接收参数并排序
var seller_id = Request.QueryString["seller_id"]; //卖家支付宝用户号
var app_id = Request.QueryString["app_id"]; //开发者AppId
var out_trade_no = Request.QueryString["out_trade_no"]; //交易订单号 var orderNumberGuid = new Guid(out_trade_no);
try
{
var isVerfied = AlipaySignature.RSACheckV1(sPara, alipayPublicKey, "utf-8", sign_type, false);
if (isVerfied)
{
if (app_id == appID && seller_id == sellerID)
{
//你的支付成功页面
}
} }
catch
{
//你的支付失败页面
}
}
else
{
//你的支付失败页面
}
return View();
} /// <summary>
/// 参数排序字典
/// </summary>
/// <returns></returns>
private SortedDictionary<string, string> GetRequestGet()
{
SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();
NameValueCollection coll = Request.QueryString; String[] requestItem = coll.AllKeys; foreach (string t in requestItem)
{
sArray.Add(t, Request.QueryString[t]);
}
return sArray;
}
四、结尾
参加工作以来一直主攻WPF,偶尔搞搞Web还是挺有趣的!
【移动支付】.NET支付宝App支付接入的更多相关文章
- H5使用codovar插件实现支付宝支付(支付宝APP支付模式,前端)
H5打包的app实现支付及支付宝支付,本章主要详解支付宝支付,微信支付请查看另一篇“H5使用codovar插件实现微信支付(微信APP支付模式,前端)” ps:本文只试用H5开发的,支付宝 APP支付 ...
- 微信APP支付,支付宝APP支付demo
最近公司新开发的APP中,需要集成微信支付和支付宝支付,2个平台申请的都是APP支付.这是个人第一次单独的,完整的做完2个平台的支付. 这里我主要用到了2个接口:支付接口,订单查询接口,虽然2个平台的 ...
- 支付宝app支付服务端流程
支付宝APP支付服务端详解 前面接了微信支付,相比微信支付,支付宝APP支付提供了支付封装类,下面将实现支付宝APP支付.订单查询.支付结果异步通知.APP支付申请参数说明,以及服务端返回APP端发起 ...
- 微信、支付宝App支付-JPay0.0.2发布
JPay 对微信App支付.支付宝App支付的二次封装,对外提供一个相对简单的接口以及支付结果的回调 GitHub:https://github.com/Javen205/JPay OsChina:h ...
- H5使用codovar插件实现微信支付(微信APP支付模式,前端)
H5打包的app实现微信支付及支付宝支付,本章主要详解微信支付,支付宝支付请查看另一篇“H5使用codovar插件实现支付宝支付(支付宝APP支付模式,前端)” ps:本文只试用H5开发的,微信 AP ...
- 支付宝APP支付IOS手机端java后台版
版权声明:http://blog.csdn.net/u012131769/article/details/76639527#t8 转载:http://blog.csdn.net/u012131769/ ...
- 支付宝APP支付开发- IOException : DER input, Integer tag error
支付宝APP支付Java开发报错: 1 java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: I ...
- 支付宝APP支付开发- IOException : DerInputStream.getLength(): lengthTag=127, too big.
支付宝APP支付Java开发报错: IOException : DerInputStream.getLength(): lengthTag=127, too big. 后来排查是因为没有设置私钥.
- 支付宝APP支付之Java后台生成签名具体步骤
/** *支付宝支付 * @param orderId 订单编号 * @param actualPay 实际支付金额 * @return */ private String getOrderInfoB ...
- Android版-支付宝APP支付
此项目已开源 赶快来围观 Start支持下吧 [客户端开源地址-JPay][服务端端开源地址-在com.javen.alipay 包名下] 上一篇详细介绍了微信APP支付 点击这里 此篇文章来详细介绍 ...
随机推荐
- PHPStrom 里修改Emmet对php的自动扩展
PHPStrom 7.1.3 Emmet 想必大家都比较清楚了.Emmet有个特点,对于匹配不到的符号,仍然会自动扩展为标签的形式,比如我输入aaaa,然后按tab,会自动扩展为<aaaa> ...
- ubuntu apt-xxx
1. apt-get install xxx 2. dpkg -l ; list software already installed. 3. apt-cache dumpavail ; print ...
- 测试面试必会sql(1)
测试一般各种查询语句用的较多,下面的查询语句都是需要熟悉的 Course表 Score表 Student表 Teacher表 1,查询课程编号为“02”的总成绩 SELECT * FROM `Scor ...
- vue中的样式
一.使用class样式: CSS部分: <style> .green{ color:green; } .italic{ font-style:italic; } .thin{ ; } .a ...
- smartgit 过期
进入到安装目录把Setting.xml 文件删除然后,再次打开就可以正常使用了.
- Memcached&PHP-Memcache安装配置
参考文档: memcache官网:https://memcached.org/ 参考:http://www.runoob.com/memcached/memcached-install.html 参考 ...
- eBay报告:德国或将成为外贸电商热门市场
[亿邦动力网讯]1月3日消息,日前,跨境电商平台eBay发布公告称,自2014年1月中旬起,卖家在eBay德国 ( eBay.de ).eBay 奥地利 ( eBay.at ) 或eBay瑞士 ( e ...
- ES6的新特性(5)——数值的扩展
数值的扩展 二进制和八进制表示法 ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示. 0b111110111 === 503 // true 0o767 === ...
- 欢迎来怼--第三十次Scrum会议
一.小组信息 队名:欢迎来怼 小组成员 队长:田继平 成员:李圆圆,葛美义,王伟东,姜珊,邵朔,阚博文 小组照片 二.开会信息 时间:2017/11/18 17:20~17:53,总计33min. 地 ...
- python获取前几天的时间
days的参数就是你想获取前多少天的数据,如果是昨天的话,则days=1 import datetime today=datetime.date.today() oneday=datetime.tim ...