问题 PayPal C#SDK端点


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

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

我正在使用PayPal Merchant SDK for .Net,ver 2.1.96.0。


8093
2018-01-24 18:49


起源

我是唯一一个受到PayPal荒谬声明的“INFURIATED”,“描述API的自我记录的类”通过了文档??? x.com/developers/paypal/documentation-tools/paypal-sdk-index - Simon_Weaver
显然他们已经在主代码库中解决了这个问题。我不确定如何,因为我现在不需要更新它,但如果您是这个问题的新手,您将首先检查最新的商家SDK - Simon_Weaver


答案:


我需要能够指定.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"]));

6
2018-04-18 17:29



这似乎是paypal提出的通过代码提供配置数据的方法 - 来自Paypal @knakai - 您现在可以在没有配置部分的情况下使用SDK - 您只需将其初始化为实例而不是静态使用它。这是来自较新版本的构造函数(确保您是最新的):public PayPalAPIInterfaceServiceService(Dictionary <string,object> config);您构建字典以传递给构造函数,因此它可以来自数据库或外部配置。 - Noam
这根本不是懒惰,这应该是现在接受的答案!这基本上应该是可能的。注意:这个构造函数是在你添加答案的时候添加的(我不确定确切的版本)。这发生在版本2.1.96和2.5.103之间,但是当我写了我疯狂的长期参与答案时,这个构造函数不存在 - Simon_Weaver


答案2:但如果您对编辑PayPal的代码没问题,这样可以正常工作......

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


编辑:这不是必要的 - 请看Simon Simon先生的回答


因此,在花了HOURS并编写我的应用程序后,我可以在live和sandbox之间切换端点(就像我以前直接调用SOAP服务时那样),我决定再去深入挖掘源代码并进行计算出。

以下是我为使其发挥作用所做的更改。

假设:

脚步:

  • 您将编辑PayPal的源代码并在本地编译 - 但只有2个文件:
  • 空白了 endpoint 在web.config下 <paypal>。建议安全预防措施!
  • 下载源代码 PayPalAPIInterfaceServiceService.cs  来自GitHub (商家SDK)
  • 下载源代码 DefaultSOAPAPICallHandler.cs  来自GitHub (核心SDK)
  • 您可能需要花一点时间来确保版本与nuGet包相同。

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

  • 我建议重命名这两个文件,以避免混淆和与NuGet版本冲突。我很沮丧,只是打电话给他们 SimonsPayPalAPIInterfaceServiceService 和 SimonsSOAPAPICallHandler  - 但无论你想要什么,都可以打电话

对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的更高版本,因为您必须重新执行此操作

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


4
2018-02-21 07:42



我印象深刻!我没有耐心跟踪这一点,并试图找出如何修改他们的代码以使其工作。话虽这么说,我现在更加确信他们的“API”只是他们的WSDL的重新包装,我强烈建议使用带有我的答案的硬编码绑定的Web服务。我想不出任何理由更喜欢打包的“API”。 - Bobson
我刚刚到达了这一点并且一切都井井有条的方式使它看起来像它一样 必须 有可能。我已经把时间投入到我自己的代码中,假设它可能是这样或那样我需要让它工作。在我的应用程序的先前版本中,我使用了WSDL,这不是问题我只是假设API是要走的路 - Simon_Weaver
好消息是,其中一位开发人员已经联系过我并告诉我他们同意这是一个有用的功能,他们将在下一个版本中实现它: github.com/paypal/SDKs/issues/43 - Simon_Weaver
这真棒!谢谢!! - ntsue
显然他们已经在主代码库中解决了这个问题。我不确定如何,因为我现在不需要更新它,但如果你是这个问题的新手,你会想先检查一下 - Simon_Weaver


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

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 代替。


3
2018-01-24 19:14



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


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

如果没有自己编译代码并且进行相当多的改变,这似乎是不可能的。这是当前的 来自GitHub的代码 对于 PayPalAPIInterfaceServiceService 这实际上是生成的 - 可能使用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.config 要么 app.config

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

遗憾的是,没有任何钩子或任何其他东西来改变终点。

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


1
2018-02-21 06:04



另见答案2 :-) - Simon_Weaver