Skip to content
hiihellox10 edited this page Nov 17, 2019 · 15 revisions

如何使用


第一步页面的编码配置

因为部分支付平台的编码仅支持GB2312,为了能够支持多个支付平台所以所有支付平台统一使用GB2312编码。创建支付平台订单的页面跟接收支付平台支付通知的页面均需要使用GB2312编码。如果使用其他编码可能会因为乱码而造成无法正常创建支付订单和识别支付平台的支付通知。

如果你的程序需要使用其它编码而不能使用GB2312编码,你可以将创建支付订单跟接受支付平台通知页面放在独立Views的路径中,并通过在Web.config文件中配置此路径使用GB2312编码,而其他页面将不会受到影响。以下配置将的Views的Payment路径设置为GB2312编码。

<configuration>
  <location path="Payment">
    <system.web>
      <globalization requestEncoding="gb2312" responseEncoding="gb2312"/>
    </system.web>
  </location>
</configuration>

创建订单

创建订单时有2种方式,一种是传统的创建订单的Form表单或者Url,另一种是创建订单的支付二维码。

1、传统的创建订单的Form表单或者Url 下面先演示如何使用创建传统的Form表单或者Url支付订单。首先你需要在Views中新建一个名为Payment的文件夹,然后在Payment文件夹中创建Index.cshtml视图,Index.cshtml视图仅保留如下代码:

@{
    Layout = null;
}

这样的目的是因为实现了IPaymentForm接口的支付网关在创建订单时会生成并输出完整的Form表单,如果当前页面包含其他内容可能会造成无法提交订单,所以需要保持空白页面。

下面的代码将演示如何使用支付宝、易宝来创建订单。

/// <summary>
/// 创建支付宝的支付订单
/// </summary>
private void CreateAlipayOrder()
{
    PaymentSetting paymentSetting = new PaymentSetting(GatewayType.Alipay);
    paymentSetting.Merchant = new AlipayMerchant                    // 支付宝需要额外的 SellerEmail 参数,这里需要使用继承自 Merchant 的 AlipayMerchant。
    {
        SellerEmail = "[email protected]",                       // 支付宝的注册邮箱
        UserName = "000000000000000",                               // 合作伙伴身份(PID)
        Key = "000000000000000000000000000000000000000000",         // MD5密钥
        NotifyUrl = new Uri("http://yourwebsite.com/Notify")
    };

    paymentSetting.Order = new Order
    {
        Amount = 0.01,
        Id = "35",
        Subject = "测试支付宝"
    };

    paymentSetting.Payment();
}


/// <summary>
/// 创建易宝的支付订单
/// </summary>
private void CreateYeepayOrder()
{
    PaymentSetting paymentSetting = new PaymentSetting(GatewayType.Yeepay);
    paymentSetting.Merchant = new Merchant
    {
        UserName = "000000000000000",                               // 商户编号
        Key = "000000000000000000000000000000000000000000",         // 商户密钥
        NotifyUrl = new Uri("http://yourwebsite.com/Notify")
    };

    paymentSetting.Order = new Order
    {
        Amount = 0.01,
        Id = "24",
        Subject = "测试易宝"
    };

    paymentSetting.Payment();
}

在上面的代码我们使用了支付宝、易宝的支付平台来创建订单,在创建订单时需要设置商户、订单、接收网关平台通知的Url这些必填的数据。在使用支付宝时,需要注意因为支付宝需要额外的卖家支付宝账号邮箱参数,这时设置Merchant属性需要使用AlipayMerchant。

在完成必须的设置后,使用Payment方法将会在当前页面输出提交订单的Form或者Url,然后会将用户定向到相应的支付网站。

2、支付二维码

接下来是创建支付二维码,下面的代码是创建微信支付的支付二维码。代码跟创建传统的生成Form表单或者Url订单的代码一致,唯一的区别是Payment方法会在当前页面输出支付二维码的图片,而不再是Form表单或者Url。

