Поделиться через


Оформление заказа и оплата по PayPal

Эрик Рейтан (Erik Reitan)

Скачать пример проекта Wingtip Toys (C#) или скачать электронную книгу (PDF)

В этой серии учебников вы узнаете об основах создания приложения ASP.NET Web Forms с помощью ASP.NET 4.5 и Microsoft Visual Studio Express 2013 для Интернета. В этой серии руководств доступен проект Visual Studio 2013 с исходным кодом C#.

В этом руководстве описывается, как изменить пример приложения Wingtip Toys, чтобы включить авторизацию пользователя, регистрацию и оплату с помощью PayPal. Только пользователи, выполнившие вход в систему, будут иметь разрешение на покупку продуктов. Встроенная функция регистрации пользователей в шаблоне проекта ASP.NET 4.5 веб-формы уже включает в себя большую часть необходимого. Вы добавите функцию оформления заказа PayPal Express. В этом руководстве вы используете среду тестирования для разработчиков PayPal, поэтому фактические средства не будут переведены. В конце учебника вы протестируете приложение, выбрав продукты для добавления в корзину, нажав кнопку оформления заказа и передав данные на веб-сайт тестирования PayPal. На тестовом веб-сайте PayPal вы подтвердите сведения о доставке и оплате, а затем вернитесь в пример приложения Wingtip Toys, чтобы подтвердить и завершить покупку.

Существует несколько опытных сторонних платежных процессоров, специализирующихся на онлайн-покупках, которые решают проблемы масштабируемости и безопасности. ASP.NET разработчики должны учитывать преимущества использования стороннего решения для оплаты перед реализацией решения для покупок и покупок.

Примечание

Пример приложения Wingtip Toys был разработан, чтобы показать конкретные ASP.NET концепции и функции, доступные ASP.NET веб-разработчикам. Этот пример приложения не был оптимизирован для всех возможных обстоятельств с точки зрения масштабируемости и безопасности.

Из этого руководства вы узнаете, как выполнять такие задачи:

  • Как ограничить доступ к определенным страницам в папке.
  • Как создать известную корзину для покупок из анонимной корзины.
  • Как включить SSL для проекта.
  • Добавление поставщика OAuth в проект.
  • Использование PayPal для приобретения продуктов с помощью среды тестирования PayPal.
  • Отображение сведений из PayPal в элементе управления DetailsView .
  • Как обновить базу данных приложения Wingtip Toys с помощью сведений, полученных из PayPal.

Добавление отслеживания заказов

В этом руководстве вы создадите два новых класса для отслеживания данных из заказа, созданного пользователем. Классы будут отслеживать данные, касающиеся сведений о доставке, общей сумме покупки и подтверждении оплаты.

Добавление классов моделей Order и OrderDetail

Ранее в этой серии руководств вы определили схему для категорий, продуктов и элементов корзины, создав Categoryклассы , Productи CartItem в папке Models . Теперь вы добавите два новых класса, чтобы определить схему для заказа на продукт и сведения о заказе.

  1. В папке Models добавьте новый класс с именем Order.cs.
    Новый файл класса отображается в редакторе.

  2. Замените его код по умолчанию на следующий код.

    using System;
    using System.ComponentModel.DataAnnotations;
    using System.Collections.Generic;
    using System.ComponentModel;
    
    namespace WingtipToys.Models
    {
      public class Order
      {
        public int OrderId { get; set; }
    
        public DateTime OrderDate { get; set; }
    
        public string Username { get; set; }
    
        [Required(ErrorMessage = "First Name is required")]
        [DisplayName("First Name")]
        [StringLength(160)]
        public string FirstName { get; set; }
    
        [Required(ErrorMessage = "Last Name is required")]
        [DisplayName("Last Name")]
        [StringLength(160)]
        public string LastName { get; set; }
    
        [Required(ErrorMessage = "Address is required")]
        [StringLength(70)]
        public string Address { get; set; }
    
        [Required(ErrorMessage = "City is required")]
        [StringLength(40)]
        public string City { get; set; }
    
        [Required(ErrorMessage = "State is required")]
        [StringLength(40)]
        public string State { get; set; }
    
        [Required(ErrorMessage = "Postal Code is required")]
        [DisplayName("Postal Code")]
        [StringLength(10)]
        public string PostalCode { get; set; }
    
        [Required(ErrorMessage = "Country is required")]
        [StringLength(40)]
        public string Country { get; set; }
    
        [StringLength(24)]
        public string Phone { get; set; }
    
        [Required(ErrorMessage = "Email Address is required")]
        [DisplayName("Email Address")]
        [RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}",
            ErrorMessage = "Email is is not valid.")]
        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }
    
        [ScaffoldColumn(false)]
        public decimal Total { get; set; }
    
        [ScaffoldColumn(false)]
        public string PaymentTransactionId { get; set; }
    
        [ScaffoldColumn(false)]
        public bool HasBeenShipped { get; set; }
    
        public List<OrderDetail> OrderDetails { get; set; }
      }
    }
    
  3. Добавьте класс OrderDetail.cs в папку Models .

  4. Замените код по умолчанию на приведенный ниже:

    using System.ComponentModel.DataAnnotations;
    
    namespace WingtipToys.Models
    {
        public class OrderDetail
        {
            public int OrderDetailId { get; set; }
    
            public int OrderId { get; set; }
    
            public string Username { get; set; }
    
            public int ProductId { get; set; }
    
            public int Quantity { get; set; }
    
            public double? UnitPrice { get; set; }
    
        }
    }
    

Классы Order и OrderDetail содержат схему для определения сведений о заказах, используемых для приобретения и доставки.

Кроме того, необходимо обновить класс контекста базы данных, который управляет классами сущностей и предоставляет доступ к данным в базу данных. Для этого вы добавите в класс только что созданные классы ProductContext Order и OrderDetail model.

  1. В Обозреватель решений найдите и откройте файл ProductContext.cs.

  2. Добавьте выделенный код в файл ProductContext.cs , как показано ниже:

    using System.Data.Entity;
    
    namespace WingtipToys.Models
    {
      public class ProductContext : DbContext
      {
        public ProductContext()
          : base("WingtipToys")
        {
        }
        public DbSet<Category> Categories { get; set; }
        public DbSet<Product> Products { get; set; }
        public DbSet<CartItem> ShoppingCartItems { get; set; }
        public DbSet<Order> Orders { get; set; }
        public DbSet<OrderDetail> OrderDetails { get; set; }
      }
    }
    

Как упоминалось ранее в этой серии руководств, код в файле ProductContext.cs добавляет System.Data.Entity пространство имен, чтобы у вас был доступ ко всем основным функциям Entity Framework. Эта функция включает возможность запрашивать, вставлять, обновлять и удалять данные путем работы со строго типизированными объектами. Приведенный выше код в ProductContext классе добавляет доступ Entity Framework к только что добавленным Order классам и OrderDetail .

Добавление доступа к оформлению заказа

Пример приложения Wingtip Toys позволяет анонимным пользователям просматривать и добавлять продукты в корзину. Однако, когда анонимные пользователи предпочитают приобретать продукты, добавленные в корзину, они должны войти на сайт. После входа они могут получить доступ к страницам веб-приложения с ограниченным доступом, которые обрабатывают процесс оформления заказа и покупки. Эти страницы с ограниченным доступом содержатся в папке Checkout приложения.

Добавление папки и страниц оформления заказа

Теперь вы создадите папку Checkout и страницы в ней, которые клиент увидит во время оформления заказа. Вы обновите эти страницы позже в этом руководстве.

  1. Щелкните правой кнопкой мыши имя проекта (Wingtip Toys) в Обозреватель решений и выберите Добавить новую папку.

    Извлечение и оплата с помощью PayPal — новая папка

  2. Назовите новую папку Checkout.

  3. Щелкните правой кнопкой мыши папку Checkout и выберите Добавить новый>элемент.

    Оформления заказа и оплаты с помощью PayPal — новый элемент

  4. Откроется диалоговое окно Добавление нового элемента.

  5. Выберите группу Visual C# - Веб-шаблоны> слева. Затем в средней области выберите Веб-форма с главной страницейи присвойте ей имя CheckoutStart.aspx.

    Извлечение и оплата с помощью PayPal — диалоговое окно добавления нового элемента

  6. Как и ранее, выберите файл Site.Master в качестве страницы master.

  7. Добавьте следующие дополнительные страницы в папку Checkout , выполнив те же действия, что и выше:

    • CheckoutReview.aspx
    • CheckoutComplete.aspx
    • CheckoutCancel.aspx
    • CheckoutError.aspx

Добавление файла Web.config

Добавив новый файлWeb.config в папку Checkout , вы сможете ограничить доступ ко всем страницам, содержащимся в папке.

  1. Щелкните правой кнопкой мыши папку Checkout и выберите Добавить ->Новый элемент.
    Откроется диалоговое окно Добавление нового элемента.

  2. Выберите группу Visual C# - Веб-шаблоны> слева. Затем в средней области выберите Файл веб-конфигурации, примите имя по умолчанию Web.configи нажмите кнопку Добавить.

  3. Замените существующее XML-содержимое в файле Web.config на следующее:

    <?xml version="1.0"?>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?"/>
        </authorization>
      </system.web>
    </configuration>
    
  4. Сохраните файл Web.config.

