Finalizacja zakupu i płatność w systemie PayPal

Autor: Erik Reitan

Pobierz przykładowy projekt Wingtip Toys (C#) lub pobierz książkę elektroniczną (PDF)

Ta seria samouczków zawiera podstawowe informacje dotyczące tworzenia aplikacji ASP.NET Web Forms przy użyciu ASP.NET 4.5 i Microsoft Visual Studio Express 2013 for Web. Dostępny jest projekt Visual Studio 2013 z kodem źródłowym języka C#, który towarzyszy tej serii samouczków.

W tym samouczku opisano sposób modyfikowania przykładowej aplikacji Wingtip Toys w celu uwzględnienia autoryzacji użytkownika, rejestracji i płatności przy użyciu usługi PayPal. Tylko użytkownicy, którzy są zalogowani, będą mieli autoryzację do zakupu produktów. Wbudowana funkcja rejestracji użytkowników szablonu projektu ASP.NET 4.5 Web Forms zawiera już wiele potrzebnych elementów. Dodasz funkcję payPal Express Checkout. W tym samouczku używasz środowiska testowego dla deweloperów usługi PayPal, więc nie zostaną przeniesione żadne rzeczywiste fundusze. Na końcu samouczka przetestujesz aplikację, wybierając produkty do dodania do koszyka zakupów, klikając przycisk wyewidencjonowania i przesyłając dane do witryny internetowej testowania usługi PayPal. W witrynie internetowej z testowaniem usługi PayPal potwierdzisz informacje o wysyłki i płatności, a następnie wrócisz do lokalnej aplikacji przykładowej Wingtip Toys, aby potwierdzić i ukończyć zakup.

Istnieje kilka doświadczonych podmiotów przetwarzających płatności innych firm, które specjalizują się w zakupach online, które dotyczą skalowalności i bezpieczeństwa. ASP.NET deweloperzy powinni rozważyć zalety korzystania z rozwiązania płatniczego innej firmy przed wdrożeniem rozwiązania zakupów i zakupów.

Uwaga

Przykładowa aplikacja Wingtip Toys została zaprojektowana tak, aby przedstawiała konkretne pojęcia i funkcje ASP.NET dostępne dla deweloperów ASP.NET sieci Web. Ta przykładowa aplikacja nie została zoptymalizowana pod kątem wszystkich możliwych okoliczności w odniesieniu do skalowalności i zabezpieczeń.

Zawartość:

  • Jak ograniczyć dostęp do określonych stron w folderze.
  • Jak utworzyć znany koszyk na podstawie anonimowego koszyka zakupowego.
  • Jak włączyć protokół SSL dla projektu.
  • Jak dodać dostawcę OAuth do projektu.
  • Jak używać usługi PayPal do zakupu produktów przy użyciu środowiska testowego PayPal.
  • Jak wyświetlić szczegóły z usługi PayPal w kontrolce DetailsView .
  • Jak zaktualizować bazę danych aplikacji Wingtip Toys przy użyciu szczegółów uzyskanych z usługi PayPal.

Dodawanie śledzenia zamówień

W tym samouczku utworzysz dwie nowe klasy do śledzenia danych z kolejności utworzenia przez użytkownika. Klasy będą śledzić dane dotyczące informacji o wysyłki, łącznej wartości zakupu i potwierdzenia płatności.

Dodawanie klas modelu Order i OrderDetail

Wcześniej w tej serii samouczków zdefiniowano schemat kategorii, produktów i elementów koszyka zakupów, tworząc Categoryklasy , Producti CartItem w folderze Models . Teraz dodasz dwie nowe klasy, aby zdefiniować schemat zamówienia produktu i szczegóły zamówienia.

  1. W folderze Models dodaj nową klasę o nazwie Order.cs.
    Nowy plik klasy jest wyświetlany w edytorze.

  2. Zastąp domyślny kod następującym kodem:

    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. Dodaj klasę OrderDetail.cs do folderu Models .

  4. Zastąp kod domyślny następującym kodem:

    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; }
    
        }
    }
    

Klasy Order i OrderDetail zawierają schemat służący do definiowania informacji o zamówieniu używanych do zakupu i wysyłki.

Ponadto należy zaktualizować klasę kontekstu bazy danych, która zarządza klasami jednostek i która zapewnia dostęp do danych do bazy danych. W tym celu dodasz nowo utworzone klasy Order i OrderDetail model do ProductContext klasy.

  1. W Eksplorator rozwiązań znajdź i otwórz plik ProductContext.cs.

  2. Dodaj wyróżniony kod do pliku ProductContext.cs , jak pokazano poniżej:

    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; }
      }
    }
    

Jak wspomniano wcześniej w tej serii samouczków, kod w pliku ProductContext.cs dodaje System.Data.Entity przestrzeń nazw, aby mieć dostęp do wszystkich podstawowych funkcji programu Entity Framework. Ta funkcja obejmuje możliwość wykonywania zapytań, wstawiania, aktualizowania i usuwania danych przez pracę z obiektami silnie typizowanym. Powyższy kod w ProductContext klasie dodaje dostęp do programu Entity Framework do nowo dodanych Order klas i OrderDetail .

Dodawanie dostępu do wyewidencjonowania

Przykładowa aplikacja Wingtip Toys umożliwia anonimowym użytkownikom przeglądanie i dodawanie produktów do koszyka. Jednak gdy anonimowi użytkownicy zdecydują się na zakup produktów dodanych do koszyka, muszą zalogować się do witryny. Po zalogowaniu użytkownicy mogą uzyskiwać dostęp do ograniczonych stron aplikacji internetowej obsługującej proces wyewidencjonowania i zakupu. Te strony z ograniczeniami znajdują się w folderze Wyewidencjonuj aplikację.

