【问题标题】:PayPal C# SDK Endpoint贝宝 C# SDK 端点
【发布时间】:2013-01-08 15:14:19
【问题描述】:

我正在寻找一种在代码中设置 PayPal SOAP API 端点的方法,而不是在 web.config 或 app.config 中指定它。我需要从不是 web.config/app.config 的环境特定配置中读取和使用端点。

这可能吗?我已经在他们的 github repo 上阅读了 SDK 的一些代码,这似乎是不可能的,但我希望我错过了一些东西。

我正在使用适用于 .Net 的 PayPal Merchant SDK,版本 2.1.96.0。

【问题讨论】:

  • 我是唯一一个被 PayPal 荒谬的声明激怒的人吗? x.com/developers/paypal/documentation-tools/paypal-sdk-index
  • 显然他们已经在主代码库中修复了这个问题。我不确定具体是怎么做的,因为我现在不需要更新它,但如果你是这个问题的新手,你会想先检查最新的商家 SDK

标签: c# paypal


【解决方案1】:

我需要能够指定 .config 文件之外的所有重要设置。我很懒所以我是这样做的:

paypalConfig = new Dictionary<string, string>();
paypalConfig.Add("apiUsername", "xxxxx");
paypalConfig.Add("apiPassword", "xxxxx");
paypalConfig.Add("apiSignature", "xxxxx");
==>paypalConfig.Add("mode","live|sandbox");

然后您需要通过再次指定凭据来调用您的方法(没有过多调查为什么这是必要的):

var service = new PayPalAPIInterfaceServiceService(paypalConfig);
var doCaptureResponse = service.DoCapture(amount, new SignatureCredential(paypalConfig["apiUsername"], paypalConfig["apiPassword"], paypalConfig["apiSignature"]));

【讨论】:

  • 这似乎是 paypal 通过代码提供配置数据的建议方式 - 来自 Paypal @knakai - 您现在可以在没有配置部分的情况下实际使用 SDK - 您只需将其初始化为实例而不是静态使用它。这是来自较新版本的构造函数(确保您是最新版本): public PayPalAPIInterfaceServiceService(Dictionary config);您构建字典以传递给构造函数,因此它可以来自数据库或外部配置。
  • 这一点都不懒,现在应该是公认的答案!这基本上是一直以来都应该做到的。注意:这个构造函数是在您添加答案时添加的(我不确定确切的版本)。这发生在 2.1.96 和 2.5.103 之间的某个地方,但是当我写出我疯狂的长期参与的答案时,这个构造函数不存在
【解决方案2】:

答案 2:但是如果您可以编辑 PayPal 的代码,这将可以正常工作...

(PayPal:如果您正在阅读本文,请实现此功能!)


编辑:不再需要 - 请参阅 Simon Labrecque 的回答


因此,在花费了 HOURS 并围绕我可以在实时和沙盒之间切换端点的期望编写了我的应用程序之后(就像我以前直接调用 SOAP 服务时一样),我决定继续深入研究源代码并弄清楚。

这是我为使其正常工作所做的更改。

假设:

步骤:

  • 您将编辑 PayPal 的源代码并在本地编译 - 但只有 2 个文件:
  • &lt;paypal&gt; 下的web.config 中删除endpoint。推荐的安全预防措施!
  • PayPalAPIInterfaceServiceService.csfrom GitHub(商户 SDK)的下载源
  • DefaultSOAPAPICallHandler.csfrom GitHub(核心 SDK)的下载源
  • 您可能需要花一点时间来确保版本与您的 nuGet 包相同。

  • 在您的项目中的文件夹 PayPalMerchantSDK 或类似的文件夹中复制这两个文件

  • 我建议重命名这两个文件以避免与 NuGet 版本混淆和冲突。我很沮丧,只是给他们打电话 SimonsPayPalAPIInterfaceServiceServiceSimonsSOAPAPICallHandler - 但随便你怎么称呼他们。

对 SimonsSOAPAPICallHandler.cs 的更改

更改构造函数以添加布尔值useSandbox

注意:它必须是第一个参数,因为我们很快就会做一些搜索和替换魔法。

    public SimonsSOAPAPICallHandler(bool useSandbox, string rawPayLoad, string attributesNamespace,
        string headerString)
        : base()
    {
        this.rawPayLoad = rawPayLoad;
        this.nmespceAttributes = attributesNamespace;
        this.headElement = headerString;

        // you can get these from config if you wish but I doubt they'll ever change
        this.endpoint = useSandbox ? "https://api-3t.sandbox.paypal.com/2.0" : "https://api-3t.paypal.com/2.0";
    }