Файл Web.config указывает, что всем неизвестным пользователям веб-приложения должно быть отказано в доступе к страницам, содержащимся в папке Checkout . Однако если пользователь зарегистрировал учетную запись и вошел в систему, он будет известным пользователем и будет иметь доступ к страницам в папке Checkout .

Важно отметить, что ASP.NET конфигурация следует иерархии, где каждый файлWeb.config применяет параметры конфигурации к папке, в которой он находится, и ко всем дочерним каталогам под ним.

Включение SSL для проекта

Secure Sockets Layer (SSL) — это протокол, позволяющие веб-серверам и веб-клиентам более безопасно обмениваться данными с помощью шифрования. Если протокол SSL не используется, пакеты данных, передаваемые между клиентом и сервером, открыты для сканирования любому человеку с физическим доступом к сети. Кроме того, некоторые распространенные схемы проверки подлинности небезопасны при использовании простого HTTP. В частности, базовая проверка подлинности и формы проверки подлинности отправляют незашифрованные учетные данные. Чтобы обеспечить безопасность, эти схемы проверки подлинности должны использовать протокол SSL.

  1. В Обозреватель решений щелкните проект WingtipToys, а затем нажмите клавишу F4, чтобы открыть окно Свойства.
  2. Для параметра SSL включен измените значение на true.
  3. Скопируйте URL-адрес SSL для дальнейшего использования.
    URL-адрес SSL будет указан https://localhost:44300/ , если вы ранее не создали веб-сайты SSL (как показано ниже).
    Свойства проекта
  4. В Обозреватель решений щелкните правой кнопкой мыши проект WingtipToys и выберите пункт Свойства.
  5. На левой вкладке щелкните Интернет.
  6. Измените URL-адрес проекта , чтобы использовать URL-адрес SSL , сохраненный ранее.
    Веб-свойства проекта
  7. Сохраните страницу, нажав CTRL+S.
  8. Для запуска приложения нажмите сочетание клавиш Ctrl+F5 . В Visual Studio будет отображаться параметр, который позволяет отключить предупреждающие сообщения SSL.
  9. Нажмите Да , чтобы начать доверять сертификату IIS Express SSL и продолжить работу.
    сведения о SSL-сертификате IIS Express
    Отобразится предупреждение системы безопасности.
  10. Нажмите Да , чтобы установить сертификат для вашего localhost.
    Диалоговое окно
    Откроется окно браузера.

Теперь вы можете легко протестировать веб-приложение локально с помощью SSL.

Добавление поставщика OAuth 2.0

Веб-формы ASP.NET предлагают расширенные параметры для членства и проверки подлинности. К этим расширениям относится OAuth. OAuth — это открытый протокол, обеспечивающий безопасную авторизацию простым и стандартным методом из веб-приложений, мобильных и настольных приложений. Шаблон ASP.NET Web Forms использует OAuth для предоставления Facebook, Twitter, Google и Майкрософт в качестве поставщиков проверки подлинности. В этом учебнике в качестве поставщика проверки подлинности используется только Google, но вы легко можете изменить код, чтобы использовать любой другой поставщик. Шаги по реализации других поставщиков очень похожи на шаги, представленные в этом учебнике.

Помимо проверки подлинности в учебнике будут использоваться роли для реализации авторизации. Только пользователи, добавленные в роль canEdit , смогут изменять данные (создавать, изменять и удалять контакты).

Примечание

Приложения Windows Live принимают только динамический URL-адрес для рабочего веб-сайта, поэтому вы не можете использовать URL-адрес локального веб-сайта для проверки входа.

В последующих шагах вы сможете добавить поставщика проверки подлинности Google.

  1. Откройте файл App_Start\Startup.Auth.cs .

  2. Удалите символы комментариев из метода app.UseGoogleAuthentication() , чтобы метод выглядел следующим образом:

    app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
    {
        ClientId = "",
        ClientSecret = ""
    });
    
  3. Перейдите к Консоли разработчиков Google. Вам также потребуется выполнить вход со своей учетной записью электронной почты разработчика Google (gmail.com). Если отсутствует учетная запись Google, выберите ссылку Создать учетную запись .
    Далее вы ознакомитесь с консолью разработчиков Google.
    Консоль разработчиков Google

  4. Нажмите кнопку Создать проект и введите имя и идентификатор проекта (можно использовать значения по умолчанию). Затем установите флажок соглашения и кнопку Создать .

    Google — новый проект

    Через несколько секунд будет создан новый проект, а в браузере будет отображаться новая страница проектов.

  5. На вкладке слева щелкните API-интерфейсы & проверки подлинности, а затем щелкните Учетные данные.

  6. Щелкните Создать идентификатор клиента в разделе OAuth.
    Откроется диалоговое окно Создание идентификатора клиента .
    Google — создание идентификатора клиента

  7. В диалоговом окне Создание идентификатора клиента сохраните веб-приложение по умолчанию для типа приложения.

  8. Задайте для параметра Авторизованные источники JavaScript URL-адрес SSL, который использовался ранее в этом руководстве (https://localhost:44300/ если только вы не создали другие проекты SSL).
    Этот URL-адрес является источником вашего приложения. В нашем примере вводится только тестовый URL-адрес localhost. Однако можно ввести несколько URL-адресов для учета localhost и production.

  9. Задайте в поле Авторизованный URI перенаправления следующее значение:

    https://localhost:44300/signin-google
    

    Это значение представляет собой URI, который ASP.NET OAuth использует для обмена данными с сервером Google OAuth. Запомните URL-адрес SSL, который вы использовали выше ( https://localhost:44300/ если вы не создали другие проекты SSL).

  10. Нажмите кнопку Создать идентификатор клиента .

  11. В меню слева в консоли разработчиков Google щелкните пункт меню "Согласие" , а затем укажите адрес электронной почты и название продукта. Завершив заполнение формы, нажмите кнопку Сохранить.

  12. Щелкните пункт меню API , прокрутите страницу вниз и нажмите кнопку "Выкл ." рядом с пунктом API Google+.
    При принятии этого параметра будет включен API Google+.

  13. Также необходимо обновить пакет NuGet Microsoft.Owin до версии 3.0.0.
    В меню Сервис выберите Диспетчер пакетов NuGet , а затем — Управление пакетами NuGet для решения.
    В окне Управление пакетами NuGet найдите и обновите пакет Microsoft.Owin до версии 3.0.0.

  14. В Visual Studio обновите UseGoogleAuthentication метод страницы Startup.Auth.cs , скопировав и вставив идентификатор клиента и секрет клиента в метод . Приведенные ниже значения идентификатора клиента и секрета клиента являются примерами и не будут работать.

    using System;
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.EntityFramework;
    using Microsoft.AspNet.Identity.Owin;
    using Microsoft.Owin;
    using Microsoft.Owin.Security.Cookies;
    using Microsoft.Owin.Security.DataProtection;
    using Microsoft.Owin.Security.Google;
    using Owin;
    using WingtipToys.Models;
    
    namespace WingtipToys
    {
        public partial class Startup {
    
            // For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301883
            public void ConfigureAuth(IAppBuilder app)
            {
                // Configure the db context, user manager and signin manager to use a single instance per request
                app.CreatePerOwinContext(ApplicationDbContext.Create);
                app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
                app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
    
                // Enable the application to use a cookie to store information for the signed in user
                // and to use a cookie to temporarily store information about a user logging in with a third party login provider
                // Configure the sign in cookie
                app.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                    LoginPath = new PathString("/Account/Login"),
                    Provider = new CookieAuthenticationProvider
                    {
                        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                            validateInterval: TimeSpan.FromMinutes(30),
                            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                    }
                });
                // Use a cookie to temporarily store information about a user logging in with a third party login provider
                app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
    
                // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
                app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
    
                // Enables the application to remember the second login verification factor such as phone or email.
                // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
                // This is similar to the RememberMe option when you log in.
                app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
    
                // Uncomment the following lines to enable logging in with third party login providers
                //app.UseMicrosoftAccountAuthentication(
                //    clientId: "",
                //    clientSecret: "");
    
                //app.UseTwitterAuthentication(
                //   consumerKey: "",
                //   consumerSecret: "");
    
                //app.UseFacebookAuthentication(
                //   appId: "",
                //   appSecret: "");
    
                app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
                {
                  ClientId = "000000000000.apps.googleusercontent.com",
                  ClientSecret = "00000000000"
                });
            }
        }
    }
    
  15. Нажмите клавиши CTRL+F5 , чтобы выполнить сборку и запуск приложения. Щелкните ссылку Войти в систему .

  16. В разделе Использовать другую службу для входа щелкнитеGoogle.
    Войти

  17. Если будет необходимо ввести учетные данные, произойдет перенаправление на сайт Google, где можно будет ввести свои учетные данные.
    Google — вход

  18. После ввода учетных данных вам будет предложено предоставить разрешения только что созданному веб-приложению.
    Учетная запись службы проекта по умолчанию

  19. Нажмите кнопку Принимаю. Теперь вы будете перенаправлены обратно на страницу Регистрация приложения WingtipToys , где вы можете зарегистрировать свою учетную запись Google.
    Регистрация с помощью учетной записи Google

  20. Вы можете изменить локальное имя регистрации электронной почты, используемое для вашей учетной записи Gmail, но обычно требуется сохранить псевдоним электронной почты по умолчанию (то есть псевдоним, используемый для проверки подлинности). Щелкните Войти, как показано выше.