Dodawanie folderu i stron wyewidencjonowania

Teraz utworzysz folder wyewidencjonowania i strony, które klient zobaczy podczas procesu wyewidencjonowania. Te strony zostaną zaktualizowane w dalszej części tego samouczka.

  1. Kliknij prawym przyciskiem myszy nazwę projektu (Wingtip Toys) w Eksplorator rozwiązań i wybierz pozycję Dodaj nowy folder.

    Wyewidencjonuj i płatność za pomocą usługi PayPal — nowy folder

  2. Nazwij nowy folder Wyewidencjonuj.

  3. Kliknij prawym przyciskiem myszy folder Wyewidencjonuj, a następnie wybierz polecenie Dodaj nowy>element.

    Wyewidencjonuj i płatność za pomocą usługi PayPal — nowy element

  4. Zostanie wyświetlone okno dialogowe Dodaj nowy element.

  5. Wybierz grupę Visual C# ->Web templates po lewej stronie. Następnie w środkowym okienku wybierz pozycję Formularz internetowy ze stroną wzorcowąi nadaj jej nazwę CheckoutStart.aspx.

    Wyewidencjonuj i płatność za pomocą usługi PayPal — okno dialogowe Dodawanie nowego elementu

  6. Tak jak poprzednio, wybierz plik Site.Master jako stronę wzorcową.

  7. Dodaj następujące dodatkowe strony do folderu Wyewidencjonuj , wykonując te same kroki powyżej:

    • CheckoutReview.aspx
    • CheckoutComplete.aspx
    • WyewidencjonowanieCancel.aspx
    • CheckoutError.aspx

Dodawanie pliku Web.config

Dodając nowy plik Web.config do folderu wyewidencjonowania , będzie można ograniczyć dostęp do wszystkich stron zawartych w folderze.

  1. Kliknij prawym przyciskiem myszy folder Wyewidencjonuj i wybierz polecenie Dodaj ->Nowy element.
    Zostanie wyświetlone okno dialogowe Dodaj nowy element.

  2. Wybierz grupę Visual C# ->Web templates po lewej stronie. Następnie w środkowym okienku wybierz pozycję Plik konfiguracji sieci Web, zaakceptuj domyślną nazwę Web.config, a następnie wybierz pozycję Dodaj.

  3. Zastąp istniejącą zawartość XML w pliku Web.config następującym kodem:

    <?xml version="1.0"?>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?"/>
        </authorization>
      </system.web>
    </configuration>
    
  4. Zapisz plik Web.config .

Plik Web.config określa, że wszyscy nieznani użytkownicy aplikacji sieci Web muszą odmówić dostępu do stron zawartych w folderze wyewidencjonowania . Jeśli jednak użytkownik zarejestrował konto i jest zalogowany, będzie znany użytkownik i będzie miał dostęp do stron w folderze wyewidencjonowania .

Należy pamiętać, że ASP.NET konfiguracja jest zgodna z hierarchią, w której każdy plik Web.config stosuje ustawienia konfiguracji do folderu, w którym znajduje się i do wszystkich katalogów podrzędnych poniżej.

Włączanie protokołu SSL dla projektu

Secure Sockets Layer (SSL) to protokół zdefiniowany w celu umożliwienia serwerom sieci Web i klientom internetowym bezpieczniejszego komunikowania się przy użyciu szyfrowania. Jeśli protokół SSL nie jest używany, dane wysyłane między klientem a serwerem są otwarte w celu wąchania pakietów przez wszystkich osób z fizycznym dostępem do sieci. Ponadto kilka typowych schematów uwierzytelniania nie jest bezpiecznych za pośrednictwem zwykłego protokołu HTTP. W szczególności uwierzytelnianie podstawowe i uwierzytelnianie formularzy wysyłają niezaszyfrowane poświadczenia. Aby zapewnić bezpieczeństwo, te schematy uwierzytelniania muszą używać protokołu SSL.

  1. W Eksplorator rozwiązań kliknij projekt WingtipToys, a następnie naciśnij klawisz F4, aby wyświetlić okno Właściwości.
  2. Zmień wartość protokołu SSL włączone na true.
  3. Skopiuj adres URL PROTOKOŁU SSL , aby można było go później użyć.
    Adres URL protokołu SSL będzie mieć wartość https://localhost:44300/ , chyba że wcześniej utworzono witryny sieci Web SSL (jak pokazano poniżej).
    Właściwości projektu
  4. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt WingtipToys, a następnie kliknij pozycję Właściwości.
  5. Na lewej karcie kliknij pozycję Sieć Web.
  6. Zmień adres URL projektu , aby użyć zapisanego wcześniej adresu URL protokołu SSL .
    Właściwości sieci Web projektu
  7. Zapisz stronę, naciskając klawisze CTRL+S.
  8. Naciśnij klawisze Ctrl+F5 , aby uruchomić aplikację. W programie Visual Studio zostanie wyświetlona opcja umożliwiająca uniknięcie ostrzeżeń PROTOKOŁU SSL.
  9. Kliknij przycisk Tak, aby zaufać certyfikatowi SSL IIS Express i kontynuować.
    szczegóły certyfikatu SSL IIS Express
    Zostanie wyświetlone ostrzeżenie o zabezpieczeniach.
  10. Kliknij przycisk Tak , aby zainstalować certyfikat na hoście lokalnym.
    Okno dialogowe Ostrzeżenie o zabezpieczeniach
    Zostanie wyświetlone okno przeglądarki.

Teraz możesz łatwo przetestować aplikację internetową lokalnie przy użyciu protokołu SSL.

Dodawanie dostawcy OAuth 2.0

