• 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 + "&notify_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 != 0) { //验签以及验证合作伙伴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 != 0)
                {
                    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沙箱版的进行扫码支付 或者进行沙箱账号买家账户登录支付

    支付成功提示页面

  • 相关阅读:
    memset 还可以这样用
    搜索(DFS)
    搜索(BFS)
    最大流之sap算法
    最大流之sap算法
    String VS Cstring(字符串)
    String VS Cstring(字符串)
    Set 与 Multiset
    deque(双端队列)
    枚举 TODO
  • 原文地址:https://www.cnblogs.com/Warmsunshine/p/7904609.html
Copyright © 2020-2023  润新知