Skip to content

Implement a new gateway

hiihellox10 edited this page Oct 25, 2017 · 8 revisions

实现基类支持更多支付网关


主要基类、接口介绍

GatewayBase
所有的支付网关的基类,新增加支持的支付网关必须继承自GatewayBase

IPaymentForm
当支付网关是通过创建一个包含订单数据的form表单来提交订单时通过实现IPaymentForm接口来创建支付订单的html页面代码。

IPaymentUrl
当支付网关是通过创建一个包含订单数据的url来提交订单时通过实现IPaymentUrl接口来创建订单的url。

IPaymentQRCode
当支付网关是使用二维码支付时通过实现IPaymentQRCode接口来创建订单并获得支付二维码。

IQueryNow
通过向支付网关查询url发送需要查询的订单数据,支付网关在查询url页面输出查询结果时实现此接口。

IQueryForm
当支付网关是通过创建一个包含订单数据的form表单来查询订单时通过实现IQueryForm接口来创建查询订单的html页面代码。查询结果跟订单支付成功时的通知返回方式一致。

IQueryUrl
当支付网关是通过创建一个包含订单数据的url来查询订单时通过实现IPaymentUrl接口来创建订单的url。查询结果跟订单支付成功时的通知返回方式一致。


让ICanPay支持新的支付网关

下面演示如何增加新的支付网关,我们新建一个名为DemoGateway的新支付网关它继承自GatewayBase基类。

public sealed class DemoGateway : GatewayBase
{
}

接着我们需要修改ICanPay.GatewayType枚举,在ICanPay.GatewayType枚举中增加Demo值来表示当前网关为DemoGateway

public enum GatewayType
{
    // 省略已存在枚举值
    Demo
}

再修改DemoGateway.GatewayType属性,让它返回新增的GatewayType.Demo值。

public sealed class DemoGateway : GatewayBase
{
    public override GatewayType GatewayType
    {
        get { return GatewayType.Demo }
    }
}

我们还需要实现PaymentNotifyMethod属性。订单的支付结果目前会通过2种形式返回,1 、支付网关服务器发送支付结果通知到指定url,2、将用户跳转到设置的通知url,并在查询字符串里包含支付结果。

有的支付网关可能通过服务器发送支付结果通知给你时会要求你输出一个特定的字符串用户表示已接收到支付通知,而将用户跳转到通知url时则不需要。如果没有对这2种方式做判断,在用户跳转到通知url时输出表示接收到支付网站通知的字符串时会让用户觉得很奇怪,这时应该给用户一个支付成功的提示页面,而不是奇怪的字符串。

支付通知是否由网关服务器发送,我们可以通过HttpContext.Current.RequestRequestTypeUserAgent2个属性来判断,因为支付网关的服务器通知的这2个属性都是固定值,而用户通过浏览器返回支付通知页面时的这2个属性会明显不同。这2个属性你可以先运行几次你需要新增的支付网关提供的Demo,完成支付并获得相关值。

public sealed class DemoGateway : GatewayBase
{
    public override PaymentNotifyMethod PaymentNotifyMethod
    {
        get
        {
            if (string.Compare(HttpContext.Current.Request.RequestType, "POST") == 0 &&
                string.Compare(HttpContext.Current.Request.UserAgent, "Mozilla/4.0") == 0)
            {
                return PaymentNotifyMethod.ServerNotify;
            }

            return PaymentNotifyMethod.AutoReturn;
        }
    }
}

WriteSucceedFlag方法在收到支付网关通知并验证无误时输出表示接收到支付通知的字符串,请参考相关支付网关的文档,如果支付网关没有要求则保持方法为空即可。

public sealed class DemoGateway : GatewayBase
{
    public override void WriteSucceedFlag()
    {
    }
}

ValidateNotify方法用于验证当前支付网关返回的支付结果。支付网关返回的支付通知数据(查询字符串、from表单)都保存在GatewayParameterData属性中,你可以使用GetGatewayParameterValue帮助方法来获得相应参数的值。支付结果的验证请参考相关支付网关的文档。


让新的支付网关能被识别

DemoGateway同时需要如下2个公共的构造函数,它们将用于创建生成支付订单与处理网关的支付通知。

public DemoGateway()
{
}

public DemoGateway(List<GatewayParameter> gatewayParameterData)
    : base(gatewayParameterData)
{
}

为了能让新增加的DemoGateway支付网关可以创建订单需要修改PaymentSetting类的CreateGateway方法,当需要创建的支付网关为Demo时返回DemoGateway类的实例。

public class PaymentSetting
{
    private GatewayBase CreateGateway(GatewayType gatewayType)
    {
        switch (gatewayType)
        {
            // 省略已存在代码
            case GatewayType.Demo:
            {
                return new DemoGateway();
            }

            default:
            {
                return new NullGateway();
            }
        }
    }
}

这样就能正确返回Demo支付网关的创建订单的实现了。

我们还需要让ICanPay能够识别支付通知是否是DemoGateway发送的。先在NotifyProcess类中增加IsDemoGateway方法,在IsDemoGateway方法中我们通过判断当前支付通知中是否存在DemoGateway的支付通知中必须包含的参数来判断当前支付通知是否是DemoGateway支付网关发送的,相关参数请阅读相关支付网关的文档。

internal static class NotifyProcess
{
    static string[] demoGatewayVerifyParmaNames= { "c_mid", "c_order", "c_orderamount", "c_ymd", "c_succmark" };

    private static bool IsDemoGateway(List<GatewayParameter> gatewayParameterData)
    {
        return ExistParameter(demoGatewayVerifyParmaNames, gatewayParameterData);
    }
}

接着修改NotifyProcess类的GetGateway方法,让它在当前支付通知是由DemoGateway发送时返回DemoGateway的实例。

internal static class NotifyProcess
{
    public static GatewayBase GetGateway()
    {
        // 省略已存在代码
        if (IsDemoGateway(gatewayParameterData))
        {
            return new DemoGateway(gatewayParameterData);
        }

        return new NullGateway(gatewayParameterData);
    }
}

完成上面的这些步骤之后我们的DemoGateway已经可以处理支付网关的支付通知了。


实现创建订单接口

阅读你需要支持的支付网关的文档,当它们是通过from表单提交订单时你需要继承IPaymentForm接口,当它们是通过url表单提交订单时你需要继承IPaymentUrl接口。

GatewayBase基类中提供了一些帮助方法可以让你更方便的创建支付订单,详情请阅读已实现的支付网关的代码。


实现创建查询接口

阅读你需要支持的支付网关的文档,它们是否提供查询接口。如果是需要向支付网关查询url发送需要查询的订单数据,支付网关在查询url页面输出查询结果时你需要继承IQueryNow接口。

当它们是通过from表单提交订单并且是通过与支付通知结果一样的方法返回查询时你需要继承IQueryForm接口,当它们是通过url表单提交订单并且是通过与支付通知结果一样的方法返回查询时你需要继承IQueryUrl接口。目前没有实现支持IQueryForm接口跟IQueryUrl接口这种查询方式的支付网关,之前使用这种查询方式的网银在线已经删除掉了。

Clone this wiki locally