Изменение функциональных возможностей входа

Как упоминалось ранее в этой серии руководств, большая часть функций регистрации пользователей включена в шаблон ASP.NET Web Forms по умолчанию. Теперь вы измените страницы Login.aspx и Register.aspx по умолчанию, чтобы вызвать MigrateCart метод . Метод MigrateCart связывает только что выполнившего вход пользователя с анонимной корзиной для покупок. Связав пользователя и корзину, пример приложения Wingtip Toys сможет поддерживать корзину пользователя между посещениями.

  1. В Обозреватель решений найдите и откройте папку Учетная запись.

  2. Измените страницу кода программной части с именем Login.aspx.cs , чтобы она была выделена желтым цветом, чтобы она выглядела следующим образом:

    using System;
    using System.Web;
    using System.Web.UI;
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.Owin;
    using Owin;
    using WingtipToys.Models;
    
    namespace WingtipToys.Account
    {
        public partial class Login : Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                RegisterHyperLink.NavigateUrl = "Register";
                // Enable this once you have account confirmation enabled for password reset functionality
                //ForgotPasswordHyperLink.NavigateUrl = "Forgot";
                OpenAuthLogin.ReturnUrl = Request.QueryString["ReturnUrl"];
                var returnUrl = HttpUtility.UrlEncode(Request.QueryString["ReturnUrl"]);
                if (!String.IsNullOrEmpty(returnUrl))
                {
                    RegisterHyperLink.NavigateUrl += "?ReturnUrl=" + returnUrl;
                }
            }
    
            protected void LogIn(object sender, EventArgs e)
            {
                if (IsValid)
                {
                    // Validate the user password
                    var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
                    var signinManager = Context.GetOwinContext().GetUserManager<ApplicationSignInManager>();
    
                    // This doen't count login failures towards account lockout
                    // To enable password failures to trigger lockout, change to shouldLockout: true
                    var result = signinManager.PasswordSignIn(Email.Text, Password.Text, RememberMe.Checked, shouldLockout: false);
    
                    switch (result)
                    {
                        case SignInStatus.Success:
                            WingtipToys.Logic.ShoppingCartActions usersShoppingCart = new WingtipToys.Logic.ShoppingCartActions();
                            String cartId = usersShoppingCart.GetCartId();
                            usersShoppingCart.MigrateCart(cartId, Email.Text);
    
                            IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
                            break;
                        case SignInStatus.LockedOut:
                            Response.Redirect("/Account/Lockout");
                            break;
                        case SignInStatus.RequiresVerification:
                            Response.Redirect(String.Format("/Account/TwoFactorAuthenticationSignIn?ReturnUrl={0}&RememberMe={1}", 
                                                            Request.QueryString["ReturnUrl"],
                                                            RememberMe.Checked),
                                              true);
                            break;
                        case SignInStatus.Failure:
                        default:
                            FailureText.Text = "Invalid login attempt";
                            ErrorMessage.Visible = true;
                            break;
                    }
                }
            }
        }
    }
    
  3. Сохраните файл Login.aspx.cs .

На данный момент можно игнорировать предупреждение о том, что для MigrateCart метода нет определения. Вы добавите его чуть позже в этом руководстве.

Файл кода программной части Login.aspx.cs поддерживает метод LogIn. Проверив страницу Login.aspx, вы увидите, что эта страница содержит кнопку "Вход", которая при нажатии кнопки активирует LogIn обработчик кода программной части.

При вызове Login метода в файле Login.aspx.cs создается новый экземпляр корзины с именем usersShoppingCart . Извлекается идентификатор корзины (GUID) и устанавливается cartId переменная . MigrateCart Затем вызывается метод , передавая этому методу cartId имя и имя пользователя, выполнившего вход. При переносе корзины guid, используемый для идентификации анонимной корзины, заменяется именем пользователя.

Помимо изменения файла кода программной части Login.aspx.cs для переноса корзины при входе пользователя, необходимо также изменить файл кода программной части Register.aspx.cs , чтобы перенести корзину, когда пользователь создает новую учетную запись и входит в систему.

  1. В папке Account откройте файл кода программной части с именем Register.aspx.cs.

  2. Измените файл кода программной части, добавив код желтым цветом, чтобы он выглядел следующим образом:

    using System;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.Owin;
    using Owin;
    using WingtipToys.Models;
    
    namespace WingtipToys.Account
    {
        public partial class Register : Page
        {
            protected void CreateUser_Click(object sender, EventArgs e)
            {
                var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
                var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text };
                IdentityResult result = manager.Create(user, Password.Text);
                if (result.Succeeded)
                {
                    // For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
                    //string code = manager.GenerateEmailConfirmationToken(user.Id);
                    //string callbackUrl = IdentityHelper.GetUserConfirmationRedirectUrl(code, user.Id, Request);
                    //manager.SendEmail(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>.");
    
                    IdentityHelper.SignIn(manager, user, isPersistent: false);
    
                    using (WingtipToys.Logic.ShoppingCartActions usersShoppingCart = new WingtipToys.Logic.ShoppingCartActions())
                    {
                      String cartId = usersShoppingCart.GetCartId();
                      usersShoppingCart.MigrateCart(cartId, user.Id);
                    }
    
                    IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
                }
                else 
                {
                    ErrorMessage.Text = result.Errors.FirstOrDefault();
                }
            }
        }
    }
    
  3. Сохраните файл Register.aspx.cs . Еще раз игнорируйте предупреждение о методе MigrateCart .

Обратите внимание, что код, используемый в обработчике CreateUser_Click событий, очень похож на код, используемый в методе LogIn . Когда пользователь регистрируется или входит на сайт, выполняется вызов MigrateCart метода .

Перенос корзины покупок

Теперь, когда процесс входа и регистрации обновлен, можно добавить код для переноса корзины MigrateCart с помощью метода .

  1. В Обозреватель решений найдите папку Logic и откройте файл класса ShoppingCartActions.cs.

  2. Добавьте выделенный желтым цветом код в существующий код в файле ShoppingCartActions.cs , чтобы код в файле ShoppingCartActions.cs выглядел следующим образом:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using WingtipToys.Models;
    
    namespace WingtipToys.Logic
    {
      public class ShoppingCartActions : IDisposable
      {
        public string ShoppingCartId { get; set; }
    
        private ProductContext _db = new ProductContext();
    
        public const string CartSessionKey = "CartId";
    
        public void AddToCart(int id)
        {
          // Retrieve the product from the database.           
          ShoppingCartId = GetCartId();
    
          var cartItem = _db.ShoppingCartItems.SingleOrDefault(
              c => c.CartId == ShoppingCartId
              && c.ProductId == id);
          if (cartItem == null)
          {
            // Create a new cart item if no cart item exists.                 
            cartItem = new CartItem
            {
              ItemId = Guid.NewGuid().ToString(),
              ProductId = id,
              CartId = ShoppingCartId,
              Product = _db.Products.SingleOrDefault(
               p => p.ProductID == id),
              Quantity = 1,
              DateCreated = DateTime.Now
            };
    
            _db.ShoppingCartItems.Add(cartItem);
          }
          else
          {
            // If the item does exist in the cart,                  
            // then add one to the quantity.                 
            cartItem.Quantity++;
          }
          _db.SaveChanges();
        }
    
        public void Dispose()
        {
          if (_db != null)
          {
            _db.Dispose();
            _db = null;
          }
        }
    
        public string GetCartId()
        {
          if (HttpContext.Current.Session[CartSessionKey] == null)
          {
            if (!string.IsNullOrWhiteSpace(HttpContext.Current.User.Identity.Name))
            {
              HttpContext.Current.Session[CartSessionKey] = HttpContext.Current.User.Identity.Name;
            }
            else
            {
              // Generate a new random GUID using System.Guid class.     
              Guid tempCartId = Guid.NewGuid();
              HttpContext.Current.Session[CartSessionKey] = tempCartId.ToString();
            }
          }
          return HttpContext.Current.Session[CartSessionKey].ToString();
        }
    
        public List<CartItem> GetCartItems()
        {
          ShoppingCartId = GetCartId();
    
          return _db.ShoppingCartItems.Where(
              c => c.CartId == ShoppingCartId).ToList();
        }
    
        public decimal GetTotal()
        {
          ShoppingCartId = GetCartId();
          // Multiply product price by quantity of that product to get        
          // the current price for each of those products in the cart.  
          // Sum all product price totals to get the cart total.   
          decimal? total = decimal.Zero;
          total = (decimal?)(from cartItems in _db.ShoppingCartItems
                             where cartItems.CartId == ShoppingCartId
                             select (int?)cartItems.Quantity *
                             cartItems.Product.UnitPrice).Sum();
          return total ?? decimal.Zero;
        }
    
        public ShoppingCartActions GetCart(HttpContext context)
        {
          using (var cart = new ShoppingCartActions())
          {
            cart.ShoppingCartId = cart.GetCartId();
            return cart;
          }
        }
    
        public void UpdateShoppingCartDatabase(String cartId, ShoppingCartUpdates[] CartItemUpdates)
        {
          using (var db = new WingtipToys.Models.ProductContext())
          {
            try
            {
              int CartItemCount = CartItemUpdates.Count();
              List<CartItem> myCart = GetCartItems();
              foreach (var cartItem in myCart)
              {
                // Iterate through all rows within shopping cart list
                for (int i = 0; i < CartItemCount; i++)
                {
                  if (cartItem.Product.ProductID == CartItemUpdates[i].ProductId)
                  {
                    if (CartItemUpdates[i].PurchaseQuantity < 1 || CartItemUpdates[i].RemoveItem == true)
                    {
                      RemoveItem(cartId, cartItem.ProductId);
                    }
                    else
                    {
                      UpdateItem(cartId, cartItem.ProductId, CartItemUpdates[i].PurchaseQuantity);
                    }
                  }
                }
              }
            }
            catch (Exception exp)
            {
              throw new Exception("ERROR: Unable to Update Cart Database - " + exp.Message.ToString(), exp);
            }
          }
        }
    
        public void RemoveItem(string removeCartID, int removeProductID)
        {
          using (var _db = new WingtipToys.Models.ProductContext())
          {
            try
            {
              var myItem = (from c in _db.ShoppingCartItems where c.CartId == removeCartID && c.Product.ProductID == removeProductID select c).FirstOrDefault();
              if (myItem != null)
              {
                // Remove Item.
                _db.ShoppingCartItems.Remove(myItem);
                _db.SaveChanges();
              }
            }
            catch (Exception exp)
            {
              throw new Exception("ERROR: Unable to Remove Cart Item - " + exp.Message.ToString(), exp);
            }
          }
        }
    
        public void UpdateItem(string updateCartID, int updateProductID, int quantity)
        {
          using (var _db = new WingtipToys.Models.ProductContext())
          {
            try
            {
              var myItem = (from c in _db.ShoppingCartItems where c.CartId == updateCartID && c.Product.ProductID == updateProductID select c).FirstOrDefault();
              if (myItem != null)
              {
                myItem.Quantity = quantity;
                _db.SaveChanges();
              }
            }
            catch (Exception exp)
            {
              throw new Exception("ERROR: Unable to Update Cart Item - " + exp.Message.ToString(), exp);
            }
          }
        }
    
        public void EmptyCart()
        {
          ShoppingCartId = GetCartId();
          var cartItems = _db.ShoppingCartItems.Where(
              c => c.CartId == ShoppingCartId);
          foreach (var cartItem in cartItems)
          {
            _db.ShoppingCartItems.Remove(cartItem);
          }
          // Save changes.             
          _db.SaveChanges();
        }
    
        public int GetCount()
        {
          ShoppingCartId = GetCartId();
    
          // Get the count of each item in the cart and sum them up          
          int? count = (from cartItems in _db.ShoppingCartItems
                        where cartItems.CartId == ShoppingCartId
                        select (int?)cartItems.Quantity).Sum();
          // Return 0 if all entries are null         
          return count ?? 0;
        }
    
        public struct ShoppingCartUpdates
        {
          public int ProductId;
          public int PurchaseQuantity;
          public bool RemoveItem;
        }
    
        public void MigrateCart(string cartId, string userName)
        {
          var shoppingCart = _db.ShoppingCartItems.Where(c => c.CartId == cartId);
          foreach (CartItem item in shoppingCart)
          {
            item.CartId = userName;
          }
          HttpContext.Current.Session[CartSessionKey] = userName;
          _db.SaveChanges();
        }
      }
    }
    