ASP.NET Web Forms oferuje rozszerzone opcje członkostwa i uwierzytelniania. Te ulepszenia obejmują uwierzytelnianie OAuth. OAuth to otwarty protokół, który umożliwia bezpieczną autoryzację w prostej i standardowej metodzie z aplikacji internetowych, mobilnych i klasycznych. Szablon ASP.NET Web Forms używa protokołu OAuth do ujawniania Facebook, Twitter, Google i Microsoft jako dostawców uwierzytelniania. Mimo że ten samouczek używa tylko firmy Google jako dostawcy uwierzytelniania, można łatwo zmodyfikować kod, aby użyć dowolnego dostawcy. Kroki implementacji innych dostawców są bardzo podobne do kroków, które zostaną wyświetlone w tym samouczku.

Oprócz uwierzytelniania samouczek będzie również używać ról do implementowania autoryzacji. Tylko ci użytkownicy dodani do canEdit roli będą mogli zmieniać dane (tworzyć, edytować lub usuwać kontakty).

Uwaga

Aplikacje systemu Windows Live akceptują tylko adres URL na żywo dla działającej witryny internetowej, więc nie można użyć lokalnego adresu URL witryny internetowej do testowania identyfikatorów logowania.

Poniższe kroki umożliwią dodanie dostawcy uwierzytelniania Google.

  1. Otwórz plik App_Start\Startup.Auth.cs .

  2. Usuń znaki komentarza app.UseGoogleAuthentication() z metody, aby metoda pojawiła się w następujący sposób:

    app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
    {
        ClientId = "",
        ClientSecret = ""
    });
    
  3. Przejdź do konsoli Google Developers. Musisz również zalogować się przy użyciu konta e-mail dewelopera Google (gmail.com). Jeśli nie masz konta Google, wybierz link Utwórz konto .
    Następnie zobaczysz konsolę Google Developers Console.
    Konsola Google Developers

  4. Kliknij przycisk Utwórz projekt i wprowadź nazwę i identyfikator projektu (możesz użyć wartości domyślnych). Następnie kliknij pole wyboru umowa i przycisk Utwórz .

    Google — nowy projekt

    W ciągu kilku sekund zostanie utworzony nowy projekt, a przeglądarka wyświetli stronę nowych projektów.

  5. Na lewej karcie kliknij pozycję Interfejsy API & uwierzytelniania, a następnie kliknij pozycję Poświadczenia.

  6. Kliknij pozycję Utwórz nowy identyfikator klienta w obszarze OAuth.
    Zostanie wyświetlone okno dialogowe Tworzenie identyfikatora klienta .
    Google — tworzenie identyfikatora klienta

  7. W oknie dialogowym Tworzenie identyfikatora klienta zachowaj domyślną aplikację internetową dla typu aplikacji.

  8. Ustaw pozycję Autoryzowane źródła języka JavaScript na adres URL protokołu SSL użyty wcześniej w tym samouczku (https://localhost:44300/ chyba że utworzono inne projekty SSL).
    Ten adres URL jest źródłem aplikacji. W tym przykładzie wprowadzisz tylko adres URL testu localhost. Można jednak wprowadzić wiele adresów URL, aby uwzględnić host lokalny i produkcyjny.

  9. Ustaw identyfikator URI przekierowania autoryzowanego na następujące elementy:

    https://localhost:44300/signin-google
    

    Ta wartość to identyfikator URI, który ASP.NET użytkowników OAuth do komunikowania się z serwerem google OAuth. Pamiętaj adres URL protokołu SSL użyty powyżej ( https://localhost:44300/ chyba że utworzono inne projekty SSL).

  10. Kliknij przycisk Utwórz identyfikator klienta .

  11. W menu po lewej stronie konsoli Google Developers kliknij element menu Ekran zgody , a następnie ustaw swój adres e-mail i nazwę produktu. Po zakończeniu formularza kliknij przycisk Zapisz.

  12. Kliknij element menu Interfejsy API , przewiń w dół i kliknij przycisk wyłączony obok interfejsu API Google+.
    Zaakceptowanie tej opcji spowoduje włączenie interfejsu API Google+.

  13. Należy również zaktualizować pakiet NuGet Microsoft.Owin do wersji 3.0.0.
    W menu Narzędzia wybierz pozycję Menedżer pakietów NuGet , a następnie wybierz pozycję Zarządzaj pakietami NuGet dla rozwiązania.
    W oknie Zarządzanie pakietami NuGet znajdź i zaktualizuj pakiet Microsoft.Owin do wersji 3.0.0.

  14. W programie Visual Studio zaktualizuj metodę UseGoogleAuthentication strony Startup.Auth.cs , kopiując i wklejając identyfikator klienta i klucz tajny klienta do metody . Wartości Identyfikator klienta i Klucz tajny klienta pokazane poniżej są przykładami i nie będą działać.

    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. Naciśnij klawisze CTRL+F5 , aby skompilować i uruchomić aplikację. Kliknij link Zaloguj się.

  16. W obszarze Użyj innej usługi, aby się zalogować, kliknij pozycję Google.
    Zaloguj się

  17. Jeśli musisz wprowadzić swoje poświadczenia, nastąpi przekierowanie do witryny google, w której wprowadzisz poświadczenia.
    Google — logowanie

  18. Po wprowadzeniu poświadczeń zostanie wyświetlony monit o udzielenie uprawnień do właśnie utworzonej aplikacji internetowej.
    Domyślne konto usługi projektu

  19. Kliknij przycisk Akceptuj. Nastąpi przekierowanie z powrotem do strony Rejestrowanie aplikacji WingtipToys , na której można zarejestrować swoje konto Google.
    Rejestrowanie się przy użyciu konta Google

  20. Możesz zmienić lokalną nazwę rejestracji poczty e-mail używaną dla konta Gmail, ale zazwyczaj chcesz zachować domyślny alias wiadomości e-mail (czyli ten, który został użyty do uwierzytelniania). Kliknij pozycję Zaloguj się, jak pokazano powyżej.

Modyfikowanie funkcji logowania

Jak wspomniano wcześniej w tej serii samouczków, większość funkcji rejestracji użytkowników została domyślnie uwzględniona w szablonie ASP.NET Web Forms. Teraz zmodyfikujesz domyślne strony Login.aspx i Register.aspx w celu wywołania MigrateCart metody . Metoda MigrateCart kojarzy nowo zalogowanego użytkownika z anonimowym koszykiem. Kojarząc użytkownika i koszyk z zakupami, przykładowa aplikacja Wingtip Toys będzie mogła zachować koszyk użytkownika między wizytami.

  1. W Eksplorator rozwiązań znajdź i otwórz folder Konto.

  2. Zmodyfikuj stronę z kodem o nazwie Login.aspx.cs , aby uwzględnić kod wyróżniony kolorem żółtym, tak aby był wyświetlany w następujący sposób:

    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. Zapisz plik Login.aspx.cs .

Na razie można zignorować ostrzeżenie, że nie ma definicji MigrateCart metody. W dalszej części tego samouczka dodasz go nieco później.

Plik Login.aspx.cs code-behind obsługuje metodę LogIn. Sprawdzając stronę Login.aspx, zobaczysz, że ta strona zawiera przycisk "Zaloguj się", który po kliknięciu wyzwala LogIn procedury obsługi w kodzie.

Login Po wywołaniu metody w pliku Login.aspx.cs zostanie utworzone nowe wystąpienie koszykausersShoppingCart. Identyfikator koszyka (IDENTYFIKATOR GUID) jest pobierany i ustawiany na zmienną cartId . MigrateCart Następnie metoda jest wywoływana, przekazując zarówno cartId nazwę użytkownika zalogowanego, jak i do tej metody. Podczas migracji koszyka identyfikator GUID używany do identyfikowania anonimowego koszyka zakupów jest zastępowany nazwą użytkownika.

Oprócz modyfikowania pliku Login.aspx.cs w celu migracji koszyka zakupów podczas logowania użytkownika należy również zmodyfikować plik Register.aspx.cs w celu migracji koszyka, gdy użytkownik utworzy nowe konto i zaloguje się.

  1. W folderze Konto otwórz plik o nazwie Register.aspx.cs.

  2. Zmodyfikuj plik za pomocą kodu w kolorze żółtym, aby był wyświetlany w następujący sposób:

    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. Zapisz plik Register.aspx.cs . Po raz kolejny zignoruj ostrzeżenie dotyczące MigrateCart metody .

Zwróć uwagę, że kod użyty w procedurze CreateUser_Click obsługi zdarzeń jest bardzo podobny do kodu użytego w metodzie LogIn . Po zarejestrowaniu lub zalogowaniu się użytkownika do witryny zostanie wykonane wywołanie MigrateCart metody .

Migrowanie koszyka zakupów

Teraz, gdy masz zaktualizowany proces logowania i rejestracji, możesz dodać kod, aby przeprowadzić migrację koszyka przy użyciu MigrateCart metody .

  1. W Eksplorator rozwiązań znajdź folder Logic i otwórz plik klasy ShoppingCartActions.cs.

  2. Dodaj kod wyróżniony kolorem żółtym do istniejącego kodu w pliku ShoppingCartActions.cs , aby kod w pliku ShoppingCartActions.cs był wyświetlany w następujący sposób:

    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();
        }
      }
    }
    

