Check-out e pagamento com o PayPal
por Erik Reitan
Baixar o Projeto de Exemplo wingtip toys (C#) ou baixar livro eletrônico (PDF)
Esta série de tutoriais ensinará os conceitos básicos da criação de um aplicativo ASP.NET Web Forms usando o ASP.NET 4.5 e o Microsoft Visual Studio Express 2013 para Web. Um projeto Visual Studio 2013 com código-fonte C# está disponível para acompanhar esta série de tutoriais.
Este tutorial descreve como modificar o aplicativo de exemplo Wingtip Toys para incluir autorização, registro e pagamento do usuário usando o PayPal. Somente os usuários conectados terão autorização para comprar produtos. O ASP.NET 4.5 Web Forms funcionalidade interna de registro de usuário do modelo de projeto já inclui muito do que você precisa. Você adicionará a funcionalidade do PayPal Express Checkout. Neste tutorial, você usará o ambiente de teste do desenvolvedor do PayPal, portanto, nenhum fundo real será transferido. No final do tutorial, você testará o aplicativo selecionando produtos para adicionar ao carrinho de compras, clicando no botão de check-out e transferindo dados para o site de teste do PayPal. No site de teste do PayPal, você confirmará suas informações de envio e pagamento e, em seguida, retornará ao aplicativo de exemplo wingtip toys local para confirmar e concluir a compra.
Há vários processadores de pagamento de terceiros experientes especializados em compras online que abordam escalabilidade e segurança. ASP.NET desenvolvedores devem considerar as vantagens de utilizar uma solução de pagamento de terceiros antes de implementar uma solução de compra e compra.
Nota
O aplicativo de exemplo Wingtip Toys foi projetado para mostrar conceitos e recursos ASP.NET específicos disponíveis para desenvolvedores web ASP.NET. Este aplicativo de exemplo não foi otimizado para todas as circunstâncias possíveis em relação à escalabilidade e à segurança.
- Como restringir o acesso a páginas específicas em uma pasta.
- Como criar um carrinho de compras conhecido de um carrinho de compras anônimo.
- Como habilitar o SSL para o projeto.
- Como adicionar um provedor OAuth ao projeto.
- Como usar o PayPal para comprar produtos usando o ambiente de teste do PayPal.
- Como exibir detalhes do PayPal em um controle DetailsView .
- Como atualizar o banco de dados do aplicativo Wingtip Toys com detalhes obtidos do PayPal.
Neste tutorial, você criará duas novas classes para acompanhar os dados da ordem que um usuário criou. As classes acompanharão os dados sobre informações de envio, total de compras e confirmação de pagamento.
Anteriormente nesta série de tutoriais, você definiu o esquema para categorias, produtos e itens de carrinho de compras criando as Category
classes , Product
e CartItem
na pasta Modelos . Agora você adicionará duas novas classes para definir o esquema para a ordem do produto e os detalhes do pedido.
Na pasta Modelos , adicione uma nova classe chamada Order.cs.
O novo arquivo de classe é exibido no editor.Substitua o código padrão pelo seguinte:
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; } } }
Adicione uma classe OrderDetail.cs à pasta Models .
Substitua o código padrão pelo código a seguir:
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; } } }
As Order
classes e OrderDetail
contêm o esquema para definir as informações de pedido usadas para compra e envio.
Além disso, você precisará atualizar a classe de contexto do banco de dados que gerencia as classes de entidade e que fornece acesso a dados ao banco de dados. Para fazer isso, você adicionará as classes Order e OrderDetail
model recém-criadas à ProductContext
classe .
Em Gerenciador de Soluções, localize e abra o arquivo ProductContext.cs.
Adicione o código realçado ao arquivo ProductContext.cs , conforme mostrado abaixo:
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; } } }
Conforme mencionado anteriormente nesta série de tutoriais, o código no arquivo ProductContext.cs adiciona o System.Data.Entity
namespace para que você tenha acesso a todas as funcionalidades principais do Entity Framework. Essa funcionalidade inclui a capacidade de consultar, inserir, atualizar e excluir dados trabalhando com objetos fortemente tipado. O código acima na ProductContext
classe adiciona acesso ao Entity Framework às classes e OrderDetail
recém-adicionadasOrder
.
O aplicativo de exemplo Wingtip Toys permite que usuários anônimos revisem e adicionem produtos a um carrinho de compras. No entanto, quando os usuários anônimos optam por comprar os produtos adicionados ao carrinho de compras, eles devem fazer logon no site. Depois de fazer logon, eles podem acessar as páginas restritas do aplicativo Web que lidam com o processo de compra e check-out. Essas páginas restritas estão contidas na pasta Checkout do aplicativo.
Agora você criará a pasta Checkout e as páginas nela que o cliente verá durante o processo de check-out. Você atualizará essas páginas mais adiante neste tutorial.
Clique com o botão direito do mouse no nome do projeto (Wingtip Toys) em Gerenciador de Soluções e selecione Adicionar uma Nova Pasta.
Nomeie a nova pasta Como check-out.
Clique com o botão direito do mouse na pasta Checkout e selecione Adicionar-Novo> Item.
A caixa de diálogo Adicionar novo item é exibida.
Selecione o grupo Visual C# ->Modelos da Web à esquerda. Em seguida, no painel central, selecione Web Form com Página Mestrae nomeie-o como CheckoutStart.aspx.
Como antes, selecione o arquivo Site.Master como a página master.
Adicione as seguintes páginas adicionais à pasta Checkout usando as mesmas etapas acima:
- CheckoutReview.aspx
- CheckoutComplete.aspx
- CheckoutCancel.aspx
- CheckoutError.aspx
Ao adicionar um novo arquivo Web.config à pasta Checkout , você poderá restringir o acesso a todas as páginas contidas na pasta.
Clique com o botão direito do mouse na pasta Checkout e selecione Adicionar ->Novo Item.
A caixa de diálogo Adicionar novo item é exibida.Selecione o grupo Visual C# ->Modelos da Web à esquerda. Em seguida, no painel central, selecione Arquivo de Configuração da Web, aceite o nome padrão de Web.confige selecione Adicionar.
Substitua o conteúdo XML existente no arquivo Web.config pelo seguinte:
<?xml version="1.0"?> <configuration> <system.web> <authorization> <deny users="?"/> </authorization> </system.web> </configuration>
Salvar o arquivo Web.config.
O arquivo Web.config especifica que todos os usuários desconhecidos do aplicativo Web devem ter acesso negado às páginas contidas na pasta Checkout . No entanto, se o usuário tiver registrado uma conta e estiver conectado, ele será um usuário conhecido e terá acesso às páginas na pasta Checkout .
É importante observar que ASP.NET configuração segue uma hierarquia, em que cada arquivo Web.config aplica definições de configuração à pasta em que está e a todos os diretórios filho abaixo dela.
SSL é um protocolo que permite que os servidores Web e clientes Web se comuniquem de modo mais seguro, por meio de criptografia. Quando o SSL não é utilizado, os dados enviados entre o cliente e servidor ficam abertos à detecção de pacotes por qualquer um com acesso físico à rede. Adicionalmente, diversos esquemas comuns de autenticação não são seguros por HTTP puro. Em particular, a autenticação Básica e a autenticação de formulários enviam credenciais sem criptografia. Para serem seguros, esses esquemas de autenticação precisam utilizar SSL.
- Em Gerenciador de Soluções, clique no projeto WingtipToys e pressione F4 para exibir a janela Propriedades.
- Altere Habilitado para SSL para
true
. - Copie a URL do SSL , de modo que você possa utilizá-la mais tarde.
A URL SSL seráhttps://localhost:44300/
, a menos que você tenha criado sites SSL anteriormente (conforme mostrado abaixo).
- Em Gerenciador de Soluções, clique com o botão direito do mouse no projeto WingtipToys e clique em Propriedades.
- Na guia à esquerda, clique em Web.
- Altere a URL do Projeto para usar a URL SSL que você salvou anteriormente.
- Salve a página pressionando CTRL+S.
- Pressione CTRL+F5 para executar o aplicativo. O Visual Studio exibirá uma opção para que você possa evitar avisos do SSL.
- Clique em Sim para confiar no certificado SSL IIS Express e continuar.
Será exibido um aviso de segurança. - Clique em Sim para instalar o certificado em seu localhost.
A janela do navegador será exibida.
Agora você pode testar facilmente seu aplicativo Web localmente usando SSL.
Os Web Forms ASP.NET oferecem opções aprimoradas de associação e autenticação. Esses aprimoramentos incluem OAuth. O OAuth é um protocolo aberto que permite autorização segura em um método simples e padrão da web, aplicativos móveis e de área de trabalho. O modelo ASP.NET Web Forms usa o OAuth para expor Facebook, Twitter, Google e Microsoft como provedores de autenticação. Embora este tutorial use apenas o Google como o provedor de autenticação, você pode facilmente modificar o código para usar qualquer um dos provedores. As etapas para implementar outros provedores são muito semelhantes às etapas que você verá neste tutorial.
Além da autenticação, o tutorial também usará funções para implementar a autorização. Somente os usuários que você adicionar à função canEdit
poderão alterar dados (criar, editar ou excluir contatos).
Nota
Os aplicativos do Windows Live aceitam apenas uma URL dinâmica para um site funcional, portanto, você não pode usar uma URL de site local para testar logons.
As etapas a seguir permitirão que você adicione um provedor de autenticação do Google.
Abra o arquivo App_Start\Startup.Auth.cs .
Remove os caracteres do comentário do método para que o método
app.UseGoogleAuthentication()
pareça-se cm o seguinte:app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() { ClientId = "", ClientSecret = "" });
Navegue até o Console Para Desenvolvedores do Google. Você também precisará se autenticar com sua conta de email de desenvolvedor do Google (gmail.com). Se você não tiver uma conta do Google, selecione o link Criar uma conta .
Em seguida, você verá o Console de desenvolvedores do Google.
Clique no botão Criar Projeto e insira um nome de projeto e uma ID (você pode usar os valores padrão). Em seguida, clique na caixa de seleção contrato e no botão Criar .
Em poucos segundos o novo projeto será criado e o navegador exibirá a nova página de projetos.
Na guia à esquerda, clique em APIs & autenticação e clique em Credenciais.
Clique em Criar Nova ID do Cliente em OAuth.
A caixa de diálogo Criar ID de Cliente será exibida.
Na caixa de diálogo Criar ID do Cliente , mantenha o aplicativo Web padrão para o tipo de aplicativo.
Defina as Origens Do JavaScript Autorizadas para a URL SSL usada anteriormente neste tutorial (
https://localhost:44300/
a menos que você tenha criado outros projetos SSL).
Esta URL é a origem para seu aplicativo. Para este exemplo, você irá inserir apenas a URL de teste do localhost. No entanto, você pode inserir várias URLs para levar em conta o localhost e a produção.Defina o URI de Redirecionamento Autorizado com o seguinte valor:
https://localhost:44300/signin-google
Este valor é o URI que o OAuth ASP.NET utiliza para comunicar-se com o servidor google OAuth. Lembre-se da URL SSL usada acima (
https://localhost:44300/
a menos que você tenha criado outros projetos SSL).Clique no botão Criar ID do Cliente .
No menu à esquerda do Console de Desenvolvedores do Google, clique no item de menu Da tela Consentimento e defina o endereço de email e o nome do produto. Quando você tiver concluído o formulário, clique em Salvar.
Clique no item de menu APIs , role para baixo e clique no botão desativado ao lado da API do Google+.
Aceitar essa opção habilitará a API do Google+.Você também deve atualizar o pacote NuGet Microsoft.Owin para a versão 3.0.0.
No menu Ferramentas , selecione Gerenciador de Pacotes NuGet e, em seguida, selecione Gerenciar Pacotes NuGet para solução.
Na janela Gerenciar Pacotes NuGet , localize e atualize o pacote Microsoft.Owin para a versão 3.0.0.No Visual Studio, atualize o
UseGoogleAuthentication
método da página Startup.Auth.cs copiando e colando a ID do cliente e o Segredo do Cliente no método . Os valores ID do Cliente e Segredo do Cliente mostrados abaixo são exemplos e não funcionarão.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" }); } } }
Pressione CTRL+F5 para compilar e executar o aplicativo. Clique no link Logon .
Em Usar outro serviço para fazer logon, clique em Google.
Se é necessário inserir suas credenciais, você será redirecionado ao site do Google, onde vai inserir essas credenciais.
Depois de inserir suas credenciais, você será solicitado a conceder permissões ao aplicativo Web que acabou de criar.
Clique em Aceitar. Agora você será redirecionado de volta para a página Registrar do aplicativo WingtipToys , na qual poderá registrar sua conta do Google.
Você tem a opção de alterar o nome de registro de email local utilizado para sua conta do Gmail, mas normalmente você deverá preferir manter o alias de email padrão (ou seja, aquele utilizado por você para a autenticação). Clique em Fazer logon , conforme mostrado acima.
Como mencionado anteriormente nesta série de tutoriais, grande parte da funcionalidade de registro do usuário foi incluída no modelo de ASP.NET Web Forms por padrão. Agora você modificará as páginas padrão Login.aspx e Register.aspx para chamar o MigrateCart
método. O MigrateCart
método associa um usuário conectado recentemente a um carrinho de compras anônimo. Ao associar o usuário e o carrinho de compras, o aplicativo de exemplo Wingtip Toys poderá manter o carrinho de compras do usuário entre as visitas.
Em Gerenciador de Soluções, localize e abra a pasta Conta.
Modifique a página code-behind chamada Login.aspx.cs para incluir o código realçado em amarelo, para que ele apareça da seguinte maneira:
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; } } } } }
Salve o arquivo Login.aspx.cs .
Por enquanto, você pode ignorar o aviso de que não há definição para o MigrateCart
método . Você o adicionará um pouco mais tarde neste tutorial.
O arquivo code-behind Login.aspx.cs dá suporte a um método LogIn. Ao inspecionar a página Login.aspx, você verá que esta página inclui um botão "Fazer logon" que, ao clicar, dispara o LogIn
manipulador no code-behind.
Quando o Login
método em Login.aspx.cs é chamado, uma nova instância do carrinho de compras chamada usersShoppingCart
é criada. A ID do carrinho de compras (um GUID) é recuperada e definida como a cartId
variável. Em seguida, o MigrateCart
método é chamado, passando o cartId
e o nome do usuário conectado para esse método. Quando o carrinho de compras é migrado, o GUID usado para identificar o carrinho de compras anônimo é substituído pelo nome de usuário.
Além de modificar o arquivo code-behind Login.aspx.cs para migrar o carrinho de compras quando o usuário fizer logon, você também deve modificar o arquivo code-behind Register.aspx.cs para migrar o carrinho de compras quando o usuário criar uma nova conta e fizer logon.
Na pasta Conta , abra o arquivo code-behind chamado Register.aspx.cs.
Modifique o arquivo code-behind incluindo o código em amarelo, para que ele apareça da seguinte maneira:
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(); } } } }
Salve o arquivo Register.aspx.cs . Mais uma vez, ignore o aviso sobre o
MigrateCart
método .
Observe que o código usado no CreateUser_Click
manipulador de eventos é muito semelhante ao código usado no LogIn
método . Quando o usuário registra ou faz logon no site, uma chamada para o MigrateCart
método será feita.
Agora que você tem o processo de logon e registro atualizado, você pode adicionar o código para migrar o carrinho de compras usando o MigrateCart
método .
Em Gerenciador de Soluções, localize a pasta Lógica e abra o arquivo de classe ShoppingCartActions.cs.
Adicione o código realçado em amarelo ao código existente no arquivo ShoppingCartActions.cs , para que o código no arquivo ShoppingCartActions.cs apareça da seguinte maneira:
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(); } } }
O MigrateCart
método usa a cartId existente para localizar o carrinho de compras do usuário. Em seguida, o código percorre todos os itens do carrinho de compras e substitui a CartId
propriedade (conforme especificado pelo esquema) pelo CartItem
nome de usuário conectado.
Se você estiver seguindo este tutorial usando o aplicativo de exemplo Wingtip Toys predefinido , recrie o banco de dados de associação padrão. Modificando o cadeia de conexão padrão, o banco de dados de associação será criado na próxima vez que o aplicativo for executado.
Abra o arquivo Web.config na raiz do projeto.
Atualize o cadeia de conexão padrão para que ele apareça da seguinte maneira:
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=aspnet-WingtipToys;Integrated Security=True" providerName="System.Data.SqlClient" />
O PayPal é uma plataforma de cobrança baseada na Web que aceita pagamentos de comerciantes online. Este tutorial explica como integrar a funcionalidade do Express Checkout do PayPal ao seu aplicativo. O Express Checkout permite que seus clientes usem o PayPal para pagar os itens que eles adicionaram ao carrinho de compras.
Para usar o ambiente de teste do PayPal, você deve criar e verificar uma conta de teste do desenvolvedor. Você usará a conta de teste do desenvolvedor para criar uma conta de teste do comprador e uma conta de teste do vendedor. As credenciais da conta de teste do desenvolvedor também permitirão que o aplicativo de exemplo Wingtip Toys acesse o ambiente de teste do PayPal.
Em um navegador, navegue até o site de teste do desenvolvedor do PayPal:
https://developer.paypal.comSe você não tiver uma conta de desenvolvedor do PayPal, crie uma nova conta clicando em Inscrever-see seguindo as etapas de inscrição. Se você tiver uma conta de desenvolvedor existente do PayPal, entre clicando em Fazer Logon. Você precisará de sua conta de desenvolvedor do PayPal para testar o aplicativo de exemplo Wingtip Toys mais adiante neste tutorial.
Se você acabou de se inscrever para sua conta de desenvolvedor do PayPal, talvez seja necessário verificar sua conta de desenvolvedor do PayPal com o PayPal. Você pode verificar sua conta seguindo as etapas que o PayPal enviou para sua conta de email. Depois de verificar sua conta de desenvolvedor do PayPal, faça logon novamente no site de teste do desenvolvedor do PayPal.
Depois de fazer logon no site do desenvolvedor do PayPal com sua conta de desenvolvedor do PayPal, você precisará criar uma conta de teste do comprador do PayPal se ainda não tiver uma. Para criar uma conta de teste do comprador, no site do PayPal, clique na guia Aplicativos e, em seguida, clique em Contas de área restrita.
A página Contas de teste da área restrita é mostrada.Nota
O site do Desenvolvedor do PayPal já fornece uma conta de teste do comerciante.
Na página Contas de teste da área restrita, clique em Criar Conta.
Na página Criar conta de teste , escolha um email de conta de teste do comprador e a senha de sua escolha.
Nota
Você precisará dos endereços de email e senha do comprador para testar o aplicativo de exemplo Wingtip Toys no final deste tutorial.
Crie a conta de teste do comprador clicando no botão Criar Conta .
A página Contas de teste de área restrita é exibida.Na página Contas de teste da área restrita, clique na conta de email do facilitador .
Asopções Perfil e Notificação são exibidas.Selecione a opção Perfil e clique em Credenciais de API para exibir suas credenciais de API para a conta de teste do comerciante.
Copie as credenciais da API de TESTE para o bloco de notas.
Você precisará de suas credenciais da API de TESTE Clássica exibidas (Nome de usuário, senha e assinatura) para fazer chamadas à API do aplicativo de exemplo Wingtip Toys para o ambiente de teste do PayPal. Você adicionará as credenciais na próxima etapa.
Você colocará a maior parte do código do PayPal em uma única classe. Essa classe contém os métodos usados para se comunicar com o PayPal. Além disso, você adicionará suas credenciais do PayPal a essa classe.
No aplicativo de exemplo Wingtip Toys no Visual Studio, clique com o botão direito do mouse na pasta Lógica e selecione Adicionar ->Novo Item.
A caixa de diálogo Adicionar novo item é exibida.Em Visual C# no painel Instalado à esquerda, selecione Código.
No painel central, selecione Classe. Nomeie essa nova classe PayPalFunctions.cs.
Clique em Adicionar.
O novo arquivo de classe é exibido no editor.Substitua o código padrão pelo código a seguir:
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; } }
Adicione as credenciais da API do Comerciante (Nome de usuário, senha e assinatura) exibidas anteriormente neste tutorial para que você possa fazer chamadas de função para o ambiente de teste do PayPal.
public string APIUsername = "<Your API Username>"; private string APIPassword = "<Your API Password>"; private string APISignature = "<Your Signature>";
Nota
Neste aplicativo de exemplo, você está simplesmente adicionando credenciais a um arquivo C# (.cs). No entanto, em uma solução implementada, você deve considerar criptografar suas credenciais em um arquivo de configuração.
A classe NVPAPICaller contém a maioria da funcionalidade do PayPal. O código na classe fornece os métodos necessários para fazer uma compra de teste do ambiente de teste do PayPal. As três funções do PayPal a seguir são usadas para fazer compras:
- Função
SetExpressCheckout
- Função
GetExpressCheckoutDetails
- Função
DoExpressCheckoutPayment
O ShortcutExpressCheckout
método coleta as informações de compra de teste e os detalhes do produto do carrinho de compras e chama a função PayPal SetExpressCheckout
. O GetCheckoutDetails
método confirma os detalhes da compra e chama a GetExpressCheckoutDetails
função PayPal antes de fazer a compra de teste. O DoCheckoutPayment
método conclui a compra de teste do ambiente de teste chamando a DoExpressCheckoutPayment
função PayPal. O código restante dá suporte aos métodos e ao processo do PayPal, como codificação de cadeias de caracteres, decodificação de cadeias de caracteres, processamento de matrizes e determinação de credenciais.
Nota
O PayPal permite que você inclua detalhes de compra opcionais com base na especificação da API do PayPal. Ao estender o código no aplicativo de exemplo Wingtip Toys, você pode incluir detalhes de localização, descrições de produtos, impostos, um número de atendimento ao cliente, bem como muitos outros campos opcionais.
Observe que as URLs de retorno e cancelamento especificadas no método ShortcutExpressCheckout usam um número de porta.
string returnURL = "https://localhost:44300/Checkout/CheckoutReview.aspx";
string cancelURL = "https://localhost:44300/Checkout/CheckoutCancel.aspx";
Quando o Visual Web Developer executa um projeto Web usando SSL, geralmente a porta 44300 é usada para o servidor Web. Conforme mostrado acima, o número da porta é 44300. Ao executar o aplicativo, você pode ver um número de porta diferente. O número da porta precisa ser definido corretamente no código para que você possa executar com êxito o aplicativo de exemplo Wingtip Toys no final deste tutorial. A próxima seção deste tutorial explica como recuperar o número da porta do host local e atualizar a classe paypal.
O aplicativo de exemplo Wingtip Toys compra produtos navegando até o site de teste do PayPal e retornando à sua instância local do aplicativo de exemplo Wingtip Toys. Para que o PayPal retorne à URL correta, você precisa especificar o número da porta do aplicativo de exemplo em execução localmente no código do PayPal mencionado acima.
Clique com o botão direito do mouse no nome do projeto (WingtipToys) em Gerenciador de Soluções e selecione Propriedades.
Na coluna à esquerda, selecione a guia Web .
Recupere o número da porta da caixa URL do Projeto .
Se necessário, atualize o
returnURL
ecancelURL
na classe PayPal (NVPAPICaller
) no arquivo PayPalFunctions.cs para usar o número da porta do aplicativo Web:string returnURL = "https://localhost:<Your Port Number>/Checkout/CheckoutReview.aspx"; string cancelURL = "https://localhost:<Your Port Number>/Checkout/CheckoutCancel.aspx";
Agora, o código que você adicionou corresponderá à porta esperada para seu aplicativo Web local. O PayPal poderá retornar à URL correta em seu computador local.
Agora que as funções primárias do PayPal foram adicionadas ao aplicativo de exemplo, você pode começar a adicionar a marcação e o código necessários para chamar essas funções. Primeiro, você deve adicionar o botão de check-out que o usuário verá na página do carrinho de compras.
Abra o arquivo ShoppingCart.aspx .
Role até a parte inferior do arquivo e localize o
<!--Checkout Placeholder -->
comentário.Substitua o comentário por um
ImageButton
controle para que a marcação seja substituída da seguinte maneira:<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" />
No arquivo ShoppingCart.aspx.cs , após o
UpdateBtn_Click
manipulador de eventos próximo ao final do arquivo, adicione oCheckOutBtn_Click
manipulador de eventos:protected void CheckoutBtn_Click(object sender, ImageClickEventArgs e) { using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions()) { Session["payment_amt"] = usersShoppingCart.GetTotal(); } Response.Redirect("Checkout/CheckoutStart.aspx"); }
Também no arquivo ShoppingCart.aspx.cs , adicione uma referência ao , para
CheckoutBtn
que o novo botão de imagem seja referenciado da seguinte maneira: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; } } }
Salve suas alterações no arquivo ShoppingCart.aspx e no arquivo ShoppingCart.aspx.cs .
No menu, selecione Depurar-Compilar>WingtipToys.
O projeto será recriado com o controle ImageButton recém-adicionado.
Quando o usuário clicar no botão Check-out na página do carrinho de compras (ShoppingCart.aspx), ele iniciará o processo de compra. O código a seguir chama a primeira função paypal necessária para comprar produtos.
Na pasta Checkout , abra o arquivo code-behind chamado CheckoutStart.aspx.cs.
Certifique-se de abrir o arquivo code-behind.Substitua o código existente pelo seguinte:
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"); } } } }
Quando o usuário do aplicativo clicar no botão Check-out na página do carrinho de compras, o navegador navegará até a página CheckoutStart.aspx . Quando a página CheckoutStart.aspx é carregada, o ShortcutExpressCheckout
método é chamado. Neste ponto, o usuário é transferido para o site de teste do PayPal. No site do PayPal, o usuário insere suas credenciais do PayPal, examina os detalhes da compra, aceita o contrato do PayPal e retorna ao aplicativo de exemplo Wingtip Toys em que o ShortcutExpressCheckout
método é concluído. Quando o ShortcutExpressCheckout
método for concluído, ele redirecionará o usuário para a página CheckoutReview.aspx especificada no ShortcutExpressCheckout
método . Isso permite que o usuário examine os detalhes do pedido de dentro do aplicativo de exemplo Wingtip Toys.
Depois de retornar do PayPal, a página CheckoutReview.aspx do aplicativo de exemplo Wingtip Toys exibe os detalhes do pedido. Esta página permite que o usuário examine os detalhes do pedido antes de comprar os produtos. A página CheckoutReview.aspx deve ser criada da seguinte maneira:
Na pasta Checkout , abra a página chamada CheckoutReview.aspx.
Substitua a marcação existente pelo seguinte:
<%@ 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>
Abra a página code-behind chamada CheckoutReview.aspx.cs e substitua o código existente pelo seguinte:
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"); } } }
O controle DetailsView é usado para exibir os detalhes do pedido que foram retornados do PayPal. Além disso, o código acima salva os detalhes do pedido no banco de dados Wingtip Toys como um OrderDetail
objeto . Quando o usuário clica no botão Concluir Pedido , ele é redirecionado para a página CheckoutComplete.aspx .
Nota
Dica
Na marcação da página CheckoutReview.aspx , observe que a <ItemStyle>
marca é usada para alterar o estilo dos itens dentro do controle DetailsView próximo à parte inferior da página. Exibindo a página no Modo design (selecionando Design no canto inferior esquerdo do Visual Studio), selecionando o controle DetailsView e selecionando a Marca Inteligente (o ícone de seta no canto superior direito do controle), você poderá ver as Tarefas do DetailsView.
Ao selecionar Editar Campos, a caixa de diálogo Campos será exibida. Nesta caixa de diálogo, você pode controlar facilmente as propriedades visuais, como ItemStyle, do controle DetailsView .
A página CheckoutComplete.aspx faz a compra do PayPal. Conforme mencionado acima, o usuário deve clicar no botão Concluir Pedido antes que o aplicativo navegue até a página CheckoutComplete.aspx .
Na pasta Checkout , abra a página chamada CheckoutComplete.aspx.
Substitua a marcação existente pelo seguinte:
<%@ 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>
Abra a página code-behind chamada CheckoutComplete.aspx.cs e substitua o código existente pelo seguinte:
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"); } } }
Quando a página CheckoutComplete.aspx é carregada, o DoCheckoutPayment
método é chamado. Conforme mencionado anteriormente, o DoCheckoutPayment
método conclui a compra do ambiente de teste do PayPal. Depois que o PayPal concluir a compra do pedido, a página CheckoutComplete.aspx exibirá uma transação ID
de pagamento para o comprador.
Se o usuário decidir cancelar a compra, ele será direcionado para a página CheckoutCancel.aspx , onde verá que o pedido foi cancelado.
Abra a página chamada CheckoutCancel.aspx na pasta Checkout .
Substitua a marcação existente pelo seguinte:
<%@ 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>
Os erros durante o processo de compra serão tratados pela página CheckoutError.aspx . O code-behind da página CheckoutStart.aspx , a página CheckoutReview.aspx e a página CheckoutComplete.aspx serão redirecionado para a página CheckoutError.aspx se ocorrer um erro.
Abra a página chamada CheckoutError.aspx na pasta Checkout .
Substitua a marcação existente pelo seguinte:
<%@ 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>
A página CheckoutError.aspx é exibida com os detalhes do erro quando ocorre um erro durante o processo de check-out.
Execute o aplicativo para ver como comprar produtos. Observe que você estará em execução no ambiente de teste do PayPal. Nenhum dinheiro real está sendo trocado.
Verifique se todos os arquivos foram salvos no Visual Studio.
Abra um navegador da Web e navegue até https://developer.paypal.com.
Faça logon com sua conta de desenvolvedor do PayPal que você criou anteriormente neste tutorial.
Para a área restrita do desenvolvedor do PayPal, você precisa estar conectado em https://developer.paypal.com para testar o check-out expresso. Isso só se aplica ao teste de área restrita do PayPal, não ao ambiente dinâmico do PayPal.No Visual Studio, pressione F5 para executar o aplicativo de exemplo Wingtip Toys.
Depois que o banco de dados for recompilado, o navegador será aberto e mostrará a página Default.aspx .Adicione três produtos diferentes ao carrinho de compras selecionando a categoria de produto, como "Carros" e clicando em Adicionar ao Carrinho ao lado de cada produto.
O carrinho de compras exibirá o produto selecionado.Clique no botão PayPal para fazer check-out.
O check-out exigirá que você tenha uma conta de usuário para o aplicativo de exemplo Wingtip Toys.
Clique no link do Google à direita da página para fazer logon com uma conta de email gmail.com existente.
Se você não tiver uma conta gmail.com, poderá criar uma para fins de teste em www.gmail.com. Você também pode usar uma conta local padrão clicando em "Registrar".Entre com sua conta e senha do Gmail.
Clique no botão Fazer logon para registrar sua conta do Gmail com o nome de usuário do aplicativo de exemplo Wingtip Toys.
No site de teste do PayPal, adicione o endereço de email e a senha do comprador que você criou anteriormente neste tutorial e clique no botão Fazer logon .
Concorde com a política do PayPal e clique no botão Concordar e Continuar .
Observe que esta página só é exibida na primeira vez que você usa essa conta do PayPal. Observe novamente que esta é uma conta de teste, nenhum dinheiro real é trocado.Examine as informações do pedido na página de revisão do ambiente de teste do PayPal e clique em Continuar.
Na página CheckoutReview.aspx , verifique o valor do pedido e exiba o endereço de envio gerado. Em seguida, clique no botão Concluir Pedido .
A página CheckoutComplete.aspx é exibida com uma ID de transação de pagamento.
Ao examinar os dados atualizados no banco de dados de aplicativo de exemplo wingtip toys depois de executar o aplicativo, você pode ver que o aplicativo registrou com êxito a compra dos produtos.
Você pode inspecionar os dados contidos no arquivo de banco de dados Wingtiptoys.mdf usando a janela banco de dados Explorer (janela servidor Explorer no Visual Studio), como você fez anteriormente nesta série de tutoriais.
Feche a janela do navegador se ela ainda estiver aberta.
No Visual Studio, selecione o ícone Mostrar Todos os Arquivos na parte superior do Gerenciador de Soluções para permitir que você expanda a pasta App_Data.
Expanda a pasta App_Data .
Talvez seja necessário selecionar o ícone Mostrar Todos os Arquivos para a pasta.Clique com o botão direito do mouse no arquivo de banco de dados Wingtiptoys.mdf e selecione Abrir.
A Explorer do servidor é exibida.Expanda a pasta Tabelas .
Clique com o botão direito do mouse na tabela Pedidose selecione Mostrar Dados da Tabela.
A tabela Pedidos é exibida.Examine a coluna PaymentTransactionID para confirmar transações bem-sucedidas.
Feche a janela tabela Pedidos .
No servidor Explorer, clique com o botão direito do mouse na tabela OrderDetails e selecione Mostrar Dados da Tabela.
Examine os
OrderId
valores eUsername
na tabela OrderDetails . Observe que esses valores correspondem aosOrderId
valores eUsername
incluídos na tabela Pedidos .Feche a janela da tabela OrderDetails .
Clique com o botão direito do mouse no arquivo de banco de dados Wingtip Toys (Wingtiptoys.mdf) e selecione Fechar Conexão.
Se você não vir a janela Gerenciador de Soluções, clique em Gerenciador de Soluções na parte inferior da janela Explorer servidor para mostrar o Gerenciador de Soluções novamente.
Neste tutorial, você adicionou esquemas de detalhes de pedidos e pedidos para acompanhar a compra de produtos. Você também integrou a funcionalidade do PayPal ao aplicativo de exemplo Wingtip Toys.
Visão geral da configuração do ASP.NET
Implantar um aplicativo de ASP.NET Web Forms seguro com associação, OAuth e Banco de Dados SQL para Serviço de Aplicativo do Azure
Microsoft Azure – Avaliação gratuita
Este tutorial contém o código de exemplo. Esse código de exemplo é fornecido "como está" sem garantia de qualquer tipo. Assim, a Microsoft não garante a precisão, a integridade ou a qualidade do código de exemplo. Você concorda em usar o código de exemplo por sua conta e risco. Sob nenhuma circunstância, a Microsoft será responsável por qualquer código de exemplo, conteúdo, incluindo, mas não se limitando a, quaisquer erros ou omissões em qualquer código de exemplo, conteúdo ou qualquer perda ou dano de qualquer tipo incorrido como resultado do uso de qualquer código de exemplo. Você é notificado e, portanto, concorda em indenizar, salvar e manter a Microsoft inofensiva de e contra toda e qualquer perda, alegações de perda, lesão ou dano de qualquer tipo, incluindo, sem limitação, aquelas ocasionadas ou decorrentes do material que você posta, transmite, usa ou depende de incluir, mas não se limitando, as exibições expressas nela.