Метод MigrateCart использует существующий cartId для поиска корзины пользователя. Затем код циклически просматривает все элементы корзины CartId для покупок и заменяет свойство (как указано в схеме CartItem ) именем пользователя, выполнившего вход.

Обновление подключения к базе данных

При выполнении этого руководства с помощью предварительно созданного примера приложения Wingtip Toys необходимо повторно создать базу данных членства по умолчанию. При изменении строка подключения по умолчанию база данных членства будет создана при следующем запуске приложения.

  1. Откройте файл Web.config в корне проекта.

  2. Обновите строка подключения по умолчанию, чтобы оно выглядело следующим образом:

    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=aspnet-WingtipToys;Integrated Security=True" providerName="System.Data.SqlClient" />
    

Интеграция PayPal

PayPal — это веб-платформа выставления счетов, которая принимает платежи онлайн-продавцов. Далее в этом руководстве объясняется, как интегрировать функцию Express Checkout PayPal в приложение. Express Checkout позволяет клиентам использовать PayPal для оплаты товаров, добавленных в корзину.

Создание тестовых учетных записей PayPal

Чтобы использовать среду тестирования PayPal, необходимо создать и проверить тестовую учетную запись разработчика. Вы будете использовать тестовую учетную запись разработчика для создания тестовой учетной записи покупателя и тестовой учетной записи продавца. Учетные данные тестовой учетной записи разработчика также позволят примеру приложения Wingtip Toys получить доступ к тестовой среде PayPal.

  1. В браузере перейдите на сайт тестирования для разработчиков PayPal:
    https://developer.paypal.com

  2. Если у вас нет учетной записи разработчика PayPal, создайте новую учетную запись, нажав кнопку Зарегистрироватьсяи выполнив действия по регистрации. Если у вас есть учетная запись разработчика PayPal, войдите в систему, щелкнув Войти. Вам потребуется учетная запись разработчика PayPal для тестирования примера приложения Wingtip Toys далее в этом руководстве.

  3. Если вы только что зарегистрировались для своей учетной записи разработчика PayPal, возможно, вам потребуется подтвердить свою учетную запись разработчика PayPal с помощью PayPal. Вы можете проверить свою учетную запись, выполнив действия, отправленные PayPal в вашу учетную запись электронной почты. После проверки учетной записи разработчика PayPal снова войдите на сайт тестирования для разработчиков PayPal.

  4. После входа на сайт разработчика PayPal с помощью учетной записи разработчика PayPal необходимо создать тестовую учетную запись покупателя PayPal, если у вас ее еще нет. Чтобы создать тестовую учетную запись покупателя, на сайте PayPal перейдите на вкладку Приложения и выберите учетные записи песочницы.
    Отображается страница тестовых учетных записей песочницы .

    Примечание

    Сайт разработчика PayPal уже предоставляет тестовую учетную запись продавца.

    Снимок экрана: страница тестовых учетных записей песочницы с выделенной вкладкой

  5. На странице Тестовые учетные записи песочницы щелкните Создать учетную запись.

  6. На странице Создание тестовой учетной записи выберите адрес электронной почты и пароль тестовой учетной записи покупателя.

    Примечание

    В конце этого руководства вам потребуются адреса электронной почты и пароль покупателя для тестирования примера приложения Wingtip Toys.

    Снимок экрана: страница

  7. Создайте тестовую учетную запись покупателя, нажав кнопку Создать учетную запись .
    Отобразится страница Тестовые учетные записи песочницы .

    Извлечение и оплата с помощью PayPal — учетные записи PayPal

  8. На странице Тестовые учетные записи песочницы щелкните учетную запись электронной почты посредника .
    Появятся параметры профиля и уведомления.

  9. Выберите параметр Профиль , а затем щелкните Учетные данные API , чтобы просмотреть учетные данные API для тестовой учетной записи продавца.

  10. Скопируйте учетные данные API TEST в Блокнот.

Отображаемые учетные данные классического ТЕСТОВОГО API (имя пользователя, пароль и подпись) потребуются для выполнения вызовов API из примера приложения Wingtip Toys в тестовую среду PayPal. Вы добавите учетные данные на следующем шаге.

Добавление учетных данных класса PayPal и API