Metoda MigrateCart używa istniejącego identyfikatora cartId, aby znaleźć koszyk użytkownika. Następnie kod przechodzi przez wszystkie elementy koszyka zakupów i zastępuje CartId właściwość (określoną przez CartItem schemat) nazwą zalogowanego użytkownika.

Aktualizowanie połączenia z bazą danych

Jeśli wykonasz czynności opisane w tym samouczku przy użyciu wstępnie utworzonej przykładowej aplikacji Wingtip Toys, musisz ponownie utworzyć domyślną bazę danych członkostwa. Modyfikując domyślne parametry połączenia, baza danych członkostwa zostanie utworzona przy następnym uruchomieniu aplikacji.

  1. Otwórz plik Web.config w katalogu głównym projektu.

  2. Zaktualizuj domyślne parametry połączenia, aby wyglądała następująco:

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

Integrowanie usługi PayPal

PayPal to internetowa platforma rozliczeń, która akceptuje płatności przez sprzedawców internetowych. W tym samouczku wyjaśniono, jak zintegrować funkcję express checkout platformy PayPal z aplikacją. Usługa Express Checkout umożliwia klientom korzystanie z usługi PayPal do płacenia za przedmioty dodane do koszyka.

Tworzenie kont testowych usługi PayPal

Aby korzystać ze środowiska testowego usługi PayPal, należy utworzyć i zweryfikować konto testowe dewelopera. Użyjesz konta testowego dewelopera do utworzenia konta testowego kupującego i konta testowego sprzedawcy. Poświadczenia konta testowego dewelopera umożliwią również przykładowej aplikacji Wingtip Toys dostęp do środowiska testowego payPal.

  1. W przeglądarce przejdź do witryny testowania deweloperów platformy PayPal:
    https://developer.paypal.com

  2. Jeśli nie masz konta dewelopera usługi PayPal, utwórz nowe konto, klikając pozycję Zarejestruj sięi wykonując kroki rejestracji. Jeśli masz istniejące konto dewelopera usługi PayPal, zaloguj się, klikając pozycję Zaloguj. Do przetestowania przykładowej aplikacji Wingtip Toys w dalszej części tego samouczka będzie potrzebne konto dewelopera PayPal.

  3. Jeśli właśnie utworzono konto dewelopera usługi PayPal, może być konieczne zweryfikowanie konta dewelopera usługi PayPal za pomocą usługi PayPal. Możesz zweryfikować swoje konto, wykonując kroki wysyłane przez usługę PayPal do konta e-mail. Po zweryfikowaniu konta dewelopera usługi PayPal zaloguj się ponownie w witrynie testowania deweloperów platformy PayPal.

  4. Po zalogowaniu się do witryny dewelopera usługi PayPal przy użyciu konta dewelopera usługi PayPal musisz utworzyć konto testowe kupującego usługi PayPal, jeśli jeszcze go nie masz. Aby utworzyć konto testowe kupującego, w witrynie usługi PayPal kliknij kartę Aplikacje , a następnie kliknij pozycję Konta piaskownicy.
    Zostanie wyświetlona strona Konta testowe piaskownicy .

    Uwaga

    Witryna PayPal Developer zawiera już konto testowe kupców.

    Zrzut ekranu przedstawiający stronę Konta testowe piaskownicy z wyróżnioną kartą Aplikacje.

  5. Na stronie Konta testowe piaskownicy kliknij pozycję Utwórz konto.

  6. Na stronie Tworzenie konta testowego wybierz wybraną przez kupującego nazwę e-mail konta testowego i hasło.

    Uwaga

    Aby przetestować przykładową aplikację Wingtip Toys na końcu tego samouczka, będziesz potrzebować adresów e-mail i hasła kupującego.

    Zrzut ekranu przedstawiający stronę Tworzenie konta testowego z polami tworzonego konta.

  7. Utwórz konto testowe kupującego, klikając przycisk Utwórz konto .
    Zostanie wyświetlona strona Konta testowe piaskownicy .

    Wyewidencjonuj i płatność za pomocą usługi PayPal — konta PayPal

  8. Na stronie Konta testowe piaskownicy kliknij konto e-mail facylitatora .
    Pojawią się opcje profilów i powiadomień.

  9. Wybierz opcję Profil , a następnie kliknij pozycję Poświadczenia interfejsu API , aby wyświetlić poświadczenia interfejsu API dla konta testowego kupca.

  10. Skopiuj poświadczenia interfejsu API TEST do Notatnika.

