ASP.NET Core2.0 环境下MVC模式的支付宝PC网站支付接口-沙箱环境开发测试
1.新建.NET Core web项目
2.Controllers-Models-Views 分三个大部分
3.下载安装最新sdk
官方的SDK以及Demo都还是.NET Framework的,根据官方文档说明新建网站后还是需要引用官方SDK的源码,
在这里直接使用网上一位朋友的用.NET Standard 2.0 进行实现了支付宝服务端SDK,Alipay.AopSdk.Core(github:https://github.com/stulzq/Alipay.AopSdk.Core) ,支持.NET CORE 2.0。
为了使用方便以直接使用Nuget下载安装,直接使用集成的SDK即可,道理和官网支付宝demo一个样。
通过Nuget安装:Install-Package Alipay.AopSdk.Core
4.首先要配置支付宝商户信息 在这里使用的是沙箱账号
新建一个配置类基本不用但是后续代码还是可以方便使用。
Config.cs
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks; namespace Alipay.PCPayment
{
public class Config
{
// 应用ID,您的APPID 沙箱
public static string AppId= "2016********3";
/// <summary>
/// 合作商户uid 沙箱
/// </summary>
public static string Uid= "208**********2"; // 支付宝网关 沙箱地址
public static string Gatewayurl="https://openapi.alipaydev.com/gateway.do";
// 支付宝网关 生产地址
// public static string Gatewayurl = "https://openapi.alipay.com/gateway.do"; /// <summary>
/// 异步通知 处理支付宝接口通知返回 获取是否是支付宝服务器发来的请求的验证结果
/// </summary>
/// <param name="notifyId">通知验证ID</param>
/// <returns>验证结果</returns>
public static async Task<string> VerifyNotifyAsync(string notifyId)
{
return await SendAsync(Uid, notifyId);
}
/// <summary>
/// //支付宝消息验证地址
/// </summary>
private const string API_URL = "https://mapi.alipay.com/gateway.do?service=notify_verify&"; /// <summary>
/// 获取是否是支付宝服务器发来的请求的验证结果
/// </summary>
/// <param name="partner">partner 合作身份ID</param>
/// <param name="notify_id">通知验证ID</param>
/// <returns>验证结果</returns>
public static async Task<string> SendAsync(string partner, string notify_id)
{
string strResult;
string verifyUrl = API_URL + "partner=" + partner + "¬ify_id=" + notify_id;
//获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
try
{
using (var client = new HttpClient())
{ //client.Timeout = 120000;
var response = await client.GetAsync(verifyUrl);
if (response.IsSuccessStatusCode)
{
byte[] data = await response.Content.ReadAsByteArrayAsync();
Encoding.UTF8.GetString(data);
return strResult= "true";
} }
}
catch (Exception exp)
{
strResult = "错误信息:" + exp.Message;
}
return string.Empty;
}
public static ContentResult Response_Success(string msg = null)
{
return new ContentResult
{
Content = msg ?? "success"
};
}
public static ContentResult ResponseFail(string msg = null)
{
return new ContentResult
{
Content = msg ?? "fail"
};
}
} }
5. 添加一个控制器 PayController
using System;
using System.Collections.Generic;
using Alipay.AopSdk.AspnetCore;
using Alipay.AopSdk.Core;
using Alipay.AopSdk.Core.Domain;
using Alipay.AopSdk.Core.Request;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Alipay.Demo.PCPayment.Interfaces;
using Microsoft.Extensions.Logging;
namespace Alipay.PCPayment.Controllers
{
/// <summary>
/// PC网站支付
/// </summary>
public class PayController : Controller
{
private readonly IAlipayService _alipayService;
private readonly IAccounts _IAccounts;
private readonly ILogger _logger;
public PayController(IAlipayService alipayService, ILogger<PayController> logger)
{
_alipayService = alipayService; _logger = logger;
}
//_alipayService.Execute(); #region 发起支付 public IActionResult Index()
{
return View();
}
/// <summary>
/// 发起支付请求
/// </summary>
/// <param name="tradeno">外部订单号,商户网站订单系统中唯一的订单号</param>
/// <param name="subject">订单名称</param>
/// <param name="totalAmout">付款金额</param>
/// <param name="itemBody">商品描述</param>
/// <returns></returns>
[HttpPost]
public void PayRequest(string tradeno, string subject, string totalAmout, string itemBody)
{
// DefaultAopClient client = new DefaultAopClient(Config.Gatewayurl, Config.AppId, Config.PrivateKey, "json", "2.0",
//Config.SignType, Config.AlipayPublicKey, Config.CharSet, false);
// 组装业务参数model
AlipayTradePagePayModel model = new AlipayTradePagePayModel
{
Body = itemBody,
Subject = subject,
TotalAmount = totalAmout,
OutTradeNo = tradeno,
ProductCode = "FAST_INSTANT_TRADE_PAY"
}; AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
// 设置同步回调地址 可以是调试模式地址 并非公网或域名地址 Pay走的是控制器的
request.SetReturnUrl("http://190.120.120.01:110/Pay/Callback");
// 设置异步通知接收地址 必须是公网或域名地址 Pay走的是控制器的方法
request.SetNotifyUrl("http://50.200.50.10:110/Pay/AlipayNotify");
// 将业务model载入到request
request.SetBizModel(model);
var response = _alipayService.SdkExecute(request);
Console.WriteLine($"订单支付发起成功,订单号:{tradeno}");
//跳转支付宝支付 支付网关地址
Response.Redirect(Config.Gatewayurl + "?" + response.Body);
}
#endregion
支付异步回调通知 使用异步通知来获取支付结果,异步通知即支付宝主动请求我们提供的地址,我们根据请求数据来校验,获取支付结果。
#region 支付异步回调通知
/// <summary>
/// 异步通知即支付宝主动请求我们提供的地址,我们根据请求数据来校验,获取支付结果。
/// 支付异步回调通知 需配置域名 因为是支付宝主动post请求这个action 所以要通过域名访问或者公网ip
/// </summary>//public async Task<IActionResult> AlipayNotify([FromForm]Dictionary<string,string> NotifyArray)
public async Task<IActionResult> AlipayNotify()
{
/* 实际验证过程建议商户添加以下校验。
1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
*/
Dictionary<string, string> NotifyArray = GetRequestPost();
//通知验证ID
string notifyId = NotifyArray["notify_id"];
try
{
if (NotifyArray.Count != )
{ //验签以及验证合作伙伴ID
bool flag = _alipayService.RSACheckV1(NotifyArray);
if (await Config.VerifyNotifyAsync(notifyId) == "true" && flag)
{
//交易状态
if (NotifyArray["trade_status"] == "TRADE_FINISHED" ||
NotifyArray["trade_status"] == "TRADE_SUCCESS")
{
if (NotifyArray["app_id"] == Config.AppId) { // 修改支付信息以及状态 //return await UpdateAliPayAsyn(NotifyArray);
}
} await Response.WriteAsync("success");
}
else
{
await Response.WriteAsync("fail");
}
}
}
catch (Exception e)
{
_logger.LogError("Alipay notify fail, {0}", e);
}
return View();
//string msg = null;
//return new ContentResult
//{
// Content = msg ?? "fail"
//};
}
/// <summary>
/// 更新支付宝支付结果信息
/// 判断该笔订单是否已经做过处理
///如果没有做过处理,根据订单号(out_trade_no)在商户的订单系统中查到该笔订单的详细,并执行商户的业务程序
///请务必判断请求时的total_amount与通知时获取的total_fee为一致的
///如果有做过处理,不执行商户的业务程序
/// </summary>
/// <param name="dict"></param>
/// <returns></returns>
//private async Task<ContentResult> UpdateAliPayAsyn(Dictionary<string, string> dict)
//{
// //获取支付的订单号
// string msg = null;
// var orderNO = await accountsOrder.GetOrderAsync(dict["out_trade_no"]);
// if (orderNO == null || !accountsOrder.ReadyOrderStatus(orderNO))
// {
// _logger.LogInformation("充值订单号不存在");
// // return new ContentResult
// {
// Content = msg ?? "fail"
// }; // }
// //if (!EqualAmountAliPay(order.PayPrice, dict["total_amount"]))
// //{
// // return AliPay.ResponseFail("订单金额不匹配");
// //}
// ////更新订单支付通知结果
// //if (await accountsOrder.UpdateOrderAsync(order))
// //{
// // await accountsOrder.SaveAliPayNotifyDataAsync(dict);
// // _logger.LogInformation("[支付宝]支付成功,系统于 " + dtStartTime.ToString() + " 接收到请求,于 " + dict["notify_time"] + " 完成处理,交易流水号:" + dict["trade_no"] + ",交易单号:" + dict["out_trade_no"], "支付宝日志");
// // return AliPay.ResponseSuccess(); // //} // //else
// //{
// // _logger.LogInformation("[支付宝]订单号:" + dict["out_trade_no"] + "状态:" + dict["trade_status"], "支付宝日志"); // // if (dict["trade_status"] == "TRADE_CLOSED")
// // {
// // return AliPay.ResponseSuccess();
// // }
// // else
// // { //成功
// // if (order.PayStatus == 1)
// // {
// // _logger.LogInformation("[支付宝]已支付过:" + order.RechargeOrderNO, "支付宝日志");
// // return AliPay.ResponseSuccess();
// // }
// // else
// // //等待支付
// // {
// // _logger.LogInformation("[支付宝]未支付:" + order.RechargeOrderNO, "支付宝日志");
// // return AliPay.ResponseFail("等待支付");
// // } // // } // return new ContentResult
// {
// Content = msg ?? "fail"
// };
// } #endregion
同步回调 同步回调即支付成功跳转回商户网站
#region 支付同步回调 /// <summary>
/// 支付同步回调 同步回调即支付成功跳转回商户网站
/// </summary>
[HttpGet]
public IActionResult Callback()
{
/* 实际验证过程建议商户添加以下校验。
1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
4、验证app_id是否为该商户本身。
*/
Dictionary<string, string> sArray = GetRequestGet();
if (sArray.Count != )
{
bool flag = _alipayService.RSACheckV1(sArray);
if (flag)
{
Console.WriteLine($"同步验证通过,订单号:{sArray["out_trade_no"]}");
ViewData["PayResult"] = "同步验证通过";
Response.Redirect("http://190.120.120.01:110/");
}
else
{
Console.WriteLine($"同步验证失败,订单号:{sArray["out_trade_no"]}");
ViewData["PayResult"] = "同步验证失败";
}
}
return View();
} #endregion #region 解析请求参数 private Dictionary<string, string> GetRequestGet()
{
Dictionary<string, string> sArray = new Dictionary<string, string>(); ICollection<string> requestItem = Request.Query.Keys;
foreach (var item in requestItem)
{
sArray.Add(item, Request.Query[item]); }
return sArray; }
/// <summary>
/// 获取返回的请求结果
/// </summary>
/// <returns></returns>
private Dictionary<string, string> GetRequestPost()
{
Dictionary<string, string> sArray = new Dictionary<string, string>(); ICollection<string> requestItem = Request.Form.Keys;
foreach (var item in requestItem)
{
sArray.Add(item, Request.Form[item]); }
return sArray; } #endregion }
}
}
7.支付订单信息页面
Index.cshtml 支付请求action POST
@{
ViewData["Title"] = "PC网站支付";
}
<h2>PC网站支付</h2>
<div class="row">
<div class="col-sm-12" s>
<form asp-action="PayRequest" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label for="tradeno" class="control-label col-sm-2">商户订单号:</label>
<div class="col-sm-10">
<input type="text" name="tradeno" class="form-control" id="tradeno" value=""/>
</div>
</div> <div class="form-group">
<label for="subject" class="control-label col-sm-2">订单名称:</label>
<div class="col-sm-10">
<input type="text" name="subject" class="form-control" id="subject" value="iPhone X" />
</div>
</div> <div class="form-group">
<label for="totalAmout" class="control-label col-sm-2">付款金额:</label>
<div class="col-sm-10">
<input type="number" min="0.01" name="totalAmout" class="form-control" id="totalAmout" value="99.99" />
</div>
</div> <div class="form-group">
<label for="itemBody" class="control-label col-sm-2">商品描述:</label>
<div class="col-sm-10">
<input type="text" name="itemBody" class="form-control" id="itemBody" value="苹果手机" />
</div>
</div> <div class="form-group">
<div class="col-sm-10 col-sm-offset-2">
<button class="btn btn-success btn-block">付款</button>
<p class="help-block text-center">如果您点击“付款”按钮,即表示您同意该次的执行操作。</p>
</div> </div>
</form>
</div> </div> <script>
function GetDateNow() {
var vNow = new Date();
var sNow = "";
sNow += String(vNow.getFullYear());
sNow += String(vNow.getMonth() + 1);
sNow += String(vNow.getDate());
sNow += String(vNow.getHours());
sNow += String(vNow.getMinutes());
sNow += String(vNow.getSeconds());
sNow += String(vNow.getMilliseconds());
document.getElementById("tradeno").value = sNow;
}
GetDateNow();
</script>
8.配置系统启动项目信息
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
Console.WriteLine(Configuration["Alipay:AlipayPublicKey"]);
services.AddAlipay(options =>
{
options.AlipayPublicKey = Configuration["Alipay:AlipayPublicKey"];
options.AppId = Configuration["Alipay:AppId"];
options.CharSet = Configuration["Alipay:CharSet"];
options.Gatewayurl = Configuration["Alipay:Gatewayurl"];
options.PrivateKey = Configuration["Alipay:PrivateKey"];
options.SignType = Configuration["Alipay:SignType"];
options.Uid = Configuration["Alipay:Uid"];
}).AddAlipayF2F();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{ loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug(); if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
} app.UseStaticFiles(); app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
appsettings.json
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Error"
}
},
"WriteTo": [
"LiterateConsole",
{
"Name": "RollingFile",
"Args": { "pathFormat": "logs\\log-{Date}.txt" }
}
],
"Alipay": {
"AlipayPublicKey": "/fVCQx+B+++++HLB7K9yTNoBWBGsOsNpTiErj2wqdyOp8KVSp/5P1",
"AppId": "2016******03",
"CharSet": "UTF-8",
"Gatewayurl": "https://openapi.alipaydev.com/gateway.do",
"PrivateKey": "/eQ1ykzA5hecyw4K/+/pIFjLm/M/+/vj0gy+eqabgVUjyOLDuEc"\",": null,
"SignType": "RSA2",
"Uid": "208********2"
}
}
9、支付演示
支付请求页面
跳转到支付宝支付网关沙箱地址
拿起手机APP沙箱版的进行扫码支付 或者进行沙箱账号买家账户登录支付
支付成功提示页面
ASP.NET Core2.0 环境下MVC模式的支付宝PC网站支付接口-沙箱环境开发测试的更多相关文章
- .NET Core2.0 环境下MVC模式的支付宝扫码支付接口-沙箱环境开发测试
所有配置以及相关信息均可以从PC支付中获取 使用的生成二维码的组件名为QRCoder,该组件引用了一个第三方实现的System.Drawing类库,和支付宝官网类似 当面付SDK为Alipay.Aop ...
- Asp.Net支付宝手机网站支付接口API之C#版
一.准备工作 1.使用企业支付宝签约手机网站支付 2.下载支付宝官方demo 文档地址:https://doc.open.alipay.com/doc2/detail?treeId=60&ar ...
- ASP.NET Core 2.0 使用支付宝PC网站支付
前言 最近在使用ASP.NET Core来进行开发,刚好有个接入支付宝支付的需求,百度了一下没找到相关的资料,看了官方的SDK以及Demo都还是.NET Framework的,所以就先根据官方SDK的 ...
- ASP.NET Core 2.0 使用支付宝PC网站支付实现代码(转)
最近在使用ASP.NET Core来进行开发,刚好有个接入支付宝支付的需求,百度了一下没找到相关的资料,看了官方的SDK以及Demo都还是.NET Framework的,所以就先根据官方SDK的源码, ...
- MVC支付宝PC网站接口对接
PC网站支付接口,请参考支付宝官方文档:https://b.alipay.com/signing/productSet.htm?navKey=all 1.需要提供签约账号.商户密钥 2.代码实现: 支 ...
- VS2017创建一个 ASP.NET Core2.0 应用,并搭建 MVC 框架
https://testerhome.com/topics/11747 1.使用最新版本的VS2017,并安装.NET Core2.0中相关开发工具 2.打开VS2017,点击文件-新建-项目,选 ...
- Asp.Net Core2.0在linux下发布
一.在linux上新建mvc项目发布 可以参考:https://segmentfault.com/a/1190000012428781 也可以看微软官方文档. 大致步骤如下: 1.在linux下安装. ...
- 通过Mysql连接ASP.Net Core2.0(Code First模式)
ASP.NET Core2.0连接Mysql,首先新建项目 选择Web应用程序 选择需要身份验证: 通过Nuget安装Mysql驱动,这里推荐>Pomelo.EntityFrameworkCor ...
- 一步一步带你做WebApi迁移ASP.NET Core2.0
随着ASP.NET Core 2.0发布之后,原先运行在Windows IIS中的ASP.NET WebApi站点,就可以跨平台运行在Linux中.我们有必要先说一下ASP.NET Core. ASP ...
随机推荐
- weblogic安装错误BEA-090870解决方案
00.问题描述 <Sep 3, 2017 3:29:09 PM CST> <Error> <Security> <BEA-090870> <The ...
- Android API之android.content.BroadcastReceiver
android.content.BroadcastReceiver Base class for code that will receive intents sent by sendBroadcas ...
- 【linux环境】Linux环境 php连接oracle11g数据库(相关插件已备份至U盘)
1.环境:centos6 . LNMP(linux环境都可以,跟服务器没啥大关系) 2.前期准备:弄清楚 项目php的运行目录,php.ini的配置目录,php-config的运行目录 3.安装先知: ...
- 【CAS单点登录视频教程】 第02集 -- 安装CAS
目录 ----------------------------------------- [CAS单点登录视频教程] 第06集[完] -- Cas认证 学习 票据认证FormsAuthenticati ...
- ios中自定义图层的2种方法
1:自定义图层,在图层中画图 #import <QuartzCore/QuartzCore.h> @interface MJLayer : CALayer @end #import &qu ...
- FluentScheduler
The job configuration is handled in a Registry class. A job is either an Action or a class that inhe ...
- CSS中详解height属性
目录结构: contents structure [+] hight属性值类型一览表 height的%的使用 定义 实例 需要注意的 参考文章 hight属性值类型一览表 value describt ...
- Kibana常用命令
一.范围(>500) totalTime: [500 TO *] 二.不等于 NOT monitorName: "XXX" 三.字符匹配 正则表达式: +url:/.* ...
- Haproxy TCP数据转发
在实际项目中需要用到haproxy做TCP转发,下面主要针对haproxy的安装及TCP数据转发配置进行说明 一.安装Haproxy (1)编译安装Haproxy mkdir -p /data01/h ...
- php封装数据库函数
从Thinkphp里面抽离出来的数据库模块,感觉挺好用 common.php <?PHP /** * 通用函数 */ //包含配置文件 if (is_file("config.php& ...