Вы разместите большую часть кода PayPal в одном классе. Этот класс содержит методы, используемые для взаимодействия с PayPal. Кроме того, вы добавите учетные данные PayPal в этот класс.

  1. В примере приложения Wingtip Toys в Visual Studio щелкните правой кнопкой мыши папку Логика и выберите Добавить ->Новый элемент.
    Откроется диалоговое окно Добавление нового элемента.

  2. В разделе Visual C# в области Установленные слева выберите Код.

  3. В средней области выберите Класс. Присвойте этому новому классу имя PayPalFunctions.cs.

  4. Нажмите кнопку Добавить.
    Новый файл класса отображается в редакторе.

  5. Замените код по умолчанию на приведенный ниже:

    using System;
    using System.Collections;
    using System.Collections.Specialized;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using WingtipToys;
    using WingtipToys.Models;
    using System.Collections.Generic;
    using System.Linq;
    
    public class NVPAPICaller
    {
      //Flag that determines the PayPal environment (live or sandbox)
      private const bool bSandbox = true;
      private const string CVV2 = "CVV2";
    
      // Live strings.
      private string pEndPointURL = "https://api-3t.paypal.com/nvp";
      private string host = "www.paypal.com";
    
      // Sandbox strings.
      private string pEndPointURL_SB = "https://api-3t.sandbox.paypal.com/nvp";
      private string host_SB = "www.sandbox.paypal.com";
    
      private const string SIGNATURE = "SIGNATURE";
      private const string PWD = "PWD";
      private const string ACCT = "ACCT";
    
      //Replace <Your API Username> with your API Username
      //Replace <Your API Password> with your API Password
      //Replace <Your Signature> with your Signature
      public string APIUsername = "<Your API Username>";
      private string APIPassword = "<Your API Password>";
      private string APISignature = "<Your Signature>";
      private string Subject = "";
      private string BNCode = "PP-ECWizard";
    
      //HttpWebRequest Timeout specified in milliseconds 
      private const int Timeout = 15000;
      private static readonly string[] SECURED_NVPS = new string[] { ACCT, CVV2, SIGNATURE, PWD };
    
      public void SetCredentials(string Userid, string Pwd, string Signature)
      {
        APIUsername = Userid;
        APIPassword = Pwd;
        APISignature = Signature;
      }
    
      public bool ShortcutExpressCheckout(string amt, ref string token, ref string retMsg)
      {
        if (bSandbox)
        {
          pEndPointURL = pEndPointURL_SB;
          host = host_SB;
        }
    
        string returnURL = "https://localhost:44300/Checkout/CheckoutReview.aspx";
        string cancelURL = "https://localhost:44300/Checkout/CheckoutCancel.aspx";
    
        NVPCodec encoder = new NVPCodec();
        encoder["METHOD"] = "SetExpressCheckout";
        encoder["RETURNURL"] = returnURL;
        encoder["CANCELURL"] = cancelURL;
        encoder["BRANDNAME"] = "Wingtip Toys Sample Application";
        encoder["PAYMENTREQUEST_0_AMT"] = amt;
        encoder["PAYMENTREQUEST_0_ITEMAMT"] = amt;
        encoder["PAYMENTREQUEST_0_PAYMENTACTION"] = "Sale";
        encoder["PAYMENTREQUEST_0_CURRENCYCODE"] = "USD";
    
        // Get the Shopping Cart Products
        using (WingtipToys.Logic.ShoppingCartActions myCartOrders = new WingtipToys.Logic.ShoppingCartActions())
        {
          List<CartItem> myOrderList = myCartOrders.GetCartItems();
    
          for (int i = 0; i < myOrderList.Count; i++)
          {
            encoder["L_PAYMENTREQUEST_0_NAME" + i] = myOrderList[i].Product.ProductName.ToString();
            encoder["L_PAYMENTREQUEST_0_AMT" + i] = myOrderList[i].Product.UnitPrice.ToString();
            encoder["L_PAYMENTREQUEST_0_QTY" + i] = myOrderList[i].Quantity.ToString();
          }
        }
    
        string pStrrequestforNvp = encoder.Encode();
        string pStresponsenvp = HttpCall(pStrrequestforNvp);
    
        NVPCodec decoder = new NVPCodec();
        decoder.Decode(pStresponsenvp);
    
        string strAck = decoder["ACK"].ToLower();
        if (strAck != null && (strAck == "success" || strAck == "successwithwarning"))
        {
          token = decoder["TOKEN"];
          string ECURL = "https://" + host + "/cgi-bin/webscr?cmd=_express-checkout" + "&token=" + token;
          retMsg = ECURL;
          return true;
        }
        else
        {
          retMsg = "ErrorCode=" + decoder["L_ERRORCODE0"] + "&" +
              "Desc=" + decoder["L_SHORTMESSAGE0"] + "&" +
              "Desc2=" + decoder["L_LONGMESSAGE0"];
          return false;
        }
      }
    
      public bool GetCheckoutDetails(string token, ref string PayerID, ref NVPCodec decoder, ref string retMsg)
      {
        if (bSandbox)
        {
          pEndPointURL = pEndPointURL_SB;
        }
    
        NVPCodec encoder = new NVPCodec();
        encoder["METHOD"] = "GetExpressCheckoutDetails";
        encoder["TOKEN"] = token;
    
        string pStrrequestforNvp = encoder.Encode();
        string pStresponsenvp = HttpCall(pStrrequestforNvp);
    
        decoder = new NVPCodec();
        decoder.Decode(pStresponsenvp);
    
        string strAck = decoder["ACK"].ToLower();
        if (strAck != null && (strAck == "success" || strAck == "successwithwarning"))
        {
          PayerID = decoder["PAYERID"];
          return true;
        }
        else
        {
          retMsg = "ErrorCode=" + decoder["L_ERRORCODE0"] + "&" +
              "Desc=" + decoder["L_SHORTMESSAGE0"] + "&" +
              "Desc2=" + decoder["L_LONGMESSAGE0"];
    
          return false;
        }
      }
    
      public bool DoCheckoutPayment(string finalPaymentAmount, string token, string PayerID, ref NVPCodec decoder, ref string retMsg)
      {
        if (bSandbox)
        {
          pEndPointURL = pEndPointURL_SB;
        }
    
        NVPCodec encoder = new NVPCodec();
        encoder["METHOD"] = "DoExpressCheckoutPayment";
        encoder["TOKEN"] = token;
        encoder["PAYERID"] = PayerID;
        encoder["PAYMENTREQUEST_0_AMT"] = finalPaymentAmount;
        encoder["PAYMENTREQUEST_0_CURRENCYCODE"] = "USD";
        encoder["PAYMENTREQUEST_0_PAYMENTACTION"] = "Sale";
    
        string pStrrequestforNvp = encoder.Encode();
        string pStresponsenvp = HttpCall(pStrrequestforNvp);
    
        decoder = new NVPCodec();
        decoder.Decode(pStresponsenvp);
    
        string strAck = decoder["ACK"].ToLower();
        if (strAck != null && (strAck == "success" || strAck == "successwithwarning"))
        {
          return true;
        }
        else
        {
          retMsg = "ErrorCode=" + decoder["L_ERRORCODE0"] + "&" +
              "Desc=" + decoder["L_SHORTMESSAGE0"] + "&" +
              "Desc2=" + decoder["L_LONGMESSAGE0"];
    
          return false;
        }
      }
    
      public string HttpCall(string NvpRequest)
      {
        string url = pEndPointURL;
    
        string strPost = NvpRequest + "&" + buildCredentialsNVPString();
        strPost = strPost + "&BUTTONSOURCE=" + HttpUtility.UrlEncode(BNCode);
    
        HttpWebRequest objRequest = (HttpWebRequest)WebRequest.Create(url);
        objRequest.Timeout = Timeout;
        objRequest.Method = "POST";
        objRequest.ContentLength = strPost.Length;
    
        try
        {
          using (StreamWriter myWriter = new StreamWriter(objRequest.GetRequestStream()))
          {
            myWriter.Write(strPost);
          }
        }
        catch (Exception)
        {
          // No logging for this tutorial.
        }
    
        //Retrieve the Response returned from the NVP API call to PayPal.
        HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();
        string result;
        using (StreamReader sr = new StreamReader(objResponse.GetResponseStream()))
        {
          result = sr.ReadToEnd();
        }
    
        return result;
      }
    
      private string buildCredentialsNVPString()
      {
        NVPCodec codec = new NVPCodec();
    
        if (!IsEmpty(APIUsername))
          codec["USER"] = APIUsername;
    
        if (!IsEmpty(APIPassword))
          codec[PWD] = APIPassword;
    
        if (!IsEmpty(APISignature))
          codec[SIGNATURE] = APISignature;
    
        if (!IsEmpty(Subject))
          codec["SUBJECT"] = Subject;
    
        codec["VERSION"] = "88.0";
    
        return codec.Encode();
      }
    
      public static bool IsEmpty(string s)
      {
        return s == null || s.Trim() == string.Empty;
      }
    }
    
    public sealed class NVPCodec : NameValueCollection
    {
      private const string AMPERSAND = "&";
      private const string EQUALS = "=";
      private static readonly char[] AMPERSAND_CHAR_ARRAY = AMPERSAND.ToCharArray();
      private static readonly char[] EQUALS_CHAR_ARRAY = EQUALS.ToCharArray();
    
      public string Encode()
      {
        StringBuilder sb = new StringBuilder();
        bool firstPair = true;
        foreach (string kv in AllKeys)
        {
          string name = HttpUtility.UrlEncode(kv);
          string value = HttpUtility.UrlEncode(this[kv]);
          if (!firstPair)
          {
            sb.Append(AMPERSAND);
          }
          sb.Append(name).Append(EQUALS).Append(value);
          firstPair = false;
        }
        return sb.ToString();
      }
    
      public void Decode(string nvpstring)
      {
        Clear();
        foreach (string nvp in nvpstring.Split(AMPERSAND_CHAR_ARRAY))
        {
          string[] tokens = nvp.Split(EQUALS_CHAR_ARRAY);
          if (tokens.Length >= 2)
          {
            string name = HttpUtility.UrlDecode(tokens[0]);
            string value = HttpUtility.UrlDecode(tokens[1]);
            Add(name, value);
          }
        }
      }
    
      public void Add(string name, string value, int index)
      {
        this.Add(GetArrayName(index, name), value);
      }
    
      public void Remove(string arrayName, int index)
      {
        this.Remove(GetArrayName(index, arrayName));
      }
    
      public string this[string name, int index]
      {
        get
        {
          return this[GetArrayName(index, name)];
        }
        set
        {
          this[GetArrayName(index, name)] = value;
        }
      }
    
      private static string GetArrayName(int index, string name)
      {
        if (index < 0)
        {
          throw new ArgumentOutOfRangeException("index", "index cannot be negative : " + index);
        }
        return name + index;
      }
    }
    
  6. Добавьте учетные данные API продавца (имя пользователя, пароль и подпись), которые вы отображали ранее в этом руководстве, чтобы можно было выполнять вызовы функций в тестовую среду PayPal.

    public string APIUsername = "<Your API Username>";
    private string APIPassword = "<Your API Password>";
    private string APISignature = "<Your Signature>";
    