Do wykonywania wywołań interfejsu API Wingtip Toys z przykładowej aplikacji Wingtip Toys do środowiska testowego PayPal będą potrzebne wyświetlone poświadczenia interfejsu API (nazwa użytkownika, hasło i podpis). Poświadczenia zostaną dodane w następnym kroku.

Dodawanie poświadczeń interfejsu API i klasy PayPal

Większość kodu PayPal zostanie umieszczana w jednej klasie. Ta klasa zawiera metody używane do komunikowania się z usługą PayPal. Ponadto dodasz poświadczenia usługi PayPal do tej klasy.

  1. W przykładowej aplikacji Wingtip Toys w programie Visual Studio kliknij prawym przyciskiem myszy folder Logic , a następnie wybierz polecenie Dodaj ->Nowy element.
    Zostanie wyświetlone okno dialogowe Dodaj nowy element.

  2. W obszarze Visual C# w okienku Zainstalowane po lewej stronie wybierz pozycję Kod.

  3. W środkowym okienku wybierz pozycję Klasa. Nadaj tej nowej klasie nazwę PayPalFunctions.cs.

  4. Kliknij pozycję Dodaj.
    Nowy plik klasy jest wyświetlany w edytorze.

  5. Zastąp kod domyślny następującym kodem:

    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. Dodaj poświadczenia interfejsu API kupca (nazwa użytkownika, hasło i podpis), które były wyświetlane wcześniej w tym samouczku, aby móc wykonywać wywołania funkcji w środowisku testowym usługi PayPal.

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

Uwaga

W tej przykładowej aplikacji po prostu dodajesz poświadczenia do pliku C# (cs). Jednak w zaimplementowanym rozwiązaniu należy rozważyć szyfrowanie poświadczeń w pliku konfiguracji.

Klasa NVPAPICaller zawiera większość funkcji PayPal. Kod w klasie udostępnia metody potrzebne do dokonania zakupu testu w środowisku testowym PayPal. Do dokonywania zakupów służą następujące trzy funkcje PayPal:

  • Funkcja SetExpressCheckout
  • Funkcja GetExpressCheckoutDetails
  • Funkcja DoExpressCheckoutPayment

Metoda ShortcutExpressCheckout zbiera informacje o zakupie testowym i szczegóły produktu z koszyka zakupów i wywołuje SetExpressCheckout funkcję PayPal. Metoda GetCheckoutDetails potwierdza szczegóły zakupu i wywołuje GetExpressCheckoutDetails funkcję PayPal przed dokonaniem zakupu testowego. Metoda DoCheckoutPayment kończy zakup testu w środowisku testowym, wywołując DoExpressCheckoutPayment funkcję PayPal. Pozostały kod obsługuje metody i proces PayPal, takie jak ciągi kodowania, dekodowanie ciągów, przetwarzanie tablic i określanie poświadczeń.

Uwaga

Usługa PayPal umożliwia dołączenie opcjonalnych szczegółów zakupu na podstawie specyfikacji interfejsu API usługi PayPal. Rozszerzając kod w przykładowej aplikacji Wingtip Toys, można uwzględnić szczegóły lokalizacji, opisy produktów, podatek, numer obsługi klienta, a także wiele innych pól opcjonalnych.

Zwróć uwagę, że zwracane i anulowane adresy URL określone w metodzie ShortcutExpressCheckout używają numeru portu.

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