/// <summary>
/// 创建微信的支付订单
/// </summary>
private void CreateWeChatPayOrder()
{
    PaymentSetting paymentSetting = new PaymentSetting(GatewayType.WeChatPay);
    paymentSetting.Merchant = new WeChatPayMerchant                   // 微信支付需要额外的 AppId 参数,这里需要使用继承自 Merchant 的 WeChatPayMerchant。
    {
        AppId = "wx000000000000000",                                  // 公众号APPID
        UserName = "000000000000000",                                 // 微信支付商户号
        Key = "000000000000000000000000000000000000000000",           // API密钥
        NotifyUrl = new Uri("http://yourwebsite.com/Notify")
    };

    paymentSetting.Order = new Order
    {
        Amount = 0.01,
        Id = "31",
        Subject = "测试微信"
    };

    paymentSetting.Payment();
}

在使用微信支付时,需要注意因为微信支付需要额外的AppId参数,在设置Merchant属性需要使用WeChatPayMerchant。


接收支付平台的支付通知

首先在Views中新建名为Notify的文件夹,然后在Notify文件夹中创建Index.cshtml视图,Index.cshtml视图仅保留如下代码:

@{
    Layout = null;
}

这样做的原因是因为接收支付网关通知的页面可能需要输出一些字符表示已接收到支付网关的通知,如果有其他页面内容会造成干扰。

在这个页面将接收并处理多个不同的网关返回的支付通知,相应的NotifyController控制器的代码如下:

public class NotifyController : Controller
{

    private static List<Merchant> _merchantList;

    static NotifyController()
    {
        InitMerchantList();
    }

    private static void InitMerchantList()
    {
        Merchant alipayMerchant = new Merchant
        {
            GatewayType = GatewayType.Alipay,
            UserName = "000000000000000",                       // 合作伙伴身份(PID)
            Key = "000000000000000000000000000000000000000000"  // MD5密钥
        };

        Merchant weChatPaymentMerchant = new Merchant
        {
            GatewayType = GatewayType.WeChatPay,
            UserName = "000000000000000",                        // 微信支付商户号
            Key = "000000000000000000000000000000000000000000"   // API密钥
        };

        Merchant tenpayMerchant = new Merchant
        {
            GatewayType = GatewayType.Tenpay,
            UserName = "000000000000000",                       // 商户号
            Key = "000000000000000000000000000000000000000000"  // 密钥
        };

        Merchant yeepayMerchant = new Merchant
        {
            GatewayType = GatewayType.Yeepay,
            UserName = "000000000000000",                       // 商户编号
            Key = "000000000000000000000000000000000000000000"  // 商户密钥
        };

        _merchantList = new List<Merchant>
        {
            alipayMerchant,
            weChatPaymentMerchant,
            tenpayMerchant,
            yeepayMerchant
        };
    }


    public ActionResult Index()
    {
        // 订阅支付通知事件
        PaymentNotify notify = new PaymentNotify(_merchantList);
        notify.PaymentSucceed += notify_PaymentSucceed;
        notify.PaymentFailed += notify_PaymentFailed;
        notify.UnknownGateway += notify_UnknownGateway;

        // 接收并处理支付通知
        notify.Received();

        return View();
    }

    private void notify_PaymentSucceed(object sender, PaymentSucceedEventArgs e)
    {
        // 支付成功时的处理代码
        if (e.PaymentNotifyMethod == PaymentNotifyMethod.AutoReturn)
        {
            // 当前是用户的浏览器自动返回时显示支付成功页面
        }
    }

    private void notify_PaymentFailed(object sender, PaymentFailedEventArgs e)
    {
        // 支付失败时的处理代码
    }

    private void notify_UnknownGateway(object sender, UnknownGatewayEventArgs e)
    {
        // 无法识别支付网关时的处理代码
    }
}

首先创建支付网关的商户数据,然后将他们添加到集合。在创建PaymentNotify对象时将商户数据的集合传入构造函数中。接着PaymentNotify在支付成功、失败、无法识别支付网关的事件上注册回调方法,最后使用Received方法来接收支付网关返回的支付通知,它将完成支付通知的处理并引发相应的事件。

在事件的回调方法中你可以通过e.PaymentNotifyMethod属性来获得支付通知是用户通过浏览器自动返回还是由网关服务器发送。如果是用户通过浏览器自动返回这时你可以在页面提示充值以便让用户获得更好的体验。

访问支付通知的原始数据

当你希望访问支付成功、失败、无法识别支付网关的事件数据中未提供的其他支付通知数据时,你可以通过e.GatewayParameterData属性来获得,e.GatewayParameterData属性保存了支付网关返回的所有数据。使用e.GetGatewayParameterValue帮助方法可以更方便的访问支付网关返回的数据,例如在支付宝的支付通知中使用e.GetGatewayParameterValue("buyer_email")方法可以获得买家的支付宝帐号,在微信的支付通知中使用 e.GetGatewayParameterValue("is_subscribe")方法可以知道用户是否关注公众账号。


查询订单

查询订单有2种不同的方式

1、 有的支付网关是立即获得订单的查询结果

通过向支付网关查询页面发送需要查询的订单数据后,查询页面将输出查询结果。使用这种查询方式的支付网关都实现了IQueryNow接口。

实现了IQueryNow接口的网关,将使用如下方式查询订单的状态

/// <summary>
/// 查询微信的订单支付状态
/// </summary>
private void QueryWeChatPayOrder()
{
    PaymentSetting querySetting = new PaymentSetting(GatewayType.WeChatPay);
    querySetting.Merchant = new WeChatPayMerchant()         // 微信支付需要额外的 AppId 参数,这里使用继承自 Merchant 的 WeChatPayMerchant。
    {
        AppId = "wx000000000000000",                        // 公众号APPID
        UserName = "000000000000000",                       // 微信支付商户号
        Key = "0000000000000000000000000000000000000000"    // API密钥
    };
            
    // 查询时需要设置订单的Id与金额,在查询结果中将会核对订单的Id与金额,如果不相符会返回查询失败。
    querySetting.Order = new Order
    {
        Id = "20",
        Amount = 0.01
    };

    if (querySetting.CanQueryNow && querySetting.QueryNow())
    {
        // 订单已支付
    }
}

/// <summary>
/// 查询易宝的订单支付状态
/// </summary>
private void QueryYeepayOrder()
{
    PaymentSetting querySetting = new PaymentSetting(GatewayType.Yeepay);
    querySetting.Merchant = new Merchant
    {
        UserName = "000000000000000",                         // 商户编号
        Key = "0000000000000000000000000000000000000000"      // 商户密钥
    };

    // 查询时需要设置订单的Id与金额,在查询结果中将会核对订单的Id与金额,如果不相符会返回查询失败。
    querySetting.Order = new Order
    {
        Id = "15",
        Amount = 0.01
    };

    if (querySetting.CanQueryNow && querySetting.QueryNow())
    {
        // 订单已支付
    }
}

使用CanQueryNow属性可以查询到当前的支付网关是否实现了IQueryNow接口,是否可以立即获得查询订单结果,如果可以再使用QueryNow方法来获得查询结果,因为并不是所有支付网关都实现了查询功能或者这种查询方式。这里需要注意查询时需要设置订单的Id与金额,在查询结果中将会核对订单的Id与金额,如果不相符会返回查询失败。在使用微信支付时,需要注意这里需要额外的AppId参数,在设置Merchant时需要使用WeChatPayMerchant。

2、 查询订单跟提交订单后接收处理支付网关付款通知的方式一样

提交查询以后,网关服务器给指定页面发送支付通知,然后你使用处理网关服务器返回付款通知一样的方法来处理订单的查询。

下面的代码演示了提交一个查询

private void QueryNotifyOrder()
{
    PaymentSetting querySetting= new PaymentSetting(GatewayType.None);
    querySetting.Merchant.UserName = "10000000000";
    querySetting.Merchant.Key = "0000000000000000000000000000000000000000";
    querySetting.Merchant.NotifyUrl = new Uri("http://yourwebsite.com/Notify");
    querySetting.Order.OrderId = "1564515";

    if (paymentSetting.CanQueryNotify)
    {
        paymentSetting.QueryNotify();
    }
}

通过CanQueryNotify属性可以知道当前支付网关是否支持这种查询方式,如果支持再使用QueryNotify方法查询。支持查询订单的网关都实现了IQueryForm或者IQueryUrl接口。目前没有实现支持这种查询方式的支付网关,之前使用这种查询方式的网银在线已经删除掉了。


订单Id的建议

不同支付网关对订单Id有不同的限制。它可能被要求的只能是数字、数字英文跟一些指定字符组成,或者有长度限制,详细的说明请阅读相关支付网关的问题。

但共同点就是他们都可以使用数字作为订单Id,如果你需要同时使用多个支付网关,就应该考虑只使用数字作为订单Id。