Примечание

В этом примере приложения вы просто добавляете учетные данные в файл C# (CS). Однако в реализованном решении следует рассмотреть возможность шифрования учетных данных в файле конфигурации.

Класс NVPAPICaller содержит большинство функций PayPal. Код в классе предоставляет методы, необходимые для выполнения тестовой покупки в тестовой среде PayPal. Для совершения покупок используются следующие три функции PayPal:

  • Функция SetExpressCheckout
  • Функция GetExpressCheckoutDetails
  • Функция DoExpressCheckoutPayment

Метод ShortcutExpressCheckout собирает сведения о тестовой покупке и сведения о продукте из корзины покупок и вызывает функцию SetExpressCheckout PayPal. Метод GetCheckoutDetails подтверждает сведения о покупке и вызывает функцию GetExpressCheckoutDetails PayPal перед выполнением тестовой покупки. Метод DoCheckoutPayment завершает тестовую покупку из тестовой среды, вызывая функцию DoExpressCheckoutPayment PayPal. Оставшийся код поддерживает методы и процессы PayPal, такие как кодирование строк, декодирование строк, обработка массивов и определение учетных данных.

Примечание

PayPal позволяет включать необязательные сведения о покупке на основе спецификации API PayPal. Расширив код в примере приложения Wingtip Toys, можно включить сведения о локализации, описания продуктов, налог, номер обслуживания клиентов, а также многие другие необязательные поля.

Обратите внимание, что в URL-адресах возврата и отмены, указанных в методе ShortcutExpressCheckout , используется номер порта.

string returnURL = "https://localhost:44300/Checkout/CheckoutReview.aspx";
       string cancelURL = "https://localhost:44300/Checkout/CheckoutCancel.aspx";

Когда Visual Web Developer запускает веб-проект с использованием SSL, обычно для веб-сервера используется порт 44300. Как показано выше, номер порта — 44300. При запуске приложения вы увидите другой номер порта. Номер порта должен быть правильно задан в коде, чтобы вы могли успешно запустить пример приложения Wingtip Toys в конце этого руководства. В следующем разделе этого руководства объясняется, как получить номер порта локального узла и обновить класс PayPal.

Обновление номера порта LocalHost в классе PayPal

Пример приложения Wingtip Toys покупает продукты, перейдя на сайт тестирования PayPal и возвращаясь к локальному экземпляру примера приложения Wingtip Toys. Чтобы PayPal вернула правильный URL-адрес, необходимо указать номер порта локально работающего примера приложения в приведенном выше коде PayPal.

  1. Щелкните правой кнопкой мыши имя проекта (WingtipToys) в Обозреватель решений и выберите Свойства.

  2. В левом столбце выберите вкладку Интернет .

  3. Получите номер порта из поля Url-адрес проекта .

  4. При необходимости обновите returnURL и cancelURL в классе PayPal (NVPAPICaller) в файле PayPalFunctions.cs , чтобы использовать номер порта веб-приложения:

    string returnURL = "https://localhost:<Your Port Number>/Checkout/CheckoutReview.aspx";
    string cancelURL = "https://localhost:<Your Port Number>/Checkout/CheckoutCancel.aspx";
    

Теперь добавленный код будет соответствовать ожидаемому порту для локального веб-приложения. PayPal сможет вернуться к правильному URL-адресу на локальном компьютере.

Добавление кнопки оформления заказа PayPal

Теперь, когда основные функции PayPal добавлены в пример приложения, можно приступить к добавлению разметки и кода, необходимых для вызова этих функций. Сначала необходимо добавить кнопку оформления заказа, которую пользователь увидит на странице корзины.

  1. Откройте файл ShoppingCart.aspx .

  2. Прокрутите файл вниз и найдите <!--Checkout Placeholder --> комментарий.

  3. Замените комментарий элементом ImageButton управления , чтобы разметка была заменена следующим образом:

    <asp:ImageButton ID="CheckoutImageBtn" runat="server" 
                          ImageUrl="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif" 
                          Width="145" AlternateText="Check out with PayPal" 
                          OnClick="CheckoutBtn_Click" 
                          BackColor="Transparent" BorderWidth="0" />
    
  4. В файле ShoppingCart.aspx.cs после обработчика UpdateBtn_Click событий в конце файла добавьте CheckOutBtn_Click обработчик событий:

    protected void CheckoutBtn_Click(object sender, ImageClickEventArgs e)
    {
        using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
        {
            Session["payment_amt"] = usersShoppingCart.GetTotal();
        }
        Response.Redirect("Checkout/CheckoutStart.aspx");
    }
    
  5. Кроме того, в файле ShoppingCart.aspx.cs добавьте ссылку CheckoutBtnна , чтобы кнопка "Создать изображение" была указана следующим образом:

    protected void Page_Load(object sender, EventArgs e)
    {
        using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
        {
            decimal cartTotal = 0;
            cartTotal = usersShoppingCart.GetTotal();
            if (cartTotal > 0)
            {
                // Display Total.
                lblTotal.Text = String.Format("{0:c}", cartTotal);
            }
            else
            {
                LabelTotalText.Text = "";
                lblTotal.Text = "";
                ShoppingCartTitle.InnerText = "Shopping Cart is Empty";
                UpdateBtn.Visible = false;
                CheckoutImageBtn.Visible = false;
            }
        }
    }
    
  6. Сохраните изменения в файлах ShoppingCart.aspx и ShoppingCart.aspx.cs .

  7. В меню выберите Debug-Build>WingtipToys.
    Проект будет перестроен с помощью добавленного элемента управления ImageButton .

Отправка сведений о покупке в PayPal

Когда пользователь нажимает кнопку Оформления заказа на странице корзины (ShoppingCart.aspx), он начнет процесс покупки. Следующий код вызывает первую функцию PayPal, необходимую для покупки продуктов.

  1. В папке Checkout откройте файл кода программной части с именем CheckoutStart.aspx.cs.
    Не забудьте открыть файл кода программной части.

  2. Замените существующий код следующим кодом:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace WingtipToys.Checkout
    {
        public partial class CheckoutStart : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                NVPAPICaller payPalCaller = new NVPAPICaller();
                string retMsg = "";
                string token = "";
    
                if (Session["payment_amt"] != null)
                {
                    string amt = Session["payment_amt"].ToString();
    
                    bool ret = payPalCaller.ShortcutExpressCheckout(amt, ref token, ref retMsg);
                    if (ret)
                    {
                        Session["token"] = token;
                        Response.Redirect(retMsg);
                    }
                    else
                    {
                        Response.Redirect("CheckoutError.aspx?" + retMsg);
                    }
                }
                else
                {
                    Response.Redirect("CheckoutError.aspx?ErrorCode=AmtMissing");
                }
            }
        }
    }
    

Когда пользователь приложения нажимает кнопку Оформления заказа на странице корзины, браузер перейдет на страницу CheckoutStart.aspx . При загрузке ShortcutExpressCheckout страницы CheckoutStart.aspx вызывается метод . На этом этапе пользователь переходит на веб-сайт тестирования PayPal. На сайте PayPal пользователь вводит свои учетные данные PayPal, просматривает сведения о покупке, принимает соглашение PayPal и возвращается в пример приложения Wingtip Toys, где ShortcutExpressCheckout метод завершается. ShortcutExpressCheckout После завершения работы метод перенаправит пользователя на страницу CheckoutReview.aspx, указанную в методе ShortcutExpressCheckout . Это позволяет пользователю просматривать сведения о заказе из примера приложения Wingtip Toys.

Просмотр сведений о заказе