Gdy program Visual Web Developer uruchamia projekt internetowy przy użyciu protokołu SSL, często dla serwera internetowego jest używany port 44300. Jak pokazano powyżej, numer portu to 44300. Po uruchomieniu aplikacji może zostać wyświetlony inny numer portu. Numer portu musi być poprawnie ustawiony w kodzie, aby można było pomyślnie uruchomić przykładową aplikację Wingtip Toys na końcu tego samouczka. W następnej sekcji tego samouczka wyjaśniono, jak pobrać numer portu hosta lokalnego i zaktualizować klasę PayPal.

Aktualizowanie numeru portu LocalHost w klasie PayPal

Przykładowa aplikacja Wingtip Toys kupuje produkty, przechodząc do witryny testowania usługi PayPal i wracając do lokalnego wystąpienia przykładowej aplikacji Wingtip Toys. Aby system PayPal powrócił do poprawnego adresu URL, należy określić numer portu lokalnej przykładowej aplikacji uruchomionej w kodzie PayPal wymienionym powyżej.

  1. Kliknij prawym przyciskiem myszy nazwę projektu (WingtipToys) w Eksplorator rozwiązań i wybierz pozycję Właściwości.

  2. W lewej kolumnie wybierz kartę Sieć Web .

  3. Pobierz numer portu z pola Adres URL projektu .

  4. W razie potrzeby zaktualizuj returnURL elementy i cancelURL w klasie PayPal (NVPAPICaller) w pliku PayPalFunctions.cs , aby użyć numeru portu aplikacji internetowej:

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

Teraz dodany kod będzie zgodny z oczekiwanym portem dla lokalnej aplikacji internetowej. Usługa PayPal będzie mogła wrócić do poprawnego adresu URL na komputerze lokalnym.

Dodawanie przycisku wyewidencjonowania usługi PayPal

Teraz, gdy podstawowe funkcje paypal zostały dodane do przykładowej aplikacji, możesz rozpocząć dodawanie znaczników i kodu potrzebnego do wywołania tych funkcji. Najpierw musisz dodać przycisk wyewidencjonowania, który użytkownik zobaczy na stronie koszyka.

  1. Otwórz plik ShoppingCart.aspx .

  2. Przewiń w dół pliku i znajdź <!--Checkout Placeholder --> komentarz.

  3. Zastąp komentarz kontrolką ImageButton , aby znacznik został zastąpiony w następujący sposób:

    <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. W pliku ShoppingCart.aspx.cs po UpdateBtn_Click procedurze obsługi zdarzeń pod koniec pliku dodaj procedurę CheckOutBtn_Click obsługi zdarzeń:

    protected void CheckoutBtn_Click(object sender, ImageClickEventArgs e)
    {
        using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions())
        {
            Session["payment_amt"] = usersShoppingCart.GetTotal();
        }
        Response.Redirect("Checkout/CheckoutStart.aspx");
    }
    
  5. Ponadto w pliku ShoppingCart.aspx.cs dodaj odwołanie do CheckoutBtnpliku , aby przycisk nowego obrazu był przywołyny w następujący sposób:

    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. Zapisz zmiany zarówno w pliku ShoppingCart.aspx, jak i w pliku ShoppingCart.aspx.cs .

  7. Z menu wybierz pozycję Debuguj kompilację>WingtipToys.
    Projekt zostanie przebudowany przy użyciu nowo dodanej kontrolki ImageButton .

Wysyłanie szczegółów zakupu do usługi PayPal

Gdy użytkownik kliknie przycisk Wyewidencjonuj na stronie koszyka zakupów (ShoppingCart.aspx), rozpocznie proces zakupu. Poniższy kod wywołuje pierwszą funkcję PayPal wymaganą do zakupu produktów.

  1. W folderze Wyewidencjonuj otwórz plik za kodem o nazwie CheckoutStart.aspx.cs.
    Pamiętaj, aby otworzyć plik związany z kodem.

  2. Zastąp istniejący kod następującym kodem:

    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");
                }
            }
        }
    }
    

Gdy użytkownik aplikacji kliknie przycisk Wyewidencjonuj na stronie koszyka, przeglądarka przejdzie do strony CheckoutStart.aspx . Po załadowaniu strony CheckoutStart.aspx wywoływana ShortcutExpressCheckout jest metoda . W tym momencie użytkownik jest przenoszony do witryny internetowej testowania usługi PayPal. W witrynie PayPal użytkownik wprowadza swoje poświadczenia payPal, przegląda szczegóły zakupu, akceptuje umowę PayPal i wraca do przykładowej aplikacji Wingtip Toys, w której ShortcutExpressCheckout kończy się metoda. Po zakończeniu ShortcutExpressCheckout metody nastąpi przekierowanie użytkownika do strony CheckoutReview.aspx określonej w metodzie ShortcutExpressCheckout . Dzięki temu użytkownik może przejrzeć szczegóły zamówienia z poziomu przykładowej aplikacji Wingtip Toys.

Przeglądanie szczegółów zamówienia

Po powrocie z usługi PayPal strona CheckoutReview.aspx przykładowej aplikacji Wingtip Toys wyświetla szczegóły zamówienia. Ta strona umożliwia użytkownikowi przejrzenie szczegółów zamówienia przed zakupem produktów. Strona CheckoutReview.aspx musi zostać utworzona w następujący sposób:

  1. W folderze Wyewidencjonuj otwórz stronę o nazwie CheckoutReview.aspx.

  2. Zastąp istniejącą adiustację następującym kodem:

    <%@ 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. Otwórz stronę kodową o nazwie CheckoutReview.aspx.cs i zastąp istniejący kod następującym kodem:

    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");
        }
      }
    }
    

