Compartir a través de


Finalización de la compra y pago con PayPal

Por Erik Reitan

Descargar del proyecto de ejemplo (C#) Wingtip Toys o Descarga del libro electrónico (PDF)

En esta serie de tutoriales se le enseñarán los conceptos básicos de la creación de una aplicación ASP.NET Web Forms mediante ASP.NET 4.5 y Microsoft Visual Studio Express 2013 para la Web. Como acompañamiento a esta serie de tutoriales, hay disponible un proyecto con código fuente de C# de Visual Studio 2013.

En este tutorial se describe cómo modificar la aplicación de ejemplo Wingtip Toys para incluir la autorización del usuario, el registro y el pago mediante PayPal. Solo los usuarios que hayan iniciado sesión tendrán autorización para comprar productos. La funcionalidad integrada de registro del usuario en la plantilla del proyecto ASP.NET 4.5 Web Forms ya incluye gran parte de lo que necesita. Agregará la funcionalidad Express Checkout de PayPal. En este tutorial, usará el entorno de pruebas para desarrolladores de PayPal, por lo que no se transferirán fondos reales. Al final del tutorial, probará la aplicación; para ello, seleccionará productos para agregar al carro de la compra, hará clic en el botón de finalización de la compra y transferirá datos al sitio web de pruebas de PayPal. En el sitio web de pruebas de PayPal, confirmará la información de envío y de pago y, después, volverá a la aplicación local de ejemplo Wingtip Toys para confirmar y completar la compra.

Hay varios procesadores de pagos de terceros experimentados que se especializan en las compras en línea y abordan la escalabilidad y la seguridad. Los desarrolladores de ASP.NET deben tener en cuenta las ventajas de usar una solución de pago de terceros antes de implementar una solución de compra.

Nota:

La aplicación de ejemplo Wingtip Toys se ha diseñado para mostrar los conceptos y características específicos de ASP.NET disponibles para los desarrolladores web de ASP.NET. Esta aplicación de ejemplo no se ha optimizado para todas las circunstancias posibles en lo que respecta a la escalabilidad y la seguridad.

Temas que se abordarán:

  • Cómo restringir el acceso a páginas específicas de una carpeta.
  • Cómo crear un carro de la compra conocido a partir de un carro de la compra anónimo.
  • Cómo habilitar SSL para el proyecto.
  • Cómo agregar un proveedor de OAuth al proyecto.
  • Cómo usar PayPal para comprar productos mediante el entorno de pruebas de PayPal.
  • Cómo mostrar los detalles de PayPal en un control DetailsView.
  • Cómo actualizar la base de datos de la aplicación Wingtip Toys con los detalles obtenidos de PayPal.

Adición de seguimiento de pedidos

En este tutorial, creará dos clases nuevas para realizar un seguimiento de los datos del pedido que ha creado un usuario. Las clases realizarán un seguimiento de los datos relacionados con la información de envío, el total de la compra y la confirmación de pago.

Adición de las clases de modelo Order y OrderDetail

Anteriormente en esta serie de tutoriales, definió el esquema para las categorías, los productos y los artículos del carro de la compra mediante la creación de las clases Category, Product y CartItem en la carpeta Models. Ahora agregará dos clases nuevas para definir el esquema del pedido de productos y los detalles del pedido.

  1. En la carpeta Models, agregue una nueva clase denominada Order.cs.
    El nuevo archivo de la clase se mostrará en el editor.

  2. Reemplace el código predeterminado por lo siguiente:

    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. Agregue una clase OrderDetail.cs a la carpeta Models.

  4. Reemplace el código predeterminado por el siguiente:

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

Las clases Order y OrderDetail contienen el esquema para definir la información del pedido que se usa para la compra y el envío.

Aparte de esto, debe actualizar la clase de contexto de base de datos que administra las clases de entidad y que proporciona acceso a los datos a la base de datos. Para ello, agregará las clases de modelo Order y OrderDetail recién creadas a la clase ProductContext.

  1. En el Explorador de soluciones, busque y abra el archivo ProductContext.cs.

  2. Agregue el código resaltado al archivo ProductContext.cs como se muestra a continuación:

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

Tal y como se mencionó anteriormente en esta serie de tutoriales, el código del archivo ProductContext.cs agrega el espacio de nombres System.Data.Entity para que tenga acceso a todas las funcionalidades principales de Entity Framework. Esta funcionalidad incluye la capacidad de consultar, insertar, actualizar y eliminar datos usando objetos fuertemente tipados. El código anterior de la clase ProductContext proporciona acceso a Entity Framework a las clases Order y OrderDetail recién agregadas.

Adición de acceso al proceso de finalización de la compra

La aplicación de ejemplo Wingtip Toys permite a los usuarios anónimos revisar y agregar productos a un carro de la compra. Sin embargo, cuando los usuarios anónimos deciden comprar los productos que agregaron al carro de la compra, deben iniciar sesión en el sitio. Una vez que han iniciado sesión, pueden acceder a las páginas restringidas de la aplicación web que controlan el proceso de compra y de finalización de la compra. Estas páginas restringidas se encuentran en la carpeta Checkout de la aplicación.

Adición de páginas y de una carpeta Checkout

Ahora creará la carpeta Checkout y las páginas que verá el cliente durante el proceso de finalización de la compra. Actualizará estas páginas más adelante en este tutorial.

  1. Haga clic con el botón derecho en el nombre del proyecto (Wingtip Toys) en el Explorador de soluciones y seleccione Agregar -> Nueva carpeta.

    Checkout and Payment with PayPal - New Folder

  2. Asigne el nombre Checkout a la nueva carpeta.

  3. Haga clic con el botón derecho en la carpeta Checkout y, luego, seleccione Agregar->Nuevo elemento.

    Checkout and Payment with PayPal - New Item

  4. Se abrirá el cuadro de diálogo Agregar nuevo elemento.

  5. Seleccione el grupo de plantillas Visual C# ->Web de la izquierda. Después, en el panel central, seleccione Formulario web con página maestra y asígnele el nombre CheckoutStart.aspx.

    Checkout and Payment with PayPal - Add New Item Dialog

  6. Igual que antes, seleccione el archivo Site.Master como página maestra.

  7. Agregue las siguientes páginas adicionales a la carpeta Checkout siguiendo los mismos pasos anteriores:

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

Adición de un archivo Web.config

Al agregar un nuevo archivo Web.config a la carpeta Checkout, podrá restringir el acceso a todas las páginas que contiene la carpeta.

  1. Haga clic con el botón derecho en la carpeta Checkout y elija Agregar ->Nuevo elemento.
    Se abrirá el cuadro de diálogo Agregar nuevo elemento.

  2. Seleccione el grupo de plantillas Visual C# ->Web de la izquierda. Después, en el panel central, seleccione Archivo de configuración web, acepte el nombre predeterminado de Web.config y seleccione Agregar.

  3. Reemplace el contenido XML del archivo Web.config por el siguiente:

    <?xml version="1.0"?>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?"/>
        </authorization>
      </system.web>
    </configuration>
    
  4. Guarde el archivo Web.config .

El archivo Web.config especifica que se debe denegar el acceso a las páginas de la carpeta Checkout para todos los usuarios desconocidos de la aplicación web. Sin embargo, si el usuario ha registrado una cuenta y ha iniciado sesión, será un usuario conocido y tendrá acceso a las páginas de la carpeta Chekout.

Es importante tener en cuenta que la configuración de ASP.NET sigue una jerarquía, donde cada archivo Web.config aplica las opciones de configuración a la carpeta en la que se encuentra y a todos los directorios secundarios que haya por debajo.

Habilitación de SSL para el proyecto

Capa de sockets seguros (SSL) es un protocolo definido para permitir a los servidores y clientes web comunicarse de forma más segura mediante el uso de cifrado. Cuando no se usa SSL, cualquiera que tenga acceso físico a la red puede abrir los datos que se envían entre el cliente y el servidor para examinar el paquete. Además, varios esquemas de autenticación habituales no son seguros en HTTP plano. En particular, la autenticación básica y la autenticación mediante formularios envían credenciales no cifradas. Para ser seguros, estos esquemas de autenticación deben usar SSL.

  1. En el Explorador de soluciones, haga clic en el proyecto WingtipToys y presione F4 para mostrar la ventana Propiedades.
  2. Cambie SSL habilitado a true.
  3. Copie la Dirección URL de SSL para usarla más adelante.
    La dirección URL de SSL será https://localhost:44300/, a menos que haya creado previamente sitios web SSL (como se muestra a continuación).
    Project Properties
  4. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto WingtipToys y luego haga clic en Propiedades.
  5. En el panel izquierdo, haga clic en Web.
  6. Cambie la URL del proyecto para usar la dirección URL de SSL que ha guardado anteriormente.
    Project Web Properties
  7. Presione CTRL+Spara guardar la página.
  8. Presione Ctrl+F5 para ejecutar la aplicación. Visual Studio mostrará una opción que le permite evitar advertencias de SSL.
  9. Haga clic en para confiar en el certificado SSL de IIS Express y continúe.
    IIS Express SSL certificate details
    Se mostrará una advertencia de seguridad.
  10. Haga clic en para instalar el certificado en el host local.
    Security Warning dialog box
    Se mostrará la ventana del explorador.

Ahora puede probar la aplicación web localmente de forma fácil mediante SSL.

Incorporación de un proveedor de OAuth 2.0

ASP.NET Web Forms proporciona opciones mejoradas para suscripciones y autenticación. Estas mejoras incluyen OAuth. OAuth es un protocolo abierto que ofrece autorización segura a través de un método estándar sencillo para aplicaciones web, móviles y de escritorio. La plantilla de ASP.NET Web Forms usa OAuth para exponer Facebook, Twitter, Google y Microsoft como proveedores de autenticación. Aunque este tutorial solo utiliza Google como proveedor de autenticación, puede modificar fácilmente el código para utilizar cualquiera de los proveedores. Los pasos que hay que seguir para implementar otros proveedores son muy similares a los que verá en este tutorial.

Además de la autenticación, este tutorial también utiliza roles para implementar la autorización. Únicamente los usuarios que agregue al rol canEdit podrán cambiar datos (crear, editar o eliminar contactos).

Nota:

Las aplicaciones de Windows Live solo aceptan una dirección URL dinámica para un sitio web de trabajo, por lo que no puede usar una dirección URL de sitio web local para probar los inicios de sesión.

Los pasos siguientes permiten agregar un proveedor de autenticación de Google.

  1. Abra el archivo App_Start\Startup.Auth.cs.

  2. Quite los caracteres de comentario del método app.UseGoogleAuthentication() para que tenga el siguiente aspecto:

    app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
    {
        ClientId = "",
        ClientSecret = ""
    });
    
  3. Navegue a la consola de desarrolladores de Google. Debe iniciar sesión también con su cuenta de correo electrónico de desarrollador de Google (gmail.com). Si no tiene una cuenta de Google, seleccione el vínculo Crear una cuenta .
    A continuación, verá la consola de desarrolladores de Google.
    Google Developers Console

  4. Haga clic en el botón Crear proyecto y escriba un nombre y un id. para el proyecto (puede usar los valores predeterminados). Después, marque la casilla de aceptación de los términos del servicio y haga clic en el botón Crear.

    Google - New Project

    En unos segundos, se creará el nuevo proyecto y el explorador mostrará la página de nuevos proyectos.

  5. En la pestaña izquierda, haga clic en APIs y servicios y, después, haga clic en Credenciales.

  6. Haga clic en Crear ID de cliente nuevo en OAuth.
    Se mostrará el cuadro de diálogo Crear id. de cliente .
    Google - Create Client ID

  7. En el cuadro de diálogo Crear ID de cliente, mantenga la aplicación web predeterminada para el tipo de aplicación.

  8. En Orígenes de JavaScript autorizados, indique la dirección URL de SSL que ha usado anteriormente en este tutorial (https://localhost:44300/, a menos que haya creado otros proyectos de SSL).
    Esta dirección URL es el origen de su aplicación. Para este ejemplo, solo proporcionará la dirección URL de prueba del localhost. También puede escribir varias direcciones URL para localhost y producción.

  9. Establezca el URI de redireccionamiento autorizado en lo siguiente:

    https://localhost:44300/signin-google
    

    Este valor es el URI que utiliza ASP.NET OAuth para comunicarse con el servidor OAuth de Google. Recuerde la dirección URL de SSL que ha usado anteriormente (https://localhost:44300/, a menos que haya creado otros proyectos de SSL).

  10. Haga clic en el botón Crear ID de cliente.

  11. En el menú izquierdo de Google Developers Console, haga clic en el elemento de menú Pantalla de consentimiento y establezca su dirección de correo electrónico y el nombre del producto. Cuando haya completado el formulario, haga clic en Guardar.

  12. Haga clic en el elemento de menú API, desplácese hacia abajo y haga clic en el botón Desactivado situado junto a Google+ API.
    Si acepta esta opción, se habilitará la API de Google+.

  13. También debe actualizar el paquete NuGet Microsoft.Owin a la versión 3.0.0.
    En el menú Herramientas, seleccione Administrador de paquetes NuGet y, después, Administrar paquetes NuGet para la solución.
    En la ventana Administrar paquetes NuGet, busque y actualice el paquete Microsoft.Owin a la versión 3.0.0.

  14. En Visual Studio, actualice el método UseGoogleAuthentication de la página Startup.Auth.cs copiando y pegando el id. de cliente y el secreto de cliente en el método. Los valores de ClientId y ClientSecret que se muestran a continuación son ejemplos y no funcionarán.

    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. Presione CTRL+F5 para compilar y ejecutar la aplicación. Haga clic en el vínculo Iniciar sesión .

  16. En Utilice otro servicio para iniciar sesión, haga clic en Google.
    Log in

  17. Si tiene que proporcionar credenciales, se le redirigirá al sitio de Google donde podrá especificarlas.
    Google - Sign in

  18. Después de escribir sus credenciales, se le pedirá que conceda permisos a la aplicación web que acaba de crear.
    Project Default Service Account

  19. Haga clic en Aceptar. Después, se le redirigirá a la página de registro de la aplicación WingtipToys, donde puede registrar su cuenta de Google.
    Register with your Google Account

  20. Tiene la opción de cambiar el nombre de registro de correo electrónico local que usa para su cuenta de Gmail, pero suele ser más práctico mantener el mismo alias de correo electrónico predeterminado (es decir, el que usó para la autenticación). Haga clic en Iniciar sesión tal y como se muestra arriba.

Modificación de la funcionalidad de inicio de sesión

Como se ha mencionado anteriormente en esta serie de tutoriales, gran parte de la funcionalidad de registro de usuarios se ha incluido en la plantilla de ASP.NET Web Forms de forma predeterminada. Ahora modificará las páginas Login.aspx y Register.aspx predeterminadas para llamar al método MigrateCart. El método MigrateCart asocia un usuario que acaba de iniciar sesión con un carro de la compra anónimo. Al asociar el usuario y el carro de la compra, la aplicación de ejemplo Wingtip Toys podrá mantener el carro de la compra del usuario en sus visitas.

  1. En el Explorador de soluciones, busque y abra la carpeta Account.

  2. Modifique la página de código subyacente denominada Login.aspx.cs para incluir el código resaltado en amarillo y que aparezca de la siguiente manera:

    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. Guarde el archivo Login.aspx.cs.

Por ahora, puede omitir la advertencia de que no hay ninguna definición para el método MigrateCart. Lo agregará un poco más adelante en este tutorial.

El archivo de código subyacente Login.aspx.cs admite un método LogIn. Al inspeccionar la página Login.aspx, verá que esta página incluye un botón "Iniciar sesión" que al hacer clic desencadena el controlador LogIn en el código subyacente.

Cuando se llama al método Login en Login.aspx.cs, se crea una nueva instancia del carro de la compra denominada usersShoppingCart. El id. del carro de la compra (un GUID) se recupera y se establece en la variable cartId. Después, se llama al método MigrateCart y se pasan a este método la variable cartId y el nombre del usuario que ha iniciado sesión. Cuando se migra el carro de la compra, el GUID usado para identificar el carro de la compra anónimo se reemplaza por el nombre del usuario.

Además de modificar el archivo de código subyacente Login.aspx.cs para migrar el carro de la compra cuando el usuario inicia sesión, también debe modificar el archivo de código subyacente Register.aspx.cs para migrar el carro de la compra cuando el usuario crea una cuenta e inicia sesión.

  1. En la carpeta Account, abra el archivo de código subyacente denominado Register.aspx.cs.

  2. Modifique el archivo de código subyacente mediante la inclusión del código en amarillo para que tenga el siguiente aspecto:

    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. Guarde el archivo Register.aspx.cs. Una vez más, omita la advertencia sobre el método MigrateCart.

Observe que el código que ha usado en el controlador de eventos CreateUser_Click es muy similar al código que ha usado en el método LogIn. Cuando el usuario se registra o inicia sesión en el sitio, se llama al método MigrateCart.

Migración del carro de la compra

Ahora que ha actualizado el proceso de inicio de sesión y registro, puede agregar el código para migrar el carro de la compra mediante el método MigrateCart.

  1. En el Explorador de soluciones, busque la carpeta Logic y abra el archivo de clase ShoppingCartActions.cs.

  2. Agregue el código resaltado en amarillo al código existente en el archivo ShoppingCartActions.cs, de modo que el código del archivo ShoppingCartActions.cs tenga el siguiente aspecto:

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

El método MigrateCart usa el cartId existente para buscar el carro de la compra del usuario. Después, el código recorre en bucle todos los elementos del carro de la compra y reemplaza la propiedad CartId (según lo especificado por el esquema CartItem) por el nombre del usuario que ha iniciado sesión.

Actualización de la conexión de base de datos

Si sigue este tutorial con la aplicación de ejemplo precompilada Wingtip Toys, debe volver a crear la base de datos de pertenencia predeterminada. Al modificar la cadena de conexión predeterminada, la base de datos de pertenencia se creará la próxima vez que se ejecute la aplicación.

  1. Abra el archivo Web.config en la raíz del proyecto.

  2. Actualice la cadena de conexión predeterminada para que tenga el siguiente aspecto:

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

Integración de PayPal

PayPal es una plataforma de facturación basada en web que acepta pagos de comerciantes en línea. En este tutorial se explica cómo integrar la funcionalidad Express Checkout de PayPal en su aplicación. Express Checkout permite a los clientes usar PayPal para pagar los artículos que han agregado a su carro de la compra.

Creación de cuentas de prueba de PayPal

Para usar el entorno de pruebas de PayPal, debe crear y verificar una cuenta de prueba de desarrollador. Usará la cuenta de prueba de desarrollador para crear una cuenta de prueba de comprador y una cuenta de prueba de vendedor. Las credenciales de la cuenta de prueba de desarrollador también permitirán que la aplicación de ejemplo Wingtip Toys acceda al entorno de pruebas de PayPal.

  1. En un explorador, vaya al sitio de pruebas para desarrolladores de PayPal:
    https://developer.paypal.com

  2. Si no tiene una cuenta de desarrollador de PayPal, haga clic en Sign Up y siga los pasos de registro. Si tiene una cuenta de desarrollador de PayPal, inicie sesión haciendo clic en Log In. Necesitará su cuenta de desarrollador de PayPal para probar la aplicación de ejemplo Wingtip Toys más adelante en este tutorial.

  3. Si acaba de registrarse para una cuenta de desarrollador de PayPal, es posible que tenga que verificar su cuenta de desarrollador de PayPal con PayPal. Puede verificar su cuenta siguiendo los pasos que le ha enviado PayPal a su cuenta de correo electrónico. Una vez que haya verificado su cuenta de desarrollador de PayPal, vuelva a iniciar sesión en el sitio de pruebas para desarrolladores de PayPal.

  4. Una vez que haya iniciado sesión en el sitio para desarrolladores de PayPal con su cuenta de desarrollador de PayPal, debe crear una cuenta de prueba de comprador de PayPal, si aún no tiene una. Para crear una cuenta de prueba de comprador, en el sitio de PayPal, haga clic en la pestaña Applications y, después, haga clic en Sandbox accounts.
    Se muestra la página Sandbox test accounts.

    Nota:

    El sitio PayPal Developer ya proporciona una cuenta de prueba de comerciante.

    Screenshot showing the Sandbox test accounts page with the Applications tab highlighted.

  5. En la página Sandbox test accounts, haga clic en Create Account.

  6. En la página Create test account, elija un correo electrónico para la cuenta de prueba de comprador y una contraseña de su elección.

    Nota:

    Necesitará la dirección de correo electrónico de comprador y la contraseña para probar la aplicación de ejemplo Wingtip Toys al final de este tutorial.

    Screenshot of the Create test account page displaying the fields of an account that is being created.

  7. Cree la cuenta de prueba de comprador haciendo clic en el botón Create Account.
    Se muestra la página Sandbox test accounts.

    Checkout and Payment with PayPal - PayPal Accounts

  8. En la página Sandobx test accounts, haga clic en la cuenta de correo electrónico facilitator.
    Se mostrarán las opciones Profile y Notification.

  9. Seleccione la opción Profile y haga clic en API Credentials para ver las credenciales de API de la cuenta de prueba de comerciante.

  10. Copie las credenciales de la API de prueba en el Bloc de notas.

Necesitará las credenciales que aparecen en Classic TEST API Credentials (nombre de usuario, contraseña y firma) para realizar llamadas API desde la aplicación de ejemplo Wingtip Toys al entorno de pruebas de PayPal. En el paso siguiente agregará las credenciales.

Adición de una clase y de las credenciales de API de PayPal

Colocará la mayoría del código de PayPal en una sola clase. Esta clase contiene los métodos usados para comunicarse con PayPal. Además, agregará sus credenciales de PayPal a esta clase.

  1. En la aplicación de ejemplo Wingtip Toys en Visual Studio, haga clic con el botón derecho en la carpeta Logic y seleccione Agregar ->Nuevo elemento.
    Se abrirá el cuadro de diálogo Agregar nuevo elemento.

  2. En Visual C#, en el panel Instalado de la izquierda, seleccione Código.

  3. En el panel central, seleccione Clase. Asigne a esta nueva clase el nombre PayPalFunctions.cs.

  4. Haga clic en Agregar.
    El nuevo archivo de la clase se mostrará en el editor.

  5. Reemplace el código predeterminado por el siguiente:

    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. Agregue las credenciales de la API de comerciante (nombre de usuario, contraseña y firma) que ha copiado anteriormente en este tutorial para poder realizar llamadas de función al entorno de pruebas de PayPal.

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

Nota:

En esta aplicación de ejemplo, simplemente va a agregar credenciales a un archivo de C# (.cs). Sin embargo, en una solución implementada, debe considerar la posibilidad de cifrar las credenciales en un archivo de configuración.

La clase NVPAPICaller contiene la mayoría de funcionalidades de PayPal. El código de la clase proporciona los métodos necesarios para realizar una compra de prueba desde el entorno de pruebas de PayPal. Las siguientes tres funciones de PayPal se usan para realizar compras:

  • Función SetExpressCheckout
  • Función GetExpressCheckoutDetails
  • Función DoExpressCheckoutPayment

El método ShortcutExpressCheckout recopila la información de la compra de prueba y los detalles de los productos del carro de la compra y llama a la función SetExpressCheckout de PayPal. El método GetCheckoutDetails confirma los detalles de la compra y llama a la función GetExpressCheckoutDetails de PayPal antes de finalizar la compra de prueba. El método DoCheckoutPayment completa la compra de prueba desde el entorno de pruebas llamando a la función DoExpressCheckoutPayment de PayPal. El código restante respalda los métodos y procesos de PayPal, por ejemplo, mediante la codificación y descodificación de las cadenas, el procesamiento de matrices y la determinación de las credenciales.

Nota:

PayPal le permite incluir detalles de compra opcionales en función de la especificación de la API de PayPal. Al extender el código en la aplicación de ejemplo Wingtip Toys, puede incluir detalles de localización, descripciones de productos, impuestos, un número de atención al cliente y muchos otros campos opcionales.

Observe que las direcciones URL de retorno y cancelación especificadas en el método ShortcutExpressCheckout usan un número de puerto.

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

Cuando Visual Web Developer ejecuta un proyecto web mediante SSL, normalmente se usa el puerto 44300 para el servidor web. Como se muestra anteriormente, el número de puerto es 44300. Al ejecutar la aplicación, podría ver un número de puerto diferente. De establecer el número de puerto correcto en el código para ejecutar correctamente la aplicación de ejemplo Wingtip Toys al final de este tutorial. En la siguiente sección de este tutorial se explica cómo recuperar el número de puerto localhost y cómo actualizar la clase de PayPal.

Actualización del número de puerto localhost en la clase de PayPal

La aplicación de ejemplo Wingtip Toys compra productos; para ello, va al sitio de prueba de PayPal y vuelve a su instancia local de la aplicación de ejemplo Wingtip Toys. Para que PayPal vuelva a la dirección URL correcta, debe especificar el número de puerto de la aplicación de ejemplo que se ejecuta localmente en el código de PayPal mencionado anteriormente.

  1. Haga clic con el botón derecho en el nombre del proyecto (WingtipToys) en el Explorador de soluciones y seleccione Propiedades.

  2. En la columna izquierda, seleccione la pestaña Web.

  3. Recupere el número de puerto del cuadro URL del proyecto.

  4. Si es necesario, actualice returnURL y cancelURL en la clase de PayPal (NVPAPICaller) en el archivo PayPalFunctions.cs para usar el número de puerto de su aplicación web:

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

Ahora el código que ha agregado coincidirá con el puerto esperado para la aplicación web local. PayPal podrá volver a la dirección URL correcta en su máquina local.

Adición del botón PayPal Checkout

Ahora que se han agregado las funciones principales de PayPal a la aplicación de ejemplo, puede empezar a agregar el marcado y el código necesarios para llamar a estas funciones. En primer lugar, debe agregar el botón de finalización de la compra que el usuario verá en la página del carro de la compra.

  1. Abra el archivo ShoppingCart.aspx.

  2. Desplácese hasta la parte inferior del archivo y busque el comentario <!--Checkout Placeholder -->.

  3. Reemplace el comentario por un control ImageButton para reemplazar el marcado de la siguiente manera:

    <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. En el archivo ShoppingCart.aspx.cs, después del controlador de eventos UpdateBtn_Click cerca del final del archivo, agregue el controlador de eventos 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. En el archivo ShoppingCart.aspx.cs, agregue también una referencia a CheckoutBtn, de modo que se haga referencia al nuevo botón de imagen de la siguiente manera:

    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. Guarde los cambios en los archivos ShoppingCart.aspx y ShoppingCart.aspx.cs.

  7. En el menú, seleccione Depurar->Compilar WingtipToys.
    El proyecto se volverá a compilar con el control ImageButton recién agregado.

Envío de los detalles de la compra a PayPal

Cuando el usuario hace clic en el botón Checkout en la página del carro de la compra (ShoppingCart.aspx), comenzará el proceso de compra. El código siguiente llama a la primera función de PayPal necesaria para comprar productos.

  1. En la carpeta Checkout, abra el archivo de código subyacente denominado CheckoutStart.aspx.cs.
    Asegúrese de abrir el archivo de código subyacente.

  2. Reemplace el código existente por el siguiente:

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

Cuando el usuario de la aplicación hace clic en el botón Checkout en la página del carro de la compra, el explorador navega a la página CheckoutStart.aspx. Cuando se carga la página CheckoutStart.aspx, se llama al método ShortcutExpressCheckout. En este momento, el usuario se transfiere al sitio web de pruebas de PayPal. En el sitio de PayPal, el usuario escribe sus credenciales de PayPal, revisa los detalles de la compra, acepta el contrato de PayPal y vuelve a la aplicación de ejemplo Wingtip Toys donde se completa el método ShortcutExpressCheckout. Una vez completado el método ShortcutExpressCheckout, redirigirá al usuario a la página CheckoutReview.aspx especificada en el método ShortcutExpressCheckout. Esto permite al usuario revisar los detalles del pedido desde la aplicación de ejemplo Wingtip Toys.

Revisión de los detalles del pedido

Después de volver de PayPal, la página CheckoutReview.aspx de la aplicación de ejemplo Wingtip Toys muestra los detalles del pedido. Esta página permite al usuario revisar los detalles del pedido antes de comprar los productos. La página CheckoutReview.aspx debe crearse de la siguiente manera:

  1. En la carpeta Checkout, abra la página denominada CheckoutReview.aspx.

  2. Reemplace el marcado existente por lo siguiente:

    <%@ 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. Abra la página de código subyacente denominada CheckoutReview.aspx.cs y reemplace el código existente por lo siguiente:

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

El control DetailsView se usa para mostrar los detalles del pedido que se han devuelto desde PayPal. Además, el código anterior guarda los detalles del pedido en la base de datos de Wingtip Toys como un objeto OrderDetail. Cuando el usuario hace clic en el botón Complete Order, se le redirige a la página CheckoutComplete.aspx.

Nota:

Sugerencia

En el marcado de la página CheckoutReview.aspx, observe que la etiqueta <ItemStyle> se usa para cambiar el estilo de los elementos del control DetailsView cerca de la parte inferior de la página. Al ver la página en la vista Diseño (seleccionando Diseño en la esquina inferior izquierda de Visual Studio), si selecciona el control DetailsView y la etiqueta inteligente (el icono de flecha situado en la parte superior derecha del control), podrá ver la ventana DetailsView Tasks.

Checkout and Payment with PayPal - Edit Fields

Si selecciona Editar campos, aparecerá el cuadro de diálogo Campos. En este cuadro de diálogo puede controlar fácilmente las propiedades visuales, como ItemStyle, del control DetailsView.

Checkout and Payment with PayPal - Fields Dialog

Finalización de la compra

La página CheckoutComplete.aspx realiza la compra desde PayPal. Como se ha mencionado anteriormente, el usuario debe hacer clic en el botón Complete Order para que la aplicación vaya a la página CheckoutComplete.aspx.

  1. En la carpeta Checkout, abra la página denominada CheckoutComplete.aspx.

  2. Reemplace el marcado existente por lo siguiente:

    <%@ 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. Abra la página de código subyacente denominada CheckoutComplete.aspx.cs y reemplace el código existente por lo siguiente:

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

Cuando se carga la página CheckoutComplete.aspx, se llama al método DoCheckoutPayment. Como se ha mencionado anteriormente, el método DoCheckoutPayment completa la compra desde el entorno de pruebas de PayPal. Una vez que PayPal ha completado la compra del pedido, la página CheckoutComplete.aspx muestra un ID de la transacción de pago al comprador.

Control de la cancelación de la compra

Si el usuario decide cancelar la compra, se le dirigirá a la página CheckoutCancel.aspx donde verá que se ha cancelado su pedido.

  1. Abra la página denominada CheckoutCancel.aspx en la carpeta Checkout.

  2. Reemplace el marcado existente por lo siguiente:

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

Control de los errores al procesar la compra

La página CheckoutError.aspx controlará los errores durante el proceso de compra. El código subyacente de las páginas CheckoutStart.aspx, CheckoutReview.aspx y CheckoutComplete.aspx redirigirá a la página CheckoutError.aspx si se produce un error.

  1. Abra la página denominada CheckoutError.aspx en la carpeta Checkout.

  2. Reemplace el marcado existente por lo siguiente:

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

La página CheckoutError.aspx se muestra con los detalles del error cuando se produce un error durante el proceso de finalización de la compra.

Ejecutar la aplicación

Ejecute la aplicación para ver cómo comprar productos. Tenga en cuenta que se va a ejecutar en el entorno de pruebas de PayPal. No se intercambia dinero real.

  1. Asegúrese de que todos los archivos se han guardado en Visual Studio.

  2. Abra un explorador web y vaya a https://developer.paypal.com.

  3. Inicie sesión con su cuenta de desarrollador de PayPal que ha creado anteriormente en este tutorial.
    Para el espacio aislado para desarrolladores de PayPal, debe iniciar sesión en https://developer.paypal.com para probar la funcionalidad de compra rápida. Esto solo se aplica a las pruebas en el espacio aislado de PayPal, no al entorno activo de PayPal.

  4. En Visual Studio, presione F5 para ejecutar la aplicación de ejemplo Wingtip Toys.
    Después de volver a generar la base de datos, el explorador se abrirá y mostrará la página Default.aspx.

  5. Agregue tres productos diferentes al carro de la compra seleccionando la categoría de producto, como "Cars" y, después, haga clic en Add to Cart junto a cada producto.
    El carro de la compra mostrará el producto que ha seleccionado.

  6. Haga clic en el botón PayPal para finalizar la compra.

    Checkout and Payment with PayPal - Cart

    Para finalizar la compra, necesitará una cuenta de usuario para la aplicación de ejemplo Wingtip Toys.

  7. Haga clic en el vínculo Google a la derecha de la página para iniciar sesión con una cuenta de correo electrónico de gmail.com existente.
    Si no tiene una cuenta de gmail.com, puede crear una con fines de prueba en www.gmail.com. También puede usar una cuenta local estándar haciendo clic en "Register".

    Checkout and Payment with PayPal - Log in

  8. Inicie sesión con su cuenta de gmail y su contraseña.

    Checkout and Payment with PayPal - Gmail Sign In

  9. Haga clic en el botón Log in para registrar su cuenta de gmail con el nombre de usuario de la aplicación de ejemplo Wingtip Toys.

    Checkout and Payment with PayPal - Register Account

  10. En el sitio de prueba de PayPal, agregue la dirección de correo electrónico y la contraseña de comprador que ha creado anteriormente en este tutorial y, después, haga clic en el botón Log In.

    Checkout and Payment with PayPal - PayPal Sign In

  11. Acepte la directiva de PayPal y haga clic en el botón Aceptar y continuar.
    Tenga en cuenta que esta página solo se muestra la primera vez que usa esta cuenta de PayPal. Tenga en cuenta también que se trata de una cuenta de prueba, no se intercambia dinero real.

    Checkout and Payment with PayPal - PayPal Policy

  12. Revise la información del pedido en la página de revisión del entorno de pruebas de PayPal y haga clic en Continue.

    Checkout and Payment with PayPal - Review Information

  13. En la página CheckoutReview.aspx, compruebe el importe del pedido y la dirección de envío generada. Después, haga clic en el botón Complete Order.

    Checkout and Payment with PayPal - Order Review

  14. La página CheckoutComplete.aspx se muestra con un id. de la transacción de pago.

    Checkout and Payment with PayPal - Checkout Complete

Revisión de la base de datos

Al revisar los datos actualizados en la base de datos de la aplicación de ejemplo Wingtip Toys después de ejecutar la aplicación, puede ver que la aplicación ha registrado correctamente la compra de los productos.

Puede inspeccionar los datos incluidos en el archivo de base de datos de Wingtiptoys.mdf mediante la ventana Explorador de bases de datos (o Explorador de servidores en Visual Studio), tal y como hizo anteriormente en esta serie de tutoriales.

  1. Cierre la ventana del explorador si todavía está abierta.

  2. En Visual Studio, seleccione el icono Mostrar todos los archivos en la parte superior del Explorador de soluciones para poder expandir la carpeta App_Data.

  3. Expanda la carpeta App_Data.
    Es posible que tenga que seleccionar el icono Mostrar todos los archivos para la carpeta.

  4. Haga clic con el botón derecho en el archivo de base de datos Wingtiptoys.mdf y seleccione Abrir.
    Se abrirá el Explorador de servidores.

  5. Expanda la carpeta Tablas .

  6. Haga clic con el botón derecho en la tabla Orders y seleccione Mostrar datos de tabla.
    Se mostrará la tabla Orders.

  7. Revise la columna PaymentTransactionID para confirmar las transacciones correctas.

    Checkout and Payment with PayPal - Review Database

  8. Cierre la ventana de la tabla Orders.

  9. En el Explorador de servidores, haga clic con el botón derecho en la tabla OrderDetails y seleccione Mostrar datos de tabla.

  10. Revise los valores OrderId y Username de la tabla OrderDetails. Observe que estos valores coinciden con los valores OrderId y Username incluidos en la tabla Orders.

  11. Cierre la ventana de la tabla OrderDetails.

  12. Haga clic con el botón derecho en el archivo de base de datos de Wingtip Toys (Wingtiptoys.mdf) y seleccione Cerrar conexión.

  13. Si no ve la ventana del Explorador de soluciones, haga clic en Explorador de soluciones en la parte inferior de la ventana Explorador de servidores para mostrar de nuevo el Explorador de soluciones.

Resumen

En este tutorial ha agregado esquemas de pedidos y de detalles de los pedidos para realizar un seguimiento de la compra de productos. También ha integrado la funcionalidad de PayPal en la aplicación de ejemplo Wingtip Toys.

Recursos adicionales

Información general sobre la configuración de ASP.NET
Implementación de una aplicación segura de ASP.NET Web Forms con pertenencia, OAuth y SQL Database en Azure App Service
Microsoft Azure: prueba gratuita

Declinación de responsabilidades

Este tutorial contiene código de ejemplo. Este código de ejemplo se proporciona "tal cual" sin ningún tipo de garantía. En consecuencia, Microsoft no garantiza la precisión, integridad ni calidad del código de ejemplo. Acepta usar el código de ejemplo bajo su propia responsabilidad. En ningún caso Microsoft será responsable ante usted de ninguna manera por ningún código de ejemplo o contenido, incluido, entre otros, por errores u omisiones en cualquier código de ejemplo o contenido, o por pérdidas o daños de cualquier tipo en que se incurra como resultado del uso de cualquier código de ejemplo. Por la presente, queda notificado y acepta indemnizar, defender y eximir a Microsoft de toda responsabilidad ante y contra cualquier pérdida, reclamación de pérdida, lesión o daño de cualquier tipo, incluidos, entre otros, los causados por o derivados de material publicado, transmitido y usado por usted, o en el que usted confía, incluidas las opiniones expresadas en él.