После возвращения из PayPal на странице CheckoutReview.aspx примера приложения Wingtip Toys отображаются сведения о заказе. Эта страница позволяет пользователю просматривать сведения о заказе перед покупкой продуктов. Страница CheckoutReview.aspx должна быть создана следующим образом:

  1. В папке Checkout откройте страницу с именем CheckoutReview.aspx.

  2. Замените существующую разметку следующей:

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="CheckoutReview.aspx.cs" Inherits="WingtipToys.Checkout.CheckoutReview" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <h1>Order Review</h1>
        <p></p>
        <h3 style="padding-left: 33px">Products:</h3>
        <asp:GridView ID="OrderItemList" runat="server" AutoGenerateColumns="False" GridLines="Both" CellPadding="10" Width="500" BorderColor="#efeeef" BorderWidth="33">              
            <Columns>
                <asp:BoundField DataField="ProductId" HeaderText=" Product ID" />        
                <asp:BoundField DataField="Product.ProductName" HeaderText=" Product Name" />        
                <asp:BoundField DataField="Product.UnitPrice" HeaderText="Price (each)" DataFormatString="{0:c}"/>     
                <asp:BoundField DataField="Quantity" HeaderText="Quantity" />        
            </Columns>    
        </asp:GridView>
        <asp:DetailsView ID="ShipInfo" runat="server" AutoGenerateRows="false" GridLines="None" CellPadding="10" BorderStyle="None" CommandRowStyle-BorderStyle="None">
            <Fields>
            <asp:TemplateField>
                <ItemTemplate>
                    <h3>Shipping Address:</h3>
                    <br />
                    <asp:Label ID="FirstName" runat="server" Text='<%#: Eval("FirstName") %>'></asp:Label>  
                    <asp:Label ID="LastName" runat="server" Text='<%#: Eval("LastName") %>'></asp:Label>
                    <br />
                    <asp:Label ID="Address" runat="server" Text='<%#: Eval("Address") %>'></asp:Label>
                    <br />
                    <asp:Label ID="City" runat="server" Text='<%#: Eval("City") %>'></asp:Label>
                    <asp:Label ID="State" runat="server" Text='<%#: Eval("State") %>'></asp:Label>
                    <asp:Label ID="PostalCode" runat="server" Text='<%#: Eval("PostalCode") %>'></asp:Label>
                    <p></p>
                    <h3>Order Total:</h3>
                    <br />
                    <asp:Label ID="Total" runat="server" Text='<%#: Eval("Total", "{0:C}") %>'></asp:Label>
                </ItemTemplate>
                <ItemStyle HorizontalAlign="Left" />
            </asp:TemplateField>
              </Fields>
        </asp:DetailsView>
        <p></p>
        <hr />
        <asp:Button ID="CheckoutConfirm" runat="server" Text="Complete Order" OnClick="CheckoutConfirm_Click" />
    </asp:Content>
    
  3. Откройте страницу кода программной части с именем CheckoutReview.aspx.cs и замените существующий код следующим:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using WingtipToys.Models;
    
    namespace WingtipToys.Checkout
    {
      public partial class CheckoutReview : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
          if (!IsPostBack)
          {
            NVPAPICaller payPalCaller = new NVPAPICaller();
    
            string retMsg = "";
            string token = "";
            string PayerID = "";
            NVPCodec decoder = new NVPCodec();
            token = Session["token"].ToString();
    
            bool ret = payPalCaller.GetCheckoutDetails(token, ref PayerID, ref decoder, ref retMsg);
            if (ret)
            {
              Session["payerId"] = PayerID;
    
              var myOrder = new Order();
              myOrder.OrderDate = Convert.ToDateTime(decoder["TIMESTAMP"].ToString());
              myOrder.Username = User.Identity.Name;
              myOrder.FirstName = decoder["FIRSTNAME"].ToString();
              myOrder.LastName = decoder["LASTNAME"].ToString();
              myOrder.Address = decoder["SHIPTOSTREET"].ToString();
              myOrder.City = decoder["SHIPTOCITY"].ToString();
              myOrder.State = decoder["SHIPTOSTATE"].ToString();
              myOrder.PostalCode = decoder["SHIPTOZIP"].ToString();
              myOrder.Country = decoder["SHIPTOCOUNTRYCODE"].ToString();
              myOrder.Email = decoder["EMAIL"].ToString();
              myOrder.Total = Convert.ToDecimal(decoder["AMT"].ToString());
    
              // Verify total payment amount as set on CheckoutStart.aspx.
              try
              {
                decimal paymentAmountOnCheckout = Convert.ToDecimal(Session["payment_amt"].ToString());
                decimal paymentAmoutFromPayPal = Convert.ToDecimal(decoder["AMT"].ToString());
                if (paymentAmountOnCheckout != paymentAmoutFromPayPal)
                {
                  Response.Redirect("CheckoutError.aspx?" + "Desc=Amount%20total%20mismatch.");
                }
              }
              catch (Exception)
              {
                Response.Redirect("CheckoutError.aspx?" + "Desc=Amount%20total%20mismatch.");
              }
    
              // Get DB context.
              ProductContext _db = new ProductContext();
    
              // Add order to DB.
              _db.Orders.Add(myOrder);
              _db.SaveChanges();
    
              // Get the shopping cart items and process them.
              using (WingtipToys.Logic.ShoppingCartActions usersShoppingCart = new WingtipToys.Logic.ShoppingCartActions())
              {
                List<CartItem> myOrderList = usersShoppingCart.GetCartItems();
    
                // Add OrderDetail information to the DB for each product purchased.
                for (int i = 0; i < myOrderList.Count; i++)
                {
                  // Create a new OrderDetail object.
                  var myOrderDetail = new OrderDetail();
                  myOrderDetail.OrderId = myOrder.OrderId;
                  myOrderDetail.Username = User.Identity.Name;
                  myOrderDetail.ProductId = myOrderList[i].ProductId;
                  myOrderDetail.Quantity = myOrderList[i].Quantity;
                  myOrderDetail.UnitPrice = myOrderList[i].Product.UnitPrice;
    
                  // Add OrderDetail to DB.
                  _db.OrderDetails.Add(myOrderDetail);
                  _db.SaveChanges();
                }
    
                // Set OrderId.
                Session["currentOrderId"] = myOrder.OrderId;
    
                // Display Order information.
                List<Order> orderList = new List<Order>();
                orderList.Add(myOrder);
                ShipInfo.DataSource = orderList;
                ShipInfo.DataBind();
    
                // Display OrderDetails.
                OrderItemList.DataSource = myOrderList;
                OrderItemList.DataBind();
              }
            }
            else
            {
              Response.Redirect("CheckoutError.aspx?" + retMsg);
            }
          }
        }
    
        protected void CheckoutConfirm_Click(object sender, EventArgs e)
        {
          Session["userCheckoutCompleted"] = "true";
          Response.Redirect("~/Checkout/CheckoutComplete.aspx");
        }
      }
    }
    

Элемент управления DetailsView используется для отображения сведений о заказах, возвращенных из PayPal. Кроме того, приведенный выше код сохраняет сведения о заказе в базе данных Wingtip Toys в виде OrderDetail объекта . Когда пользователь нажимает кнопку Завершить заказ , он перенаправляется на страницу CheckoutComplete.aspx .

Примечание

Совет

Обратите внимание, что <ItemStyle> в разметке страницы CheckoutReview.aspx тег используется для изменения стиля элементов элемента управления DetailsView в нижней части страницы. Просмотр страницы в режиме конструктора (выбрав Конструктор в левом нижнем углу Visual Studio), а затем выбрав элемент управления DetailsView и смарт-тег (значок со стрелкой в правом верхнем углу элемента управления), вы сможете увидеть сведенияПросмотр задач.

Оформления заказа и оплаты с помощью PayPal — изменение полей

При нажатии кнопки Изменить поля откроется диалоговое окно Поля . В этом диалоговом окне можно легко управлять визуальными свойствами элемента управления DetailsView, например ItemStyle.

Диалоговое окно

Завершить покупку

На странице CheckoutComplete.aspx выполняется покупка в PayPal. Как упоминалось выше, пользователь должен нажать кнопку Завершить заказ , прежде чем приложение перейдет на страницу CheckoutComplete.aspx .

  1. В папке Checkout откройте страницу с именем CheckoutComplete.aspx.

  2. Замените существующую разметку следующей:

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="CheckoutComplete.aspx.cs" Inherits="WingtipToys.Checkout.CheckoutComplete" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <h1>Checkout Complete</h1>
        <p></p>
        <h3>Payment Transaction ID:</h3> <asp:Label ID="TransactionId" runat="server"></asp:Label>
        <p></p>
        <h3>Thank You!</h3>
        <p></p>
        <hr />
        <asp:Button ID="Continue" runat="server" Text="Continue Shopping" OnClick="Continue_Click" />
    </asp:Content>
    
  3. Откройте страницу кода программной части с именем CheckoutComplete.aspx.cs и замените существующий код следующим:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using WingtipToys.Models;
    
    namespace WingtipToys.Checkout
    {
      public partial class CheckoutComplete : System.Web.UI.Page
      {
        protected void Page_Load(object sender, EventArgs e)
        {
          if (!IsPostBack)
          {
            // Verify user has completed the checkout process.
            if ((string)Session["userCheckoutCompleted"] != "true")
            {
              Session["userCheckoutCompleted"] = string.Empty;
              Response.Redirect("CheckoutError.aspx?" + "Desc=Unvalidated%20Checkout.");
            }
    
            NVPAPICaller payPalCaller = new NVPAPICaller();
    
            string retMsg = "";
            string token = "";
            string finalPaymentAmount = "";
            string PayerID = "";
            NVPCodec decoder = new NVPCodec();
    
            token = Session["token"].ToString();
            PayerID = Session["payerId"].ToString();
            finalPaymentAmount = Session["payment_amt"].ToString();
    
            bool ret = payPalCaller.DoCheckoutPayment(finalPaymentAmount, token, PayerID, ref decoder, ref retMsg);
            if (ret)
            {
              // Retrieve PayPal confirmation value.
              string PaymentConfirmation = decoder["PAYMENTINFO_0_TRANSACTIONID"].ToString();
              TransactionId.Text = PaymentConfirmation;
    
              ProductContext _db = new ProductContext();
              // Get the current order id.
              int currentOrderId = -1;
              if (Session["currentOrderId"] != string.Empty)
              {
                currentOrderId = Convert.ToInt32(Session["currentOrderID"]);
              }
              Order myCurrentOrder;
              if (currentOrderId >= 0)
              {
                // Get the order based on order id.
                myCurrentOrder = _db.Orders.Single(o => o.OrderId == currentOrderId);
                // Update the order to reflect payment has been completed.
                myCurrentOrder.PaymentTransactionId = PaymentConfirmation;
                // Save to DB.
                _db.SaveChanges();
              }
    
              // Clear shopping cart.
              using (WingtipToys.Logic.ShoppingCartActions usersShoppingCart =
                  new WingtipToys.Logic.ShoppingCartActions())
              {
                usersShoppingCart.EmptyCart();
              }
    
              // Clear order id.
              Session["currentOrderId"] = string.Empty;
            }
            else
            {
              Response.Redirect("CheckoutError.aspx?" + retMsg);
            }
          }
        }
    
        protected void Continue_Click(object sender, EventArgs e)
        {
          Response.Redirect("~/Default.aspx");
        }
      }
    }
    