Kontrolka DetailsView służy do wyświetlania szczegółów zamówienia zwróconych z usługi PayPal. Ponadto powyższy kod zapisuje szczegóły zamówienia w bazie danych Wingtip Toys jako OrderDetail obiekt. Gdy użytkownik kliknie przycisk Zakończ zamówienie , zostanie przekierowany do strony CheckoutComplete.aspx .

Uwaga

Porada

Zwróć uwagę, że <ItemStyle> znaczniki strony CheckoutReview.aspx służą do zmiany stylu elementów w kontrolce DetailsView w dolnej części strony. Wyświetlając stronę w widoku projektu (wybierając pozycję Projekt w lewym dolnym rogu programu Visual Studio), a następnie wybierając kontrolkę DetailsView i wybierając tag inteligentny (ikonę strzałki w prawym górnym rogu kontrolki), będzie można wyświetlić zadania Widoku szczegółów.

Wyewidencjonowanie i płatność przy użyciu usługi PayPal — edytowanie pól

Po wybraniu pozycji Edytuj pola zostanie wyświetlone okno dialogowe Pola . W tym oknie dialogowym można łatwo kontrolować właściwości wizualizacji, takie jak ItemStyle, kontrolki DetailsView .

Wyewidencjonowanie i płatność przy użyciu usługi PayPal — okno dialogowe Pola

Ukończ zakup

Strona CheckoutComplete.aspx dokonuje zakupu w usłudze PayPal. Jak wspomniano powyżej, użytkownik musi kliknąć przycisk Zakończ zamówienie , zanim aplikacja przejdzie do strony CheckoutComplete.aspx .

  1. W folderze Wyewidencjonuj otwórz stronę o nazwie CheckoutComplete.aspx.

  2. Zastąp istniejącą adiustację następującym kodem:

    <%@ 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. Otwórz stronę kodową o nazwie CheckoutComplete.aspx.cs i zastąp istniejący kod następującym kodem:

    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");
        }
      }
    }
    

Po załadowaniu strony CheckoutComplete.aspx wywoływana DoCheckoutPayment jest metoda . Jak wspomniano wcześniej, DoCheckoutPayment metoda kończy zakup w środowisku testowym PayPal. Po zakończeniu zakupu zamówienia na stronie CheckoutComplete.aspx zostanie wyświetlona transakcja ID płatności nabywcy.

Obsługa anulowania zakupu

Jeśli użytkownik zdecyduje się anulować zakup, zostanie przekierowany do strony CheckoutCancel.aspx , na której zobaczy, że zamówienie zostało anulowane.

  1. Otwórz stronę o nazwie CheckoutCancel.aspx w folderze Wyewidencjonuj .

  2. Zastąp istniejącą adiustację następującym kodem:

    <%@ 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>
    

Obsługa błędów zakupu

Błędy podczas procesu zakupu będą obsługiwane przez stronę CheckoutError.aspx . Kod strony CheckoutStart.aspx , strona CheckoutReview.aspx i strona CheckoutComplete.aspx spowoduje każde przekierowanie do strony CheckoutError.aspx , jeśli wystąpi błąd.

  1. Otwórz stronę o nazwie CheckoutError.aspx w folderze Wyewidencjonuj .

  2. Zastąp istniejącą adiustację następującym kodem:

    <%@ 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>
    

Strona CheckoutError.aspx jest wyświetlana ze szczegółami błędu w przypadku wystąpienia błędu podczas procesu wyewidencjonowania.

Uruchamianie aplikacji

Uruchom aplikację, aby zobaczyć, jak kupować produkty. Pamiętaj, że będziesz działać w środowisku testowym usługi PayPal. Nie są wymieniane żadne rzeczywiste pieniądze.

  1. Upewnij się, że wszystkie pliki zostały zapisane w programie Visual Studio.

  2. Otwórz przeglądarkę internetową i przejdź do witryny https://developer.paypal.com.

  3. Zaloguj się przy użyciu konta dewelopera usługi PayPal utworzonego wcześniej w tym samouczku.
    W przypadku piaskownicy deweloperów platformy PayPal musisz zalogować się na stronie https://developer.paypal.com , aby przetestować wyewidencjonowania ekspresowego. Dotyczy to tylko testowania piaskownicy usługi PayPal, a nie środowiska na żywo usługi PayPal.

  4. W programie Visual Studio naciśnij klawisz F5 , aby uruchomić przykładową aplikację Wingtip Toys.
    Po odbudowaniu bazy danych przeglądarka zostanie otwarta i zostanie wyświetlona strona Default.aspx .

  5. Dodaj trzy różne produkty do koszyka zakupów, wybierając kategorię produktu, taką jak "Samochody", a następnie klikając pozycję Dodaj do koszyka obok każdego produktu.
    W koszyku zostanie wyświetlony wybrany produkt.

  6. Kliknij przycisk PayPal , aby wyewidencjonować.

    Wyewidencjonuj i płatność za pomocą usługi PayPal — koszyk

    Wyewidencjonowanie będzie wymagało konta użytkownika dla przykładowej aplikacji Wingtip Toys.

  7. Kliknij link Google po prawej stronie, aby zalogować się przy użyciu istniejącego konta e-mail gmail.com.
    Jeśli nie masz konta gmail.com, możesz go utworzyć do celów testowych w www.gmail.com. Możesz również użyć standardowego konta lokalnego, klikając pozycję "Zarejestruj".

    Wyewidencjonuj i płatność przy użyciu usługi PayPal — logowanie

  8. Zaloguj się przy użyciu konta gmaila i hasła.

    Wyewidencjonuj i płatność przy użyciu usługi PayPal — logowanie w usłudze Gmail

  9. Kliknij przycisk Zaloguj, aby zarejestrować swoje konto Gmail przy użyciu przykładowej nazwy użytkownika aplikacji Wingtip Toys.

    Wyewidencjonuj i płatność za pomocą usługi PayPal — zarejestruj konto

  10. W witrynie testowej usługi PayPal dodaj adres e-mail nabywcy i hasło utworzone wcześniej w tym samouczku, a następnie kliknij przycisk Zaloguj .

    Wyewidencjonuj i płatność przy użyciu usługi PayPal — logowanie przy użyciu usługi PayPal

  11. Zaakceptuj zasady payPal i kliknij przycisk Zgadzam się i kontynuuj .
    Pamiętaj, że ta strona jest wyświetlana tylko przy pierwszym użyciu tego konta PayPal. Ponownie należy pamiętać, że jest to konto testowe, nie są wymieniane prawdziwe pieniądze.

    Wyewidencjonuj i płatność za pomocą usługi PayPal — zasady paypal

  12. Przejrzyj informacje o zamówieniu na stronie przeglądu środowiska testowego usługi PayPal i kliknij przycisk Kontynuuj.

    Wyewidencjonuj i płatność za pomocą usługi PayPal — przeglądanie informacji

  13. Na stronie CheckoutReview.aspx sprawdź kwotę zamówienia i wyświetl wygenerowany adres wysyłkowy. Następnie kliknij przycisk Zakończ zamówienie .

    Wyewidencjonuj i płatność przy użyciu usługi PayPal — przegląd zamówienia

  14. Strona CheckoutComplete.aspx jest wyświetlana z identyfikatorem transakcji płatności.

    Wyewidencjonuj i płatność przy użyciu usługi PayPal — zakończono wyewidencjonowania

