//logger属性本来应该考虑空模式
        //Options和Logger 本身不必要提供的,库的调用方完全可以自己做依赖注入。但是由于中间件中已经拿到这些对象的引用,直接传递过来 比去依赖注入再拿一次 更快吧

        public WeChatPaymentNoticeContext(HttpContext httpContext, WeChatPaymentOptions options, WeChatPaymentNoticeResult paymentNoticeResult, ILogger logger)
        {
            HttpContext         = httpContext;
            Options             = options;
            PaymentNoticeResult = paymentNoticeResult;
            Logger = logger;
        }
        public async Task Invoke(HttpContext context)
        {
            var request  = context.Request;
            var response = context.Response;

            //由于考虑用户代码的某些组件也需要访问此选项对象,因此使用asp.net core选项模型,使用依赖注入的方式
            //而不是使用注册中间件是直接提供Options的方式,这样调用方可以随时依赖注入此选项对象
            var options = context.RequestServices.GetRequiredService <IOptionsMonitor <WeChatPaymentOptions> >().CurrentValue;

            //若当前请求不是支付结果回调请求,则跳过处理,直接执行后续中间件
            if (options.CallbackPath != request.Path)
            {
                await this._next(context);

                return;
            }

            //另外将来可能使用GetServices拿到多个处理器,按顺序遍历,传入WeChatPaymentNoticeContext逐一处理 此情况目前不考虑
            var handler = context.RequestServices.GetService <IWeChatPaymentNoticeHandler>();

            if (handler == null)
            {
                await response.ResponseWeChatSuccessAsync();

                return;
            }

            var factory = context.RequestServices.GetRequiredService <WeChatPaymentNoticeResult.WeChatPaymentNoticeResultFactory>();
            var logger  = context.RequestServices.GetService <ILogger>();

            //拿到微信传来的数据
            WeChatPaymentNoticeResult wpnr = await factory.LoadAsync(request.Body, context.RequestAborted);

            //无论微信通知我们支付成功还是失败都应该交给调用方去做业务处理

            var paymentNoticeContext = new WeChatPaymentNoticeContext(context, options, wpnr, logger);

            try
            {
                //中间件无法参与业务处理,因此业务处理需要考虑并发情况
                await handler.PaymentNoticeAsync(paymentNoticeContext);

                await response.ResponseWeChatSuccessAsync();
            }
            //catch (UserFriendlyException ex) {
            //  可以定义一个类似UserFriendlyException,让调用方的Handler返回业务异常是使用这个类。
            //  这里直接捕获,将ex.Message响应给微信,其它异常属于系统级别异常 就不要返回ex.Message给微信了
            //  await response.ResponseWeChatFailAsync(ex.Message);
            //}
            catch (Exception ex)
            {
                //这里可以做其它处理
                logger.LogError(ex, $"支付结果通知处理失败!微信支付订单号:{wpnr.transaction_id}");
                await response.ResponseWeChatFailAsync("业务处理失败!");
            }
        }
            /// <summary>
            /// 微信小程序支付结果通知提交过来的Stream 可以通过此方法解析
            /// </summary>
            /// <param name="stream"></param>
            /// <param name="cancellation"></param>
            /// <returns></returns>
            public async Task <WeChatPaymentNoticeResult> LoadAsync(Stream stream, CancellationToken cancellation = default)
            {
                var xd = await XDocument.LoadAsync(stream, LoadOptions.None, cancellation);

                var c = xd.Root;

                var p = new WeChatPaymentNoticeResult();

                p.return_code = Enum.Parse <return_code>((string)c.Element("return_code"));
                p.return_msg  = (string)c.Element("return_msg");
                if (p.return_code != return_code.SUCCESS)
                {
                    return(p);
                }

                p.appid       = (string)c.Element("appid");
                p.mch_id      = (string)c.Element("mch_id");
                p.device_info = (string)c.Element("device_info");
                p.nonce_str   = (string)c.Element("nonce_str");
                p.sign        = (string)c.Element("sign");

                var sign_type = (string)c.Element("sign_type");

                if (!string.IsNullOrWhiteSpace(sign_type))
                {
                    p.sign_type = Enum.Parse <sign_type>(sign_type);
                }

                p.result_code  = Enum.Parse <result_code>((string)c.Element("result_code"));
                p.err_code     = (string)c.Element("err_code");
                p.err_code_des = (string)c.Element("err_code_des");
                if (p.result_code != result_code.SUCCESS)
                {
                    return(p);
                }

                p.openid       = (string)c.Element("openid");
                p.is_subscribe = (bool)c.Element("is_subscribe");
                p.trade_type   = Enum.Parse <trade_type>((string)c.Element("trade_type"));
                p.bank_type    = (string)c.Element("bank_type");
                p.total_fee    = (int)c.Element("total_fee") / 100m;
                var settlement_total_fee = (string)c.Element("settlement_total_fee");

                if (!string.IsNullOrWhiteSpace(settlement_total_fee))
                {
                    p.settlement_total_fee = Convert.ToDecimal(settlement_total_fee) / 100;
                }
                var fee_type = (string)c.Element("fee_type");

                if (!string.IsNullOrWhiteSpace(fee_type))
                {
                    p.fee_type = Enum.Parse <fee_type>((string)c.Element("fee_type"));
                }

                #region 现金
                var cash_fee = (string)c.Element("cash_fee");
                if (!string.IsNullOrWhiteSpace(cash_fee))
                {
                    p.cash_fee = Convert.ToDecimal(cash_fee) / 100;
                }

                var cash_fee_type = (string)c.Element("cash_fee_type");
                if (!string.IsNullOrWhiteSpace(cash_fee_type))
                {
                    p.cash_fee_type = Enum.Parse <fee_type>((string)c.Element("cash_fee_type"));
                }
                #endregion

                #region 代金券

                var coupon_fee = (string)c.Element("coupon_fee");
                if (!string.IsNullOrWhiteSpace(coupon_fee))
                {
                    p.coupon_fee = Convert.ToDecimal(coupon_fee) / 100;
                }


                var coupon_count = (string)c.Element("coupon_count");
                if (!string.IsNullOrWhiteSpace(coupon_count))
                {
                    p.coupon_count = Convert.ToInt32(coupon_count);
                }

                var coupon_type_0 = (string)c.Element("coupon_type_0");
                if (!string.IsNullOrWhiteSpace(coupon_type_0))
                {
                    p.coupon_type_0 = Enum.Parse <coupon_type>((string)c.Element("coupon_type_0"));
                    p.coupon_fee_0  = Convert.ToDecimal(c.Element("coupon_fee_0")) / 100;
                }
                var coupon_type_1 = (string)c.Element("coupon_type_1");
                if (!string.IsNullOrWhiteSpace(coupon_type_1))
                {
                    p.coupon_type_1 = Enum.Parse <coupon_type>((string)c.Element("coupon_type_1"));
                    p.coupon_fee_1  = Convert.ToDecimal(c.Element("coupon_fee_1")) / 100;
                }
                var coupon_type_2 = (string)c.Element("coupon_type_2");
                if (!string.IsNullOrWhiteSpace(coupon_type_2))
                {
                    p.coupon_type_2 = Enum.Parse <coupon_type>((string)c.Element("coupon_type_2"));
                    p.coupon_fee_2  = Convert.ToDecimal(c.Element("coupon_fee_2")) / 100;
                }
                var coupon_type_3 = (string)c.Element("coupon_type_3");
                if (!string.IsNullOrWhiteSpace(coupon_type_3))
                {
                    p.coupon_type_3 = Enum.Parse <coupon_type>((string)c.Element("coupon_type_3"));
                    p.coupon_fee_3  = Convert.ToDecimal(c.Element("coupon_fee_3")) / 100;
                }
                var coupon_type_4 = (string)c.Element("coupon_type_4");
                if (!string.IsNullOrWhiteSpace(coupon_type_4))
                {
                    p.coupon_type_4 = Enum.Parse <coupon_type>((string)c.Element("coupon_type_4"));
                    p.coupon_fee_4  = Convert.ToDecimal(c.Element("coupon_fee_4")) / 100;
                }
                p.coupon_id_0 = (string)c.Element("coupon_id_0");
                p.coupon_id_1 = (string)c.Element("coupon_id_1");
                p.coupon_id_2 = (string)c.Element("coupon_id_2");
                p.coupon_id_3 = (string)c.Element("coupon_id_3");
                p.coupon_id_4 = (string)c.Element("coupon_id_4");
                #endregion

                p.transaction_id = (string)c.Element("transaction_id");
                p.out_trade_no   = (string)c.Element("out_trade_no");
                p.attach         = (string)c.Element("attach");
                p.time_end       = DateTimeOffset.Parse((string)c.Element("time_end"));

                if (!securet.CheckSign(p))
                {
                    throw new InvalidCastException("微信小程序支付 > 支付结果通知 > 微信提交过来的数据 > sign校验失败!");
                }

                return(p);
            }
Exemple #4
0
 public WeChatPaymentNoticeContext(HttpContext httpContext, WeChatPaymentNoticeOptions options, WeChatPaymentNoticeResult paymentNoticeResult)
 {
     HttpContext         = httpContext;
     Options             = options;
     PaymentNoticeResult = paymentNoticeResult;
 }