При загрузке DoCheckoutPayment страницы CheckoutComplete.aspx вызывается метод . Как упоминалось ранее, DoCheckoutPayment метод завершает покупку в тестовой среде PayPal. После того как PayPal завершит покупку заказа, на странице CheckoutComplete.aspx отображается платежная транзакция ID для покупателя.

Обработка отмены покупки

Если пользователь решит отменить покупку, он будет перенаправлен на страницу CheckoutCancel.aspx , где он увидит, что его заказ был отменен.

  1. Откройте страницу с именем CheckoutCancel.aspx в папке Checkout .

  2. Замените существующую разметку следующей:

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="CheckoutCancel.aspx.cs" Inherits="WingtipToys.Checkout.CheckoutCancel" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <h1>Checkout Cancelled</h1>
        <p></p>
        <h3>Your purchase has been cancelled.</h3>
    </asp:Content>
    

Обработка ошибок при покупке

Ошибки во время покупки будут обрабатываться страницей CheckoutError.aspx . Код программной части страницы CheckoutStart.aspx , страницы CheckoutReview.aspx и страницы CheckoutComplete.aspx будут перенаправлены на страницу CheckoutError.aspx в случае возникновения ошибки.

  1. Откройте страницу с именем CheckoutError.aspx в папке Checkout .

  2. Замените существующую разметку следующей:

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="CheckoutError.aspx.cs" Inherits="WingtipToys.Checkout.CheckoutError" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        <h1>Checkout Error</h1>
        <p></p>
    <table id="ErrorTable">
        <tr>
            <td class="field"></td>
            <td><%=Request.QueryString.Get("ErrorCode")%></td>
        </tr>
        <tr>
            <td class="field"></td>
            <td><%=Request.QueryString.Get("Desc")%></td>
        </tr>
        <tr>
            <td class="field"></td>
            <td><%=Request.QueryString.Get("Desc2")%></td>
        </tr>
    </table>
        <p></p>
    </asp:Content>
    

Страница CheckoutError.aspx отображается с подробными сведениями об ошибке при возникновении ошибки во время оформления заказа.

Запуск приложения

Запустите приложение, чтобы узнать, как приобрести продукты. Обратите внимание, что вы будете работать в тестовой среде PayPal. Фактические деньги не обмениваются.

  1. Убедитесь, что все файлы сохранены в Visual Studio.

  2. Откройте веб-браузер и перейдите по адресу https://developer.paypal.com.

  3. Войдите с помощью учетной записи разработчика PayPal, созданной ранее в этом руководстве.
    Для песочницы разработчика PayPal необходимо войти в https://developer.paypal.com систему, чтобы протестировать экспресс-оформления заказа. Это относится только к тестированию в песочнице PayPal, а не к активной среде PayPal.

  4. В Visual Studio нажмите клавишу F5 , чтобы запустить пример приложения Wingtip Toys.
    После перестроения базы данных откроется браузер и отобразится страница Default.aspx .

  5. Добавьте три разных продукта в корзину, выбрав категорию продуктов, например "Автомобили", а затем нажмите кнопку Добавить в корзину рядом с каждым продуктом.
    В корзине будет отображаться выбранный продукт.

  6. Нажмите кнопку PayPal для оформления заказа.

    Оформления заказа и оплаты с помощью PayPal — корзина

    При извлечении потребуется учетная запись пользователя для примера приложения Wingtip Toys.

  7. Щелкните ссылку Google в правой части страницы, чтобы войти с помощью существующей учетной записи электронной почты gmail.com.
    Если у вас нет учетной записи gmail.com, ее можно создать для тестирования в www.gmail.com. Вы также можете использовать стандартную локальную учетную запись, нажав кнопку "Зарегистрировать".

    Регистрация и оплата с помощью PayPal — вход

  8. Войдите с помощью учетной записи Gmail и пароля.

    Регистрация и оплата с помощью PayPal — вход в Gmail

  9. Нажмите кнопку Войти, чтобы зарегистрировать учетную запись Gmail с помощью имени пользователя примера приложения Wingtip Toys.

    Оформления заказа и оплаты с помощью PayPal — регистрация учетной записи

  10. На тестовом сайте PayPal добавьте адрес электронной почты покупателя и пароль, созданные ранее в этом руководстве, а затем нажмите кнопку Войти .

    Регистрация и оплата с помощью PayPal — вход в PayPal

  11. Примите политику PayPal и нажмите кнопку Принять и продолжить .
    Обратите внимание, что эта страница отображается только при первом использовании этой учетной записи PayPal. Еще раз обратите внимание, что это тестовый счет, реальные деньги не обмениваются.

    Оплата и оплата с помощью PayPal — политика PayPal

  12. Просмотрите сведения о заказе на странице проверки тестовой среды PayPal и нажмите кнопку Продолжить.

    Оформления заказа и оплаты с помощью PayPal — просмотр сведений

  13. На странице CheckoutReview.aspx проверьте сумму заказа и просмотрите созданный адрес доставки. Затем нажмите кнопку Завершить заказ .

    Оформления заказа и оплата с помощью PayPal — проверка заказа

  14. Страница CheckoutComplete.aspx отображается с идентификатором транзакции платежа.

    Оформления заказа и оплата с помощью PayPal — завершение оформления заказа

Проверка базы данных

Просмотрев обновленные данные в базе данных примера приложения Wingtip Toys после запуска приложения, можно увидеть, что приложение успешно записало покупку продуктов.

Данные, содержащиеся в файле базы данных Wingtiptoys.mdf, можно проверить с помощью окна Обозреватель базы данных (окно server Обозреватель в Visual Studio), как это было ранее в этой серии руководств.

  1. Закройте окно браузера, если оно все еще открыто.

  2. В Visual Studio щелкните значок Показать все файлы в верхней части Обозреватель решений, чтобы можно было развернуть папку App_Data.

  3. Разверните папку App_Data .
    Может потребоваться щелкнуть значок Показать все файлы для папки.

  4. Щелкните правой кнопкой мыши файл базы данных Wingtiptoys.mdf и выберите Открыть.
    Отобразится Обозреватель сервера.

  5. Разверните папку Таблицы.

  6. Щелкните правой кнопкой мыши таблицу Ordersи выберите Показать данные таблицы.
    Отобразится таблица "Заказы ".

  7. Проверьте столбец PaymentTransactionID , чтобы подтвердить успешные транзакции.

    Оформления заказа и оплаты с помощью PayPal — проверка базы данных

  8. Закройте окно таблицы Заказы .

  9. В Обозреватель сервера щелкните правой кнопкой мыши таблицу OrderDetails и выберите Показать данные таблицы.

  10. Просмотрите OrderId значения и Username в таблице OrderDetails . Обратите внимание, что эти значения соответствуют значениям OrderId и Username , включенным в таблицу Orders .

  11. Закройте окно таблицы OrderDetails .

  12. Щелкните правой кнопкой мыши файл базы данных Wingtip Toys (Wingtiptoys.mdf) и выберите Закрыть подключение.

  13. Если окно Обозреватель решений не отображается, щелкните Обозреватель решений в нижней части окна Обозреватель сервера, чтобы снова отобразить Обозреватель решений.

Сводка

В этом руководстве вы добавили схемы сведений о заказах и заказах для отслеживания покупки продуктов. Вы также интегрировали функции PayPal в пример приложения Wingtip Toys.

Дополнительные ресурсы

Общие сведения о конфигурации ASP.NET
Развертывание приложения secure ASP.NET Web Forms с членством, OAuth и База данных SQL в Служба приложений Azure
Microsoft Azure — бесплатная пробная версия

Отказ от ответственности

Этот учебник содержит пример кода. Такой пример кода предоставляется "как есть" без каких-либо гарантий. Соответственно, корпорация Майкрософт не гарантирует точность, целостность или качество примера кода. Вы соглашаетесь использовать пример кода на свой страх и риск. Корпорация Майкрософт ни при каких обстоятельствах не несет никакой ответственности перед вами за любой пример кода, содержимого, включая, помимо прочего, ошибки или упущения в любом образце кода, содержимом, а также за любые потери или ущерб любого рода, понесенные в результате использования любого примера кода. Настоящим вы уведомлены и настоящим соглашаетесь возместить, сохранить и обезопасить Корпорацию Майкрософт от любых убытков, претензий в связи с потерей, ущербом или ущербом любого рода, включая, помимо прочего, те, которые были вызваны или вытекающие из материалов, которые вы публикуете, передаете, используете или на которые вы полагаетесь, включая, но не ограничиваясь, изложенные в них мнения.