Przeglądanie bazy danych

Przeglądając zaktualizowane dane w przykładowej bazie danych aplikacji Wingtip Toys po uruchomieniu aplikacji, możesz zobaczyć, że aplikacja pomyślnie zarejestrowała zakup produktów.

Dane zawarte w pliku bazy danych Wingtiptoys.mdf można sprawdzić przy użyciu okna Eksploratora baz danych (okna Eksploratora serwera w programie Visual Studio), tak jak wcześniej w tej serii samouczków.

  1. Zamknij okno przeglądarki, jeśli jest nadal otwarte.

  2. W programie Visual Studio wybierz ikonę Pokaż wszystkie pliki w górnej części Eksplorator rozwiązań, aby umożliwić rozwinięcie folderu App_Data.

  3. Rozwiń folder App_Data .
    Może być konieczne wybranie ikony Pokaż wszystkie pliki dla folderu.

  4. Kliknij prawym przyciskiem myszy plik bazy danych Wingtiptoys.mdf i wybierz polecenie Otwórz.
    Zostanie wyświetlony Eksplorator serwera .

  5. Rozwiń folder Tabele .

  6. Kliknij prawym przyciskiem myszy tabelę Orders (Zamówienia) i wybierz polecenie Show Table Data (Pokaż dane tabeli).
    Zostanie wyświetlona tabela Orders (Zamówienia ).

  7. Przejrzyj kolumnę PaymentTransactionID , aby potwierdzić pomyślne transakcje.

    Wyewidencjonowywanie i płatność za pomocą usługi PayPal — przeglądanie bazy danych

  8. Zamknij okno tabeli Orders (Zamówienia).

  9. W Eksploratorze serwera kliknij prawym przyciskiem myszy tabelę OrderDetails i wybierz polecenie Pokaż dane tabeli.

  10. OrderId Przejrzyj wartości i Username w tabeli OrderDetails. Należy pamiętać, że te wartości są zgodne z OrderId wartościami i Usernamezawartymi w tabeli Orders (Zamówienia).

  11. Zamknij okno tabeli OrderDetails .

  12. Kliknij prawym przyciskiem myszy plik bazy danych Wingtip Toys (Wingtiptoys.mdf) i wybierz polecenie Zamknij połączenie.

  13. Jeśli nie widzisz okna Eksplorator rozwiązań, kliknij przycisk Eksplorator rozwiązań w dolnej części okna Eksploratora serwera, aby ponownie wyświetlić Eksplorator rozwiązań.

Podsumowanie

W tym samouczku dodano schematy szczegółów zamówienia i zamówienia w celu śledzenia zakupu produktów. Zintegrowano również funkcję PayPal z przykładową aplikacją Wingtip Toys.

Dodatkowe zasoby

Omówienie konfiguracji ASP.NET
Wdrażanie bezpiecznej aplikacji ASP.NET Web Forms z członkostwem, uwierzytelnianiem OAuth i SQL Database w Azure App Service
Microsoft Azure — bezpłatna wersja próbna

Disclaimer

Ten samouczek zawiera przykładowy kod. Taki przykładowy kod jest dostarczany "jak jest" bez gwarancji jakiegokolwiek rodzaju. W związku z tym firma Microsoft nie gwarantuje dokładności, integralności ani jakości przykładowego kodu. Zgadzasz się używać przykładowego kodu na własne ryzyko. W żadnym wypadku firma Microsoft nie będzie ponosić odpowiedzialności w żaden sposób za dowolny przykładowy kod, zawartość, w tym nie tylko błędy lub pominięcie kodu przykładowego, zawartości, ani jakiejkolwiek utraty lub uszkodzenia w wyniku użycia jakiegokolwiek przykładowego kodu. Niniejszym użytkownik jest powiadamiany i niniejszym wyraża zgodę na ubezpieczenie, zapisywanie i utrzymywanie Microsoft nieszkodliwe od i przeciwko wszelkim stratom, roszczeń utraty, szkody lub szkody jakiegokolwiek rodzaju, w tym, bez ograniczeń, tych okazji lub wynikających z materiałów, które publikuje, przesyła, przesyła lub polega na tym, ale nie tylko, poglądy wyrażone tam.