一、前言

       最近也是为了新产品忙得起飞,博客都更新的慢了。新产品为了方便用户支付,需要支付宝扫码接入。这活落到了我的身上。产品是Windows系统下的桌面软件,通过软件生成二维码支付。界面以原生的MVVM编写,下面叙述一下基本的过程,做过的老司机可以直接点关闭了。

二、申请接口

        申请接口是第一步,首先有这么几件事:

  1. 公司具有支付宝账户
  2. 公司具有营业资质(废话)
  3. 创建应用,签约电脑网站支付,手机支付,App支付。
  4. 创建私钥、公钥、支付宝公钥
  5. 配置网关及回调地址

需要注意的是以下几点:

  1. 创建应用时,名称不要带有“支付”、“pay”等字样,图片建议高清
  2. 创建应用时,签约支付需要一些申请材料,如:营业资质照片,公司照片4张,应用的介绍(名称,下载地址,公司网站是否有该应用,该应用出现支付宝支付的界面样式)
  3. 签约后需要审核,大致一天,(阿里确实快,腾讯微信要4天),审核通过会发送一份邮件,里面有链接,点击链接完成签约
  4. 创建私钥、公钥、支付宝公钥,在支付宝接口网站上有官方工具,下载使用即可
  5. 网关与回调地址要与公司网站形成关联,比如是二级域名;如果网关、回调地址与公司网站没什么联系,恐怕不行。

三、代码流程

        有三个构成元素。客户端软件,商户服务器后台,支付宝后台

客户端软件点击“获取支付二维码”去获得一个可支付的二维码:

封装客户端的一些必要信息发送给商户服务器后台形成一个商户订单

        /// <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;
}

异步请求一般需要做这么几件事:

  1. 用户扫码支付完之后,支付宝后台会把所有需要验证的信息发给你,除了一个参数不需要验签完,其余都需要验签;
  2. 如果验签成功且支付状态也是成功交易后,你需要更新商户服务器后台关于此条商户订单的状态,比如将其支付状态变成已支付,填充支付时间等等;
        /// <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支付接入的更多相关文章

  1. H5使用codovar插件实现支付宝支付(支付宝APP支付模式,前端)

    H5打包的app实现支付及支付宝支付,本章主要详解支付宝支付,微信支付请查看另一篇“H5使用codovar插件实现微信支付(微信APP支付模式,前端)” ps:本文只试用H5开发的,支付宝 APP支付 ...

  2. 微信APP支付,支付宝APP支付demo

    最近公司新开发的APP中,需要集成微信支付和支付宝支付,2个平台申请的都是APP支付.这是个人第一次单独的,完整的做完2个平台的支付. 这里我主要用到了2个接口:支付接口,订单查询接口,虽然2个平台的 ...

  3. 支付宝app支付服务端流程

    支付宝APP支付服务端详解 前面接了微信支付,相比微信支付,支付宝APP支付提供了支付封装类,下面将实现支付宝APP支付.订单查询.支付结果异步通知.APP支付申请参数说明,以及服务端返回APP端发起 ...

  4. 微信、支付宝App支付-JPay0.0.2发布

    JPay 对微信App支付.支付宝App支付的二次封装,对外提供一个相对简单的接口以及支付结果的回调 GitHub:https://github.com/Javen205/JPay OsChina:h ...

  5. H5使用codovar插件实现微信支付(微信APP支付模式,前端)

    H5打包的app实现微信支付及支付宝支付,本章主要详解微信支付,支付宝支付请查看另一篇“H5使用codovar插件实现支付宝支付(支付宝APP支付模式,前端)” ps:本文只试用H5开发的,微信 AP ...

  6. 支付宝APP支付IOS手机端java后台版

    版权声明:http://blog.csdn.net/u012131769/article/details/76639527#t8 转载:http://blog.csdn.net/u012131769/ ...

  7. 支付宝APP支付开发- IOException : DER input, Integer tag error

    支付宝APP支付Java开发报错: 1 java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: I ...

  8. 支付宝APP支付开发- IOException : DerInputStream.getLength(): lengthTag=127, too big.

    支付宝APP支付Java开发报错: IOException : DerInputStream.getLength(): lengthTag=127, too big. 后来排查是因为没有设置私钥.

  9. 支付宝APP支付之Java后台生成签名具体步骤

    /** *支付宝支付 * @param orderId 订单编号 * @param actualPay 实际支付金额 * @return */ private String getOrderInfoB ...

  10. Android版-支付宝APP支付

    此项目已开源 赶快来围观 Start支持下吧 [客户端开源地址-JPay][服务端端开源地址-在com.javen.alipay 包名下] 上一篇详细介绍了微信APP支付 点击这里 此篇文章来详细介绍 ...

随机推荐

  1. async+await 让界面飞,让双手爽

    .net 4.5已经发布很久了,但是一直也没有静下心来好好的研究微软给开发者带来的喜悦. 今天我将简单的介绍下 async + await 这对搭档的出现,如何让频繁假死的界面飞起来(其实只是不再阻塞 ...

  2. macOS中启动Tomcat提示Cannot find ./catalina.sh

    首先查看Tomcat目录下是否存在catalina.sh,如果文件不存在,文件丢失,最好的方式是重装Tomcat Tomcat官网:http://tomcat.apache.org/ 如果文件存在,那 ...

  3. KEIL5的安装

    安装注意事项 1.最好不要安装在带有中文路径的文件夹. 2.试用版的Keil MDK只能编译32K以下的代码,代码大于32K只能使用正版或破解版才能编译通过. 安装MKD 这里选择MKD512A版本安 ...

  4. python爬取斗图网中的 “最新套图”和“最新表情”

    1.分析斗图网 斗图网地址:http://www.doutula.com 网站的顶部有这两个部分: 先分析“最新套图” 发现地址栏变成了这个链接,我们在点击第二页 可见,每一页的地址栏只有后面的pag ...

  5. appium自动化环境搭建

    1.java开发环境JDK 2.android SDK(platform/platform tools/tools/build tools) 3.python下载安装(pip) 4.appium下载安 ...

  6. JUC——ThreadFactory线程工厂类(四)

    ThreadFactory线程工厂类 在默认情况下如果要想创建一个线程类对象,大部分情况的选择是:直接通过子类为父类进行实例化,利用Runnable子类为Runnable接口实例化. 或者直接调用La ...

  7. 8 个用于业余项目的优秀 Python 库

    在 Python/Django 的世界里有这样一个谚语:为语言而来,为社区而留.对绝大多数人来说的确是这样的,但是,还有一件事情使得我们一直停留在 Python 的世界里,不愿离开,那就是我们可以很容 ...

  8. NO--10今天带大家回忆回忆“闭包”吧!

    对于‘闭包,我相信很多人都掉进过这个坑里,也相信很多人没能详细的理解这个问题,今天带大家再次走进闭包: 写这篇文章时的心情是十分忐忑的,因为对于我们今天的主角:闭包,很多小伙伴都写过关于它的文章,相信 ...

  9. 堆中的路径(MOOC)

    将一系列给定数字插入一个初始为空的小顶堆H[].随后对任意给定的下标i,打印从H[i]到根结点的路径. 输入格式: 每组测试第1行包含2个正整数N和M(≤),分别是插入元素的个数.以及需要打印的路径条 ...

  10. zabbix_agentd-install.sh (脚本部署zabbix_agentd服务)

    原文发表于cu:2016-05-20 基于http://www.cnblogs.com/netonline/p/7406598.html(http://blog.chinaunix.net/uid-2 ...