asp.net core 3.1开发交通银行支付接口笔记三退款、查询和收尾

 

asp.net core 3.1开发交通银行支付接口笔记一底层代码

asp.net core 3.1开发交通银行支付接口笔记二支付

退款

由于业务需要。这里要做退款功能。也好。以前我做的接口都不做退款功能。所以,我都是用自己的钱包测试的。当然。我也会找客户的帐号用,让客户左手转右手。虽然不多。但也是钱是不?这次有退款功能,而且用的是微信,绑定太多,所以就没法用客户帐号了。

开始

发送请求

按照文档的要求在第一章的基础类里面拼接XML然后用第一章的服务器soket类POST发送到文档说的指定接口(不是页面接口是接口这个注意

响应

这是同步响应,阻塞的,最好在页面点击退款有个读条遮罩防止二次退款,得到响应用第一章的代码解签后本地业务处理结果即可。

 

查询

按照文档的要求在第一章的基础类里面拼接XML然后用第一章的服务器soket类POST发送到文档说的指定接口(不是页面接口是接口这个注意

 

响应

这个也是同步的。即时结果,同样也是用第一章的解签出来后自己本地处理逻辑

 

收尾

这里交行技术人员对接有个要求,支付必须扣款成功,有退款必须到账。在没收到回调需要轮询。要求是:原则上,查询不能太频繁,如查询间隔不能低于10s。无效查询不能太多,如下单五分钟后仍未终态(success 或 failure )也停止查询。

如果没有达到要求拒绝上线的。

退款和查询很简单上面一笔带过。下面说轮询。轮询我用后台任务+redis队列做的

redis

WINDOWS64下载:https://pan.baidu.com/s/1fslLAYpWX8kE2-RWon2Ebw 提取码:3z9q

安装


配置,我这里由于有软件洁癖(其实是怕装太多拖慢我的宝贝I7新机)。

私人开发的数据库和其它辅助都是装自己的服务器上的,自己的机子只装开发工具和游戏。所以用远程部署。

设置远程访问地址。在(redis.windows-service.conf)

################################ GENERAL  #####################################

下的

# bind 127.0.0.1下面加一句

bind 0.0.0.0

设置密码。这个网上资料说(redis.windows-service.conf里面设置是错误的。没效果。只有在redis.windows.conf设置才有用)

在################################## SECURITY ###################################下面的

# requirepass foobared的下面加一句

requirepass 你的密码

安装命令:redis-server.exe --service-install redis.windows.conf --loglevel verbose

启动服务命令:redis-server.exe  --service-start

关闭服务命令:redis-server.exe  --service-stop

使用:我把订单ID加入队列,我用的是左进右出

        private readonly IDatabase _redis;
        public CourseMajorBLL(WXOfficeContext _db, ILogProvider _log, IServiceScopeFactory serviceScopeFactory, RedisHelper client)
        {
            db = _db;
            log = _log;
            _redis = client.GetDatabase();
            _serviceScopeFactory = serviceScopeFactory;
        }

        /// <summary>
        /// 加入队列
        /// </summary>
        /// <param name="id"></param>
        private void pushRedis(string id)
        {
            using (var context = (WXOfficeContext)_serviceScopeFactory.CreateScope().ServiceProvider.CreateScope().ServiceProvider.GetService(typeof(WXOfficeContext)))
            {
                log.WriteOperateLog(context, "自动加入队列", id, new UsersInfoModel() { NickName = "系统", UserName = "交行报文", IP = "" });
                context.SaveChanges();
            }
            _redis.ListLeftPush("lnr", id);
          
        }

小技巧:由于在线程里面用dbcontext而一个线程只允许用一个dbcontext所以解决方案是即时生成使用即时销毁。所以上面的日志我用了using


订单ID取出队列

_redis.ListRightPop("lnr", 0);

后台定时任务

 public class QueryBackgroundService : BackgroundService
    {
        private IBCMHandleLogic _iBCMHandleLogic;
        public QueryBackgroundService(IBCMHandleLogic iBCMHandleLogic)
        {
            _iBCMHandleLogic = iBCMHandleLogic;
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Console.WriteLine("查询服务开启");
            Console.WriteLine("MyServiceA 开始执行");
            while (!stoppingToken.IsCancellationRequested)
            {
                await _iBCMHandleLogic.StartQueryOrderTask();
                await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken);
            }
            Console.WriteLine("查询服务停止");
        }

        public override void Dispose()
        {
            base.Dispose();
        }
    }

配置

public void ConfigureServices(IServiceCollection services)
{
    //..其它配置
    services.AddHostedService<QueryBackgroundService>();
}
 public async Task StartQueryOrderTask()
        {
            if (ThreadPool.ThreadCount < 20)
            {
                //Thread.Sleep(3000);
                string orderNo = _redis.ListRightPop("lnr", 0);
                
                if (!string.IsNullOrWhiteSpace(orderNo))
                {
                    WriteOperateLog("出队列", orderNo, new UsersInfoModel() { NickName = "系统", UserName = "交行报文", IP = "" });
                    await Task.Run(async () =>
                    {
                        for (int i = 0; i < 20; i++)
                        {
                            using (var db = (WXOfficeContext)_serviceScopeFactory.CreateScope().ServiceProvider.CreateScope().ServiceProvider.GetService(typeof(WXOfficeContext)))
                            {

                                TotalOrder order = null;
                                for (int j = 0; j < 4; j++)
                                {
                                    order = db.TotalOrder.Where(r => r.OrderNo == orderNo).FirstOrDefault();
                                    if (j == 3 && order == null)
                                    {
                                        WriteOperateLog(orderNo, "订单还没保存到数据库", new UsersInfoModel() { NickName = "系统", UserName = "交行报文", IP = "" });
                                        break;
                                    }
                                    if (order == null)
                                    {
                                        Thread.Sleep(10000);
                                    }
                                    else
                                    {
                                        break;
                                    }

                                }
                                if (order == null||!(order.Status==(int)PayStateEnum.Payments||order.Status==(int)PayStateEnum.Refunding))
                                {
                                    break;
                                }
                                if (order.Status == (int)PayStateEnum.Payments)//支付
                                {
                                    TimeSpan ts = DateTime.Now - order.AddTime;
                                    if (ts.Seconds < 15)
                                    {
                                        Thread.Sleep((15 - ts.Seconds) * 1000);
                                    }
                                }
                                else if (order.Status == (int)PayStateEnum.Refunding)//退款
                                {
                                    Thread.Sleep(15000);
                                }


                            }
                            WriteOperateLog(orderNo, "开始查询", new UsersInfoModel() { NickName = "系统", UserName = "交行报文", IP = "" });
                            string rs = await runQuery(orderNo);//本地自己的业务逻辑
                            WriteOperateLog(orderNo, "开始查询"+i+"次,结果:"+rs, new UsersInfoModel() { NickName = "系统", UserName = "交行报文", IP = "" });
                            if (!string.IsNullOrWhiteSpace(rs))
                            {
                                Thread.Sleep(15000);
                            }
                            else
                            {
                                break;
                            }
                        }
                    });
                }
            }

        }

 

上面是具体逻辑。这里有个问题。会阻塞订单。也就是说,如果有2个订单A、B进入队列B会在A完成后才会执行取出B,原因我怀疑在那个线程休眠,但是时间紧还没头绪处理。

至此。整个接口的笔记完成。撒花

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值