用c#和ASP实现PayPal智能按钮的客户端/服务器。网络核心
源代码
学习成果
- 如何建立PayPal商业账户。
- 如何为沙箱获取API凭据——即客户端ID和秘密。
- 如何获取实时的API凭证——例如客户端ID和Secret。
- 数据存储中的字段。
- 服务器端代码。
先决条件
- 您已经为您的电子商务网站注册了一个URL,例如,www.delaneys.space。
- 网站使用SSL证书进行保护。
- 您的客户可以注册和登录到您的网站在一个安全的方式使用OAuth或一些过度安全的方法。
- 你的网站有一个后台数据存储,你知道如何维护它。
- 你对Visual Studio很熟悉。
用下面的行标题创建一个电子表格:
1仪表板url https://www.paypal.com/mep/dashboard2开发者仪表板url https://developer.paypal.com/developer/applications3沙箱细节 4 url www.sandbox.paypal.com/5 app名称6业务7用户名……@business.example.com8密码,9客户端id10的秘密,11个人(顾客)12个用户名…@personal.example.com13个密码,14个生活细节 ,15个用户名info@……16个密码,17 app名称18客户id19个秘密,创建一个PayPal业务帐户
要创建一个PayPal商业账户,你不需要拥有自己的企业或商业银行账户。不过,你应该采取措施,把你的个人金融交易与电子商务网站的交易分开。因此,我建议使用一个单独的个人银行账户连接到你的PayPal业务账户。
- 导航到www.PayPal.com。点击注册,即使你已经有一个个人贝宝帐户。记住永远不要把工作和娱乐混为一谈。 选择业务帐户并单击Next。完成简短的问卷 对于“我想主要接受付款”的问题,选择“On my website”。选择问题“May annual volume is:”的答案。
- 提供一个电子邮件地址并单击Continue。 这可以是任何有效的电子邮件地址,但你可能想使用“info@youre-commerce.com”。 提供密码并单击Continue。 确认电子邮件将发送到所提供的地址。 更新你的电子表格。 15个用户名info@……16个密码, 完成业务联系细节页面,点击同意和创建帐户。 他们会要求你的联系人姓名,企业名称,电话号码和企业地址。 选择业务类型 从个人、独资、合伙、私人公司、上市公司、非营利组织、政府实体、信托投资和家庭的列表中选择。 添加个人信息。 包括你的姓名、出生日期和地址。 单击Submit。 您现在已经建立了您的PayPal业务帐户。您将看到一个仪表板显示。
获取API凭证——即客户端ID和秘密
- 进入开发人员控制面板: 2开发者仪表板url https://developer.paypal.com/developer/applications 沙箱选项将被预先选中。我们先来设置它。 单击“创建应用”。创建一个沙箱应用名称并存储在电子表格中。 17 app名称 再次单击Create App。 更新以下电子表格: 6业务7用户名…@business.example.com , 9客户端id10的秘密, 现在让我们获取密码。 点击沙箱|帐户按钮或(developer.paypal.com/developer/accounts/)。 您应该看到两个电子邮件地址表示一个企业帐户和个人帐户。 点击业务账户的…按钮,选择查看/编辑账户。 在电子表格中记录系统生成的密码。 8密码, 单击Close。点击个人帐户的…按钮,选择查看/编辑帐户。 在电子表格中记录用户名和密码。 11个人(顾客)12个用户名……@personal.example.com 13密码 |0>>>>;
为Live获取API凭据
- 点击我的应用程序&凭证(developer.paypal.com/developer/applications/)。单击Live按钮。 单击Create App。 在电子表格中记录应用程序名称。 17 app名称 点击创建App(再次)。 在电子表格中记录客户ID和secret。 18客户id19个秘密,
要向数据存储添加哪些字段
- 选择一个数据存储,比如SQL Servers。你需要一个篮子,项目和发票模型/核心类。将以下蓝色突出显示的字段添加到您的发票表中。这些字段将被贝宝使用。
- 注意,FirstName、LastName和Email存储在用户表中,但是也复制在Invoice表中。这是因为来自客户PayPal账户的数据可能与用户表中的数据不同。 由您决定如何在数据存储中包括蓝色字段。
服务器端代码
- Create an ASP.NET Core 3.x MVC application using Visual Studio.
- Go to NuGet package manager and add the following packages:
-
PayPalCheckoutSdk, package version 1.0.3. I used the latest version at the time of writing.
PayPalCheckoutSdk is merely a class library. There is no logic contained within the library. The classes are decorated with attributes to aid the serialisation into JSON.
-
PayPalHttp v1.0.0.
-
Microsoft.AspNetCore.Mvc.NewtonsoftJson. With the release of ASP.NET Core 3.0 Microsoft broke their implementation of JSON serialisation. Search for "ASP.NET Core: Blank Json {} Return After Upgrading to 3.0" to find out what to add to
Startup.ConfigureServices
or choose an option from the next step.
-
-
Update
Startup.ConfigureServices
to callAddNewtonsoftJson
.Hide Copy Codeservices.AddMvc() .AddNewtonsoftJson();
OR
Hide Copy Codeservices.AddMvc() .AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver());
- Create a folder called
PayPal
in your ASP.NET Core project. - Create a class
PayPalClient
in the folder, with the code below.
Remember to use the sandbox and live client Ids and secrets to populate the highlighted string content.Hide Shrink ggimggg0 Copy Codeusing System; using PayPalCheckoutSdk.Core; using System.IO; using System.Text; using System.Runtime.Serialization.Json; namespace PayPal { public class PayPalClient { // Place these static properties into a settings area. public static string SandboxClientId { get; set; } = "<alert>{PayPal SANDBOX Client Id}</alert>"; public static string SandboxClientSecret { get; set; } = "<alert>{PayPal SANDBOX Client Secret}</alert>"; public static string LiveClientId { get; set; } = "<alert>{PayPal LIVE Client Id}</alert>"; public static string LiveClientSecret { get; set; } = "<alert>{PayPal LIVE Client Secret}</alert>"; ///<summary> /// Set up PayPal environment with sandbox credentials. /// In production, use LiveEnvironment. ///</summary> public static PayPalEnvironment Environment() { #if DEBUG // You may want to create a UAT (user exceptance tester) role and check for this: // "if(_unitOfWork.IsUATTester(GetUserId())" instead of fcomiler directives. return new SandboxEnvironment(<alert>SandboxClientId</alert>, <alert>SandboxClientSecret</alert>); #else return new LiveEnvironment(<alert>LiveClientId</alert>, <alert>LiveClientSecret</alert>); #endif } ///<summary> /// Returns PayPalHttpClient instance to invoke PayPal APIs. ///</summary> public static PayPalCheckoutSdk.Core.PayPalHttpClient Client() { return new PayPalHttpClient(Environment()); } public static PayPalCheckoutSdk.Core.PayPalHttpClient Client(string refreshToken) { return new PayPalHttpClient(Environment(), refreshToken); } ///<summary> /// Use this method to serialize Object to a JSON string. ///</summary> public static String ObjectToJSONString(Object serializableObject) { MemoryStream memoryStream = new MemoryStream(); var writer = JsonReaderWriterFactory.CreateJsonWriter(memoryStream, Encoding.UTF8, true, true, " "); var ser = new DataContractJsonSerializer(serializableObject.GetType(), new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true }); ser.WriteObject(writer, serializableObject); memoryStream.Position = 0; StreamReader sr = new StreamReader(memoryStream); return sr.ReadToEnd(); } } }
- Create a class
SmartButtonHttpResponse
in the folder, with code.Hide Copy Codeusing System.Net; using System.Net.Http.Headers; namespace PayPal { public class SmartButtonHttpResponse { readonly PayPalCheckoutSdk.Orders.Order _result; public SmartButtonHttpResponse(PayPalHttp.HttpResponse httpResponse) { Headers = httpResponse.Headers; StatusCode = httpResponse.StatusCode; _result = httpResponse.Result<PayPalCheckoutSdk.Orders.Order>(); } public HttpHeaders Headers { get; } public HttpStatusCode StatusCode { get; } public PayPalCheckoutSdk.Orders.Order Result() { return _result; } public string orderID { get; set; } } }
-
Create a class
OrderBuilder
in the folder, with code.Hide Copy Codeusing PayPalCheckoutSdk.Orders; using System.Collections.Generic; namespace PayPal { public static class OrderBuilder { /// <summary> /// Use classes from the PayPalCheckoutSdk to build an OrderRequest /// </summary> /// <returns></returns> public static OrderRequest Build() { OrderRequest orderRequest = new OrderRequest(); // Add code to fill out the order request properties <alert>// See the attached source code for a more detailed example.</alert> return orderRequest; } } }
-
Create a controller class in the
Controllers
folder calledCheckoutController
. Add the following code.Hide Shrink ggimggg1 Copy Codeusing Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using PayPalCheckoutSdk.Orders; namespace Test.Controllers { public class CheckoutController : Controller { /// <summary> /// Action to display the cart form for the SERVER side intergration /// </summary> /// <returns></returns> public IActionResult Index() { #if DEBUG // You may want to create a UAT (user exceptance tester) role and check for this: // "if(_unitOfWork.IsUATTester(GetUserId())" // Company SANDBOX Client Id. To go live replace this with the live ID. ViewBag.ClientId = <alert>PayPal.PayPalClient.SandboxClientId</alert>; // Get from a data store or stettings #else // Company LIVE Client Id. To go live replace this with the live ID. ViewBag.ClientId = <alert>PayPal.PayPalClient.LiveClientId</alert>; // Get from a data store or stettings #endif ViewBag.CurrencyCode = "GBP"; // Get from a data store ViewBag.CurrencySign = "£"; // Get from a data store return View(); } /// <summary> /// This action is called when the user clicks on the PayPal button. /// </summary> /// <returns></returns> [Route("api/paypal/checkout/order/create")] public async Task<PayPal.SmartButtonHttpResponse> Create() { var request = new PayPalCheckoutSdk.Orders.OrdersCreateRequest(); request.Prefer("return=representation"); request.RequestBody(PayPal.OrderBuilder.Build()); // Call PayPal to set up a transaction var response = await PayPal.PayPalClient.Client().Execute(request); // Create a response, with an order id. var result = response.Result<PayPalCheckoutSdk.Orders.Order>(); var payPalHttpResponse = new PayPal.SmartButtonHttpResponse(response) { orderID = result.Id }; return payPalHttpResponse; } /// <summary> /// This action is called once the PayPal transaction is approved /// </summary> /// <paramname="orderId"></param> /// <returns></returns> [Route("api/paypal/checkout/order/approved/{orderId}")] public IActionResult Approved(string orderId) { return Ok(); } /// <summary> /// This action is called once the PayPal transaction is complete /// </summary> /// <paramname="orderId"></param> /// <returns></returns> [Route("api/paypal/checkout/order/complete/{orderId}")] public IActionResult Complete(string orderId) { // 1. Update the database. // 2. Complete the order process. Create and send invoices etc. // 3. Complete the shipping process. return Ok(); } /// <summary> /// This action is called once the PayPal transaction is complete /// </summary> /// <paramname="orderId"></param> /// <returns></returns> [Route("api/paypal/checkout/order/cancel/{orderId}")] public IActionResult Cancel(string orderId) { // 1. Remove the orderId from the database. return Ok(); } /// <summary> /// This action is called once the PayPal transaction is complete /// </summary> /// <paramname="orderId"></param> /// <returns></returns> [Route("api/paypal/checkout/order/error/{orderId}/{error}")] public IActionResult Error(string orderId, string error) { // Log the error. // Notify the user. return NoContent(); } } }
-
Create a
Checkout
folder in theViews
folder and add a view calledindex.cshtml
Add the following code to create the PayPal smart button to the view.
Hide Shrink ggimggg2 Copy Code<!-- Set up a container element for the PayPal smart button --> <divid="paypal-button-container"></div> <!-- Include the PayPal JavaScript SDK --> <scriptsrc="https://www.paypal.com/sdk/js?client-id=@ViewBag.ClientId¤cy=@ViewBag.CurrencyCode"></script> <script> // This is stored just in case the user cancels the other // or there is an error in the other process. var orderId; // Render the PayPal smart button into #paypal-button-container paypal.Buttons({ // Set up the transaction createOrder: function (data, actions) { orderId = data.orderID; return fetch('/api/paypal/checkout/order/create/', { method: 'post' }).then(function (res) { return res.json(); }).then(function (data) { return data.orderID; }); }, // Finalise the transaction onApprove: function (data, actions) { return fetch('/api/paypal/checkout/order/approved/' + data.orderID, { method: 'post' }).then(function (res) { return actions.order.capture(); }).then(function (details) { // (Preferred) Notify the server that the transaction id complete and have a option to display an order completed screen. window.location.replace('/api/paypal/checkout/order/complete/' + data.orderID + '/@ViewBag.CurrencyCode'); // OR // Notify the server that the transaction id complete //httpGet('/api/paypal/checkout/order/complete/' + data.orderID); // Show a success message to the buyer alert('Transaction completed by ' + details.payer.name.given_name + '!'); }); }, // Buyer cancelled the payment onCancel: function (data, actions) { httpGet('/api/paypal/checkout/order/cancel/' + data.orderID); }, // An error occurred during the transaction onError: function (err) { httpGet('/api/paypal/checkout/order/error/' + orderId + '/' + encodeURIComponent(err)); } }).render('#paypal-button-container'); </script>
Apart from the URLs, this code is the same for all solutions.
-
Add the following JavaScript function:
Hide Copy Codefunction httpGet(url) { var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", url, false); xmlHttp.send(null); return xmlHttp.responseText; }
-
Create a folder called
Values
within thePayPal
folder. -
Add a class called
CheckoutPaymentIntent.cs
, within theValues
folder.
Add the following code.Hide Shrink ggimggg3 Copy Codeusing System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace PayPal.Values { /// <summary> /// The intent to either capture payment immediately or /// authorize a payment for an order after order creation. /// </summary> public static class CheckoutPaymentIntent { /// <summary> /// The merchant intends to capture payment immediately after the customer makes a payment. /// </summary> public static string CAPTURE { get; private set; } = "CAPTURE"; /// <summary> /// The merchant intends to authorize a payment and /// place funds on hold after the customer makes a payment. /// Authorized payments are guaranteed for up to three days but /// are available to capture for up to 29 days. /// After the three-day honor period, the original authorized payment expires /// and you must re-authorize the payment. /// You must make a separate request to capture payments on demand. /// This intent is not supported when you have more than one `purchase_unit` within your order. /// </summary> public static string AUTHORIZE { get; private set; } = "AUTHORIZE"; } }
-
Add a class called
CurrencyCode.cs
, within theValues
folder.
Add the following code.Hide Copy Codeusing System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace PayPal.Values { public static class CurrencyCode { /// <summary> /// Great British Pounds /// </summary> public static string GBP { get; private set; } = "GBP"; /// <summary> /// US Dolars /// </summary> public static string USD { get; private set; } = "USD"; /// <summary> /// Euros /// </summary> public static string EUR { get; private set; } = "EUR"; } }
Add additional currencies, as required.
-
Add a class called
LandingPage.cs
, within theValues
folder.
Add the following code.Hide Shrink ggimggg4 Copy Codeusing System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace PayPal.Values { /// <summary> /// The type of landing page to show on the PayPal site for customer checkout. /// Default: NO_PREFERENCE. /// Source: https://developer.paypal.com/docs/api/orders/v2/ /// </summary> public class LandingPage { /// <summary> /// When the customer clicks PayPal Checkout, the customer is redirected to a page to log in to PayPal and approve the payment. /// </summary> public static string LOGIN { get; private set; } = "LOGIN"; /// <summary> /// When the customer clicks PayPal Checkout, /// the customer is redirected to a page to enter credit or /// debit card and other relevant billing information required to complete the purchase. /// </summary> public static string BILLING { get; private set; } = "BILLING"; /// <summary> /// When the customer clicks PayPal Checkout, /// the customer is redirected to either a page to log in to PayPal and /// approve the payment or to a page to enter credit or /// debit card and other relevant billing information /// required to complete the purchase, depending on their previous interaction with PayPal. /// </summary> public static string NO_PREFERENCE { get; private set; } = "NO_PREFERENCE"; } }
-
Add a class called
ShippingPreference.cs
, within theValues
folder.
Add the following code.Hide Shrink ggimggg5 Copy Codenamespace PayPal.Values { /// <summary> /// The shipping preference: /// /// * Displays the shipping address to the customer. /// * Enables the customer to choose an address on the PayPal site. /// * Restricts the customer from changing the address during the payment-approval process. /// /// Default: GET_FROM_FILE. /// Source: https://developer.paypal.com/docs/api/orders/v2/ /// </summary> public static class ShippingPreference { /// <summary> /// Use the customer-provided shipping address on the PayPal site. /// </summary> public static string GET_FROM_FILE { get; private set; } = "GET_FROM_FILE"; /// <summary> /// Redact the shipping address from the PayPal site. Recommended for digital goods. /// </summary> public static string NO_SHIPPING { get; private set; } = "NO_SHIPPING"; /// <summary> /// Use the merchant-provided address. The customer cannot change this address on the PayPal site. /// </summary> public static string SET_PROVIDED_ADDRESS { get; private set; } = "SET_PROVIDED_ADDRESS"; } }
-
Add a class called
UserAction.cs
, within theValues
folder.
Add the following code.Hide Shrink ggimggg6 Copy Codeusing System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace PayPal.Values { /// <summary> /// Configures a Continue or Pay Now checkout flow. /// Source: https://developer.paypal.com/docs/api/orders/v2/ /// </summary> public static class UserAction { /// <summary> /// After you redirect the customer to the PayPal payment page, /// a Continue button appears. Use this option when the final amount is not known /// when the checkout flow is initiated and you want to redirect /// the customer to the merchant page without processing the payment. /// </summary> public static string CONTINUE { get; private set; } = "CONTINUE"; /// <summary> /// After you redirect the customer to the PayPal payment page, /// a Pay Now button appears. /// Use this option when the final amount is known when the checkout is initiated /// and you want to process the payment immediately when the customer clicks Pay Now. /// </summary> public static string PAY_NOW { get; private set; } = "PAY_NOW"; } }
-
Create a folder called
Item
within thePayPal\Values
folder. -
Add a class called
Category.cs
, within theValues
folder.
Add the following code.Hide Shrink ggimggg7 Copy Codeusing System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace PayPal.Values.Item { /// <summary> /// The item category type. /// </summary> public static class Category { /// <summary> /// Goods that are stored, delivered, and /// used in their electronic format. /// This value is not currently supported for API callers that leverage the /// [PayPal for Commerce Platform](https://www.paypal.com/us/webapps/mpp/commerce-platform) product. /// </summary> public static string DIGITAL_GOODS { get; private set; } = "DIGITAL_GOODS"; /// <summary> /// A tangible item that can be shipped with proof of delivery. /// </summary> public static string PHYSICAL_GOODS { get; private set; } = "PHYSICAL_GOODS"; } }
- The final step is to write code to handle what happens when the following code is called:
api/paypal/checkout/order/create
api/paypal/checkout/order/approved/{orderId}
api/paypal/checkout/order/complete/{orderId}
api/paypal/checkout/order/cancel/{orderId}
api/paypal/checkout/order/error/{orderId}/{error}
- Good Luck.
本文转载于:http://www.diyabc.com/frontweb/news14859.html