更改GetEndPoint():

    /// <summary>
    /// Returns the endpoint for the API call
    /// </summary>
    /// <returns></returns>
    public string GetEndPoint()
    {
        return this.endpoint;
    }

添加对应的成员:

    /// <summary>
    /// Endpoint
    /// </summary>
    private string endpoint;

对 SimonsPayPalAPIInterfaceServiceService.cs 的更改

修改构造函数添加useSandbox参数

public SimonsPayPalAPIInterfaceServiceService(bool useSandbox) 
{ 
    this.useSandbox = useSandbox; 
}

添加对应的成员

    private bool useSandbox;

对此文件进行两次搜索和替换。每个人将有大约 100 个替代品

  • new DefaultSOAPAPICallHandler( 替换为new SimonsSOAPAPICallHandler(useSandbox,
  • DefaultSOAPAPICallHandler defaultHandler 替换为var defaultHandler

您刚刚所做的是将useSandbox 作为参数添加到SimonsSOAPAPICallHandler(谢天谢地实现了IAPICallPreHandler)的构造函数中,您最终会为每个方法得到这个:

 public DoExpressCheckoutPaymentResponseType DoExpressCheckoutPayment(DoExpressCheckoutPaymentReq doExpressCheckoutPaymentReq, string apiUserName)
{
    IAPICallPreHandler apiCallPreHandler = null;
    string portName = "PayPalAPIAA";
    setStandardParams(doExpressCheckoutPaymentReq.DoExpressCheckoutPaymentRequest);
    var defaultHandler = new SimonsSOAPAPICallHandler(useSandbox, doExpressCheckoutPaymentReq.ToXMLString(null, "DoExpressCheckoutPaymentReq"), null, null);
    apiCallPreHandler = new MerchantAPICallPreHandler(defaultHandler, apiUserName, getAccessToken(), getAccessTokenSecret());
    ((MerchantAPICallPreHandler) apiCallPreHandler).SDKName = SDKName;
    ((MerchantAPICallPreHandler) apiCallPreHandler).SDKVersion = SDKVersion;
    ((MerchantAPICallPreHandler) apiCallPreHandler).PortName = portName;
    string response = Call(apiCallPreHandler);
    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.LoadXml(response);
    XmlNode xmlNode = xmlDocument.SelectSingleNode("*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='DoExpressCheckoutPaymentResponse']");
    return new DoExpressCheckoutPaymentResponseType(xmlNode);

}

就是这样!

现在当你调用一个方法时你可以说...

bool useSandbox = true; // or false
var service = new SimonsPayPalAPIInterfaceServiceService(useSandbox);

然后正常调用方法

caller.DoExpressCheckoutPayment(pp_request, config.AccountName);

注意:它仍然会在您的配置中查找帐户名称以找到相应的密钥。显然请小心更新到更高版本的 Merchant SDK,因为您将不得不重新执行此操作

我希望有人觉得这很有用:-)

【讨论】:

  • 我印象深刻!我没有耐心去追查并尝试弄清楚如何修改他们的代码以使其工作。话虽如此,现在我更加确信他们的“API”只是对他们的 WSDL 的重新打包,我强烈建议仅使用带有我回答中的硬编码绑定的 Web 服务。我想不出任何理由更喜欢打包的“API”。
  • 我已经到了无法回头的地步,一切的组织方式使它乍一看就像必须是可能的。我已经在我自己的代码上投入了时间,假设我需要以一种或另一种方式让它工作。在我的应用程序的以前版本中,我使用了 WSDL,这不是问题,我只是假设 API 是要走的路
  • 好消息是,其中一位开发人员已经与我联系并告诉我他们同意这是一个有用的功能,他们将在下一个版本中实现它:github.com/paypal/SDKs/issues/43
  • 显然他们已经在主代码库中修复了这个问题。我不确定具体是怎么做的,因为我现在不需要更新它,但如果你是这个问题的新手,你会想先检查那里
【解决方案3】:

这是完全可行的,但您必须通过将绑定创建为对象来对值进行硬编码。这是我为自己的项目制定的:

protected static PayPalAPIInterface GetService()
{
    return new PayPalAPIInterfaceClient(new BasicHttpBinding()
            {
                SendTimeout = new TimeSpan(0, 5, 0),
                MaxReceivedMessageSize = 200000,
                Security = new BasicHttpSecurity()
                {
                    Mode = BasicHttpSecurityMode.Transport,
                    Transport = new HttpTransportSecurity()
                                    {
                                        ClientCredentialType = HttpClientCredentialType.None,
                                        ProxyCredentialType = HttpProxyCredentialType.None,
                                    },
                    Message = new BasicHttpMessageSecurity()
                                {
                                    ClientCredentialType = BasicHttpMessageCredentialType.Certificate,
                                }
                }
            },
            new EndpointAddress(@"https://api-3t.paypal.com/2.0/")
        ).ChannelFactory.CreateChannel();
}

您可以设置更多参数 - 理论上,.config 文件中的所有内容都可以在这里复制。不过,这对我有用,所以我没有采取任何进一步的措施。

还值得注意的是,这使您可以将 PayPal 调用放入库中,不必必须将绑定复制到包含该库的项目的配置文件中,这就是我开发的原因首先是它。


编辑:这是PayPalAPIInterfaceClient 的基本定义 - 不保证它实际上足以使用。

public partial class PayPalAPIInterfaceClient : System.ServiceModel.ClientBase<PayPalAPIInterfaceServiceService>
{
    public PayPalAPIInterfaceClient(System.ServiceModel.Channels.Binding binding,
                                    System.ServiceModel.EndpointAddress remoteAddress) 
           : base(binding, remoteAddress) { }
}

您还需要修改之前的代码,使其返回类型为 PayPalAPIInterfaceServiceService

【讨论】:

  • 在哪里可以找到 PayPalAPIInterfaceClient?我在 Merchant 或 Core SDK 中没有看到它...?
  • @wessiyad - 它是通过为https://www.paypal.com/wsdl/PayPalSvc.wsdl 创建一个新的服务引用自动生成的。
  • 我正在使用 SDK,所以我正在寻找一种方法来完成它。
  • @wessiyad - 看看我刚刚添加的内容是否有帮助。
  • 为什么没有得到更多的选票?我发现的唯一其他答案是更改 PayPal SDK 代码......这很简单,整洁,而且效果很好。 +1
【解决方案4】:

答案 1:我同意 - 不可能开箱即用。

如果不自己编译代码并进行大量更改,这似乎是不可能的。这是实际生成的PayPalAPIInterfaceServiceService 的当前code from GitHub - 可能使用T4 模板。这是一个 2489 行的大型文件,每个 API 方法都包含这样的代码。

这里的关键是IAPICallPreHandler。您会看到它被设置为 null,然后初始化为 MerchantAPICallPreHandler 的一个实例。没有办法传进去。

    public SetExpressCheckoutResponseType SetExpressCheckout(SetExpressCheckoutReq setExpressCheckoutReq, ICredential credential)
    {
        IAPICallPreHandler apiCallPreHandler = null;
        string portName = "PayPalAPIAA";
        setStandardParams(setExpressCheckoutReq.SetExpressCheckoutRequest);
        DefaultSOAPAPICallHandler defaultHandler = new DefaultSOAPAPICallHandler(setExpressCheckoutReq.ToXMLString(null, "SetExpressCheckoutReq"), null, null);
        apiCallPreHandler = new MerchantAPICallPreHandler(defaultHandler, credential);
        ((MerchantAPICallPreHandler) apiCallPreHandler).SDKName = SDKName;
        ((MerchantAPICallPreHandler) apiCallPreHandler).SDKVersion = SDKVersion;
        ((MerchantAPICallPreHandler) apiCallPreHandler).PortName = portName;
        string response = Call(apiCallPreHandler);
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.LoadXml(response);
        XmlNode xmlNode = xmlDocument.SelectSingleNode("*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='SetExpressCheckoutResponse']");
        return new SetExpressCheckoutResponseType(xmlNode);

    }

现在让我们看看界面:

public interface IAPICallPreHandler
{
    ICredential GetCredential();
    string GetEndPoint();
    Dictionary<string, string> GetHeaderMap();
    string GetPayLoad();
}

哇! GetEndPoint() 看起来不像我们想要覆盖的东西。

深入研究代码 - 最终调用的 GetEndPoint() 实例是 DefaultSOAPAPICallHandler 中的这个实例 - 如您所见,它直接指向 ConfigManager

    public string GetEndPoint() 
    {
        return ConfigManager.Instance.GetProperty(BaseConstants.END_POINT);
}

ConfigManager 直接转至web.configapp.config

  config = (SDKConfigHandler)ConfigurationManager.GetSection("paypal");

不幸的是,没有钩子或其他任何东西可以更改端点。

我考虑过在本地编译并修复它,但我宁愿失去在代码中更改端点的能力,也不愿失去一键更新整个包的能力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-14
    • 2017-07-14
    • 2017-02-12
    • 2014-09-06
    • 2014-07-30
    • 2013-10-09
    • 2017-03-09
    • 2018-06-12
    相关资源
    最近更新 更多