Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
di Erik Reitan
Scaricare il progetto di esempio Wingtip Toys (C#) o Scaricare e-book (PDF)
Questa serie di esercitazioni illustra le nozioni di base per la creazione di un'applicazione Web Form ASP.NET usando ASP.NET 4.5 e Microsoft Visual Studio Express 2013 per Web. Per questa serie di esercitazioni è disponibile un progetto di Visual Studio 2013 con codice sorgente C# .
Questa esercitazione descrive come modificare l'applicazione di esempio Wingtip Toys per includere l'autorizzazione utente, la registrazione e il pagamento tramite PayPal. Solo gli utenti connessi avranno l'autorizzazione per l'acquisto di prodotti. La funzionalità di registrazione utente predefinita del modello di progetto Web Form ASP.NET 4.5 include già molte delle funzionalità necessarie. Aggiungerete la funzionalità di Pagamenti Express di PayPal. In questa esercitazione si sta usando l'ambiente di test per sviluppatori PayPal, quindi non verranno trasferiti fondi effettivi. Alla fine dell'esercitazione si testerà l'applicazione selezionando i prodotti da aggiungere al carrello acquisti, facendo clic sul pulsante di estrazione e trasferendo i dati al sito Web di test PayPal. Nel sito Web di test PayPal confermare le informazioni di spedizione e pagamento e quindi tornare all'applicazione di esempio Wingtip Toys locale per confermare e completare l'acquisto.
Esistono diversi processori di pagamento di terze parti esperti specializzati nello shopping online che rispondono alla scalabilità e alla sicurezza. Gli sviluppatori ASP.NET dovrebbero prendere in considerazione i vantaggi dell'utilizzo di uno strumento di pagamento di terze parti prima di implementare una soluzione di shopping e acquisto.
Annotazioni
L'applicazione di esempio Wingtip Toys è stata progettata per mostrare ASP.NET concetti e funzionalità specifici disponibili per gli sviluppatori Web ASP.NET. Questa applicazione di esempio non è stata ottimizzata per tutte le circostanze possibili in relazione alla scalabilità e alla sicurezza.
Cosa si apprenderà:
- Come limitare l'accesso a pagine specifiche in una cartella.
- Come creare un carrello acquisti noto da un carrello acquisti anonimo.
- Come abilitare SSL per il progetto.
- Come aggiungere un provider OAuth al progetto.
- Come usare PayPal per acquistare prodotti usando l'ambiente di test PayPal.
- Come visualizzare i dettagli da PayPal in un controllo DetailsView .
- Come aggiornare il database dell'applicazione Wingtip Toys con i dettagli ottenuti da PayPal.
Aggiunta del rilevamento degli ordini
In questa esercitazione verranno create due nuove classi per tenere traccia dei dati dall'ordine creato da un utente. Le classi tengono traccia dei dati relativi alle informazioni di spedizione, al totale degli acquisti e alla conferma del pagamento.
Aggiungere le classi del modello Order e OrderDetail
In precedenza in questa serie di esercitazioni è stato definito lo schema per categorie, prodotti e articoli del carrello acquisti creando le Categoryclassi , Producte CartItem nella cartella Models . Ora si aggiungeranno due nuove classi per definire lo schema per l'ordine del prodotto e i dettagli dell'ordine.
Nella cartella Models aggiungere una nuova classe denominata Order.cs.
Il nuovo file di classe viene visualizzato nell'editor.Sostituire il codice predefinito con il codice seguente:
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; } } }Aggiungere una classe OrderDetail.cs alla cartella Models .
Sostituire il codice predefinito con il codice seguente:
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; } } }
Le Order classi e OrderDetail contengono lo schema per definire le informazioni sull'ordine usate per l'acquisto e la spedizione.
Inoltre, sarà necessario aggiornare la classe di contesto del database che gestisce le classi di entità e che fornisce l'accesso ai dati al database. A tale scopo, si aggiungeranno le classi Order e OrderDetail model appena create alla ProductContext classe .
In Esplora soluzioni trovare e aprire il file ProductContext.cs .
Aggiungere il codice evidenziato al file ProductContext.cs come illustrato di seguito:
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; } } }
Come accennato in precedenza in questa serie di esercitazioni, il codice nel file ProductContext.cs aggiunge lo System.Data.Entity spazio dei nomi in modo che sia possibile accedere a tutte le funzionalità di base di Entity Framework. Questa funzionalità include la possibilità di eseguire query, inserire, aggiornare ed eliminare dati usando oggetti fortemente tipizzati. Il codice precedente nella classe ProductContext aggiunge l'accesso a Entity Framework alle classi Order e OrderDetail appena aggiunte.
Aggiunta dell'accesso per l'estrazione
L'applicazione di esempio Wingtip Toys consente agli utenti anonimi di esaminare e aggiungere prodotti a un carrello acquisti. Tuttavia, quando gli utenti anonimi scelgono di acquistare i prodotti aggiunti al carrello acquisti, devono accedere al sito. Una volta effettuato l'accesso, possono accedere alle pagine limitate dell'applicazione Web che gestiscono il processo di checkout e acquisto. Queste pagine con restrizioni sono contenute nella cartella Checkout dell'applicazione.
Aggiungere una cartella di checkout e pagine
Si creerà ora la cartella Checkout e le pagine in esso contenute che il cliente visualizzerà durante il processo di checkout. Queste pagine verranno aggiornate più avanti in questa esercitazione.
Fare clic con il pulsante destro del mouse sul nome del progetto (Wingtip Toys) in Esplora soluzioni e scegliere Aggiungi una nuova cartella.
Assegnare alla nuova cartella il nome Checkout.
Fare clic con il pulsante destro del mouse sulla cartella Checkout e quindi scegliere Aggiungi-Nuovo>elemento.
Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento .
Selezionare il gruppo di modelli Web di Visual C#> a sinistra. Quindi, nel riquadro centrale selezionare Web Form con pagina mastere denominarlo CheckoutStart.aspx.
Come in precedenza, selezionare il file Site.Master come pagina master.
Aggiungere le pagine aggiuntive seguenti alla cartella Checkout usando gli stessi passaggi precedenti:
- CheckoutReview.aspx
- CheckoutComplete.aspx
- CheckoutCancel.aspx
- CheckoutError.aspx
Aggiungere un file Web.config
Aggiungendo un nuovo file Web.config alla cartella Checkout , sarà possibile limitare l'accesso a tutte le pagine contenute nella cartella.
Fare clic con il pulsante destro del mouse sulla cartella Checkout e scegliere Aggiungi ->Nuovo elemento.
Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento .Selezionare il gruppo di modelli Visual C# ->Web a sinistra. Quindi, nel riquadro centrale selezionare File di configurazione Web, accettare il nome predefinito di Web.confige quindi selezionare Aggiungi.
Sostituire il contenuto XML esistente nel file Web.config con quanto segue:
<?xml version="1.0"?> <configuration> <system.web> <authorization> <deny users="?"/> </authorization> </system.web> </configuration>Salvare il file Web.config .
Il fileWeb.config specifica che tutti gli utenti sconosciuti dell'applicazione Web devono essere negati l'accesso alle pagine contenute nella cartella Checkout . Tuttavia, se l'utente ha registrato un account ed è connesso, sarà un utente noto e avrà accesso alle pagine nella cartella Checkout .
È importante notare che ASP.NET configurazione segue una gerarchia, in cui ogni Web.config file applica le impostazioni di configurazione alla cartella in cui si trova e a tutte le directory figlio sottostanti.
Abilitare SSL per il progetto
Secure Sockets Layer (SSL) è un protocollo definito per consentire ai server Web e ai client Web di comunicare in modo più sicuro tramite l'uso della crittografia. Quando SSL non viene usato, i dati inviati tra il client e il server sono aperti per l'analisi dei pacchetti da parte di chiunque disponga dell'accesso fisico alla rete. Inoltre, diversi schemi di autenticazione comuni non sono protetti tramite HTTP normale. In particolare, l'autenticazione di base e l'autenticazione basata su form inviano credenziali non crittografate. Per essere sicuri, questi schemi di autenticazione devono usare SSL.
- In Esplora soluzioni fare clic sul progetto WingtipToys , quindi premere F4 per visualizzare la finestra Proprietà .
- Modificare SSL abilitato in
true. - Copiare l'URL SSL in modo da poterlo usare in un secondo momento.
L'URL SSL saràhttps://localhost:44300/a meno che non siano stati creati in precedenza siti Web SSL (come illustrato di seguito).
- In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto WingtipToys e scegliere Proprietà.
- Nella scheda a sinistra fare clic su Web.
- Modificare l'URL del progetto per usare l'URL SSL salvato in precedenza.
- Salvare la pagina premendo CTRL+S.
- Premere CTRL+F5 per eseguire l'applicazione. Visual Studio visualizzerà un'opzione che consente di evitare avvisi SSL.
- Fare clic su Sì per considerare attendibile il certificato SSL di IIS Express e continuare.
Viene visualizzato un avviso di sicurezza. - Fare clic su Sì per installare il certificato in localhost.
Verrà visualizzata la finestra del browser.
È ora possibile testare facilmente l'applicazione Web in locale usando SSL.
Aggiungere un provider OAuth 2.0
ASP.NET Web Form offre opzioni avanzate per l'appartenenza e l'autenticazione. Questi miglioramenti includono OAuth. OAuth è un protocollo aperto che consente l'autorizzazione sicura in un metodo semplice e standard da applicazioni Web, per dispositivi mobili e desktop. Il modello web form ASP.NET usa OAuth per esporre Facebook, Twitter, Google e Microsoft come provider di autenticazione. Anche se questa esercitazione usa solo Google come provider di autenticazione, è possibile modificare facilmente il codice per usare uno dei provider. I passaggi per implementare altri provider sono molto simili ai passaggi illustrati in questa esercitazione.
Oltre all'autenticazione, il tutorial utilizzerà anche i ruoli per implementare l'autorizzazione. Solo gli utenti aggiunti al ruolo potranno modificare i canEdit dati (creare, modificare o eliminare i contatti).
Annotazioni
Le applicazioni Windows Live accettano solo un URL live per un sito Web funzionante, quindi non è possibile usare un URL del sito Web locale per testare gli account di accesso.
La procedura seguente consentirà di aggiungere un provider di autenticazione Google.
Aprire il file App_Start\Startup.Auth.cs .
Rimuovere i caratteri di commento dal
app.UseGoogleAuthentication()metodo in modo che il metodo venga visualizzato come segue:app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() { ClientId = "", ClientSecret = "" });Vai a Google Developers Console. Dovrai anche accedere con il tuo account di posta elettronica per sviluppatori Google (gmail.com). Se non si ha un account Google, selezionare il collegamento Crea un account .
A questo punto, vedrai Google Developers Console.
Fare clic sul pulsante Crea progetto e immettere un nome e un ID del progetto (è possibile usare i valori predefiniti). Fare quindi clic sulla casella di controllo Contratto e sul pulsante Crea .
In pochi secondi verrà creato il nuovo progetto e il browser visualizzerà la pagina dei nuovi progetti.
Nella scheda a sinistra fare clic su API e autenticazione e quindi su Credenziali.
Fare clic su Crea nuovo ID client in OAuth.
Verrà visualizzata la finestra di dialogo Crea ID client .
Nella finestra di dialogo Crea ID client mantenere l'applicazione Web predefinita per il tipo di applicazione.
Imposta le Origini JavaScript autorizzate sull'URL SSL che hai utilizzato in precedenza in questo tutorial (
https://localhost:44300/a meno che tu non abbia creato altri progetti SSL).
Questo URL è l'origine dell'applicazione. Per questo esempio, si immetterà solo l'URL del test localhost. Tuttavia, è possibile immettere più URL per tenere conto di localhost e produzione.Impostare l'URI di reindirizzamento autorizzato su quanto segue:
https://localhost:44300/signin-googleQuesto valore è l'URI che gli utenti OAuth di ASP.NET utilizzano per comunicare con il server OAuth di Google. Ricordare l'URL SSL usato in precedenza (
https://localhost:44300/a meno che non siano stati creati altri progetti SSL).Fare clic sul pulsante Create Client ID (Crea ID client).
Nel menu a sinistra di Google Developers Console fare clic sulla voce di menu Consent screen (Consenso ), quindi impostare l'indirizzo di posta elettronica e il nome del prodotto. Dopo aver completato il modulo, fare clic su Salva.
Fare clic sulla voce di menu API , scorrere verso il basso e fare clic sul pulsante disattivato accanto all'API Google+.
Accettando questa opzione si abiliterà l'API Google+.È anche necessario aggiornare il pacchetto NuGet Microsoft.Owin alla versione 3.0.0.
Dal menu Strumenti selezionare Gestione pacchetti NuGet e quindi selezionare Gestisci pacchetti NuGet per soluzione.
Nella finestra Gestisci pacchetti NuGet trovare e aggiornare il pacchetto Microsoft.Owin alla versione 3.0.0.In Visual Studio aggiornare il
UseGoogleAuthenticationmetodo della pagina Startup.Auth.cs copiando e incollando l'ID client e il segreto client nel metodo . I valori id client e segreto client illustrati di seguito sono esempi e non funzioneranno.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" }); } } }Premere CTRL+F5 per compilare ed eseguire l'applicazione. Fare clic sul collegamento Accedi .
In Usa un altro servizio per accedere fare clic su Google.
Se è necessario immettere le credenziali, si verrà reindirizzati al sito google in cui si immetteranno le credenziali.
Dopo aver immesso le credenziali, verrà richiesto di concedere le autorizzazioni all'applicazione Web appena creata.
Fare clic su Accetto. A questo punto si verrà reindirizzati alla pagina Registra dell'applicazione WingtipToys in cui è possibile registrare il proprio account Google.
Hai la possibilità di modificare il nome di registrazione della posta elettronica locale usato per il tuo account Gmail, ma in genere vuoi mantenere l'alias di posta elettronica predefinito (ovvero quello usato per l'autenticazione). Fare clic su Accedi come illustrato in precedenza.
Modifica della funzionalità di accesso
Come accennato in precedenza in questa serie di esercitazioni, gran parte delle funzionalità di registrazione utente è stata inclusa nel modello web form ASP.NET per impostazione predefinita. Modificherai le pagine predefinite Login.aspx e Register.aspx per chiamare il metodo MigrateCart. Il MigrateCart metodo associa un utente appena connesso a un carrello acquisti anonimo. Associando l'utente e il carrello acquisti, l'applicazione di esempio Wingtip Toys sarà in grado di mantenere il carrello acquisti dell'utente tra le visite.
In Esplora soluzioni trovare e aprire la cartella Account .
Modificare la pagina code-behind denominata Login.aspx.cs per includere il codice evidenziato in giallo, in modo che venga visualizzato come segue:
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; } } } } }Salvare il file Login.aspx.cs .
Per il momento, è possibile ignorare l'avviso che non esiste alcuna definizione per il MigrateCart metodo . Verrà aggiunta un po' più avanti in questa esercitazione.
Il file code-behind Login.aspx.cs supporta un metodo LogIn. Esaminando la pagina Login.aspx, si noterà che questa pagina include un pulsante "Accedi" che quando si fa clic attiva il LogIn gestore nel code-behind.
Quando viene chiamato il Login metodo sul Login.aspx.cs , viene creata una nuova istanza del carrello acquisti denominato usersShoppingCart . L'ID del carrello acquisti (GUID) viene recuperato e impostato sulla cartId variabile . Viene quindi chiamato il metodo MigrateCart, passando sia il cartId che il nome dell'utente connesso. Quando viene eseguita la migrazione del carrello acquisti, il GUID usato per identificare il carrello acquisti anonimo viene sostituito con il nome utente.
Oltre a modificare il file code-behind Login.aspx.cs per eseguire la migrazione del carrello acquisti quando l'utente accede, è necessario modificare anche il file code-behind Register.aspx.cs per eseguire la migrazione del carrello acquisti quando l'utente crea un nuovo account e accede.
Nella cartella Account aprire il file code-behind denominato Register.aspx.cs.
Modificare il file code-behind includendo il codice in giallo, in modo che venga visualizzato come segue:
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(); } } } }Salvare il file Register.aspx.cs . Anche in questo caso, ignorare l'avviso relativo al
MigrateCartmetodo .
Si noti che il codice usato nel CreateUser_Click gestore eventi è molto simile al codice usato nel LogIn metodo . Quando l'utente registra o accede al sito, verrà effettuata una chiamata al MigrateCart metodo .
Migrazione del carrello acquisti
Dopo aver aggiornato il processo di accesso e registrazione, è possibile aggiungere il codice per eseguire la migrazione del carrello acquisti usando il MigrateCart metodo .
In Esplora soluzioni individuare la cartella Logic e aprire il file di classe ShoppingCartActions.cs .
Aggiungere il codice evidenziato in giallo al codice esistente nel file ShoppingCartActions.cs , in modo che il codice nel file ShoppingCartActions.cs venga visualizzato come segue:
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(); } } }
Il MigrateCart metodo usa il cartId esistente per trovare il carrello acquisti dell'utente. Successivamente, il codice scorre tutti gli elementi del carrello acquisti e sostituisce la CartId proprietà (come specificato dallo CartItem schema) con il nome utente connesso.
Aggiornamento della connessione al database
Se si segue questa esercitazione usando l'applicazione di esempio Predefinita Wingtip Toys, è necessario ricreare il database di appartenenza predefinito. Modificando la stringa di connessione predefinita, il database di appartenenza verrà creato alla successiva esecuzione dell'applicazione.
Aprire il file Web.config nella radice del progetto.
Aggiornare la stringa di connessione predefinita in modo che venga visualizzata come segue:
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=aspnet-WingtipToys;Integrated Security=True" providerName="System.Data.SqlClient" />
Integrazione di PayPal
PayPal è una piattaforma di fatturazione basata sul Web che accetta pagamenti da parte dei commercianti online. Questa esercitazione illustra quindi come integrare la funzionalità Express Checkout di PayPal nell'applicazione. Express Checkout consente ai clienti di usare PayPal di pagare gli articoli aggiunti al carrello acquisti.
Creare account di test PayPal
Per usare l'ambiente di test PayPal, è necessario creare e verificare un account di test per sviluppatori. Si userà l'account di test per sviluppatore per creare un account di test acquirente e un account di test venditore. Le credenziali dell'account di test per sviluppatori consentiranno anche all'applicazione di esempio Wingtip Toys di accedere all'ambiente di test PayPal.
In un browser passare al sito di test per sviluppatori PayPal:
https://developer.paypal.comSe non si ha un account sviluppatore PayPal, creare un nuovo account facendo clic su Iscrivitie seguendo la procedura di iscrizione. Se si dispone di un account sviluppatore di PayPal esistente, accedere facendo clic su Accedi. Sarà necessario l'account per sviluppatore PayPal per testare l'applicazione di esempio Wingtip Toys più avanti in questa esercitazione.
Se si è appena effettuato l'iscrizione per l'account sviluppatore PayPal, potrebbe essere necessario verificare l'account sviluppatore PayPal con PayPal. Puoi verificare il tuo account seguendo i passaggi che PayPal ha inviato al tuo account di posta elettronica. Dopo aver verificato l'account sviluppatore PayPal, accedere di nuovo al sito di test per sviluppatori PayPal.
Dopo aver eseguito l'accesso al sito per sviluppatori PayPal con l'account sviluppatore PayPal è necessario creare un account di test PayPal buyer se non ne hai già uno. Per creare un account di test dell'acquirente, nel sito PayPal fare clic sulla scheda Applicazioni e quindi su Conti Sandbox.
Viene visualizzata la pagina account di test Sandbox.Annotazioni
Il sito PayPal Developer fornisce già un account di test commerciante.
Nella pagina degli account di test Sandbox, fai clic su Crea Account.
Nella pagina Crea account di test scegliere un indirizzo di posta elettronica e una password per l'account di test dell'acquirente a scelta.
Annotazioni
Saranno necessari gli indirizzi di posta elettronica dell'acquirente e la password per testare l'applicazione di esempio Wingtip Toys alla fine di questa esercitazione.
Creare l'account di test dell'acquirente facendo clic sul pulsante Crea account .
Viene visualizzata la pagina Account di test Sandbox.
Nella pagina Account di test Sandbox, cliccare sull'email del facilitatore.
Vengono visualizzate le opzioni profilo e notifica .Selezionare l'opzione Profilo , quindi fare clic su Credenziali API per visualizzare le credenziali API per l'account di test commerciante.
Copiare le credenziali dell'API TEST nel Blocco note.
Saranno necessarie le credenziali dell'API TEST classica (nome utente, password e firma) per effettuare chiamate API dall'applicazione di esempio Wingtip Toys all'ambiente di test PayPal. Le credenziali verranno aggiunte nel passaggio successivo.
Aggiungere PayPal classi e credenziali API
La maggior parte del codice PayPal verrà inserita in una singola classe. Questa classe contiene i metodi usati per comunicare con PayPal. Inoltre, aggiungerai le tue credenziali PayPal a questa classe.
Nell'applicazione di esempio Wingtip Toys in Visual Studio fare clic con il pulsante destro del mouse sulla cartella Logica e quindi scegliere Aggiungi ->Nuovo elemento.
Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento .In Visual C# dal riquadro Installato a sinistra selezionare Codice.
Nel riquadro centrale selezionare Classe. Assegnare alla nuova classe il nome PayPalFunctions.cs.
Fare clic su Aggiungi.
Il nuovo file di classe viene visualizzato nell'editor.Sostituire il codice predefinito con il codice seguente:
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; } }Aggiungere le credenziali dell'API Merchant (Nome utente, Password e Firma) visualizzate in precedenza in questa esercitazione in modo da poter effettuare chiamate di funzione all'ambiente di test PayPal.
public string APIUsername = "<Your API Username>"; private string APIPassword = "<Your API Password>"; private string APISignature = "<Your Signature>";
Annotazioni
In questa applicazione di esempio si stanno semplicemente aggiungendo credenziali a un file C# (.cs). Tuttavia, in una soluzione implementata, è consigliabile crittografare le credenziali in un file di configurazione.
La classe NVPAPICaller contiene la maggior parte delle funzionalità di PayPal. Il codice nella classe fornisce i metodi necessari per effettuare un acquisto di test dall'ambiente di test PayPal. Per effettuare acquisti vengono usate le tre funzioni di PayPal seguenti:
- Funzione
SetExpressCheckout - Funzione
GetExpressCheckoutDetails - Funzione
DoExpressCheckoutPayment
Il ShortcutExpressCheckout metodo raccoglie le informazioni sull'acquisto di test e i dettagli del prodotto dal carrello acquisti e chiama la SetExpressCheckout funzione PayPal. Il GetCheckoutDetails metodo conferma i dettagli dell'acquisto e chiama la GetExpressCheckoutDetails funzione PayPal prima di effettuare l'acquisto di test. Il DoCheckoutPayment metodo completa l'acquisto di prova dall'ambiente di test chiamando la funzione DoExpressCheckoutPayment PayPal. Il codice rimanente supporta i metodi e il processo di PayPal, ad esempio le stringhe di codifica, la decodifica di stringhe, l'elaborazione di matrici e la determinazione delle credenziali.
Annotazioni
PayPal consente di includere i dettagli di acquisto facoltativi in base alla specifica API di PayPal. Estendendo il codice nell'applicazione di esempio Wingtip Toys, è possibile includere dettagli di localizzazione, descrizioni dei prodotti, imposte, un numero di servizio clienti e molti altri campi facoltativi.
Si noti che gli URL di ritorno e di annullamento specificati nel metodo ShortcutExpressCheckout usano un numero di porta.
string returnURL = "https://localhost:44300/Checkout/CheckoutReview.aspx";
string cancelURL = "https://localhost:44300/Checkout/CheckoutCancel.aspx";
Quando Visual Web Developer esegue un progetto Web tramite SSL, in genere viene usata la porta 44300 per il server Web. Come illustrato in precedenza, il numero di porta è 44300. Quando si esegue l'applicazione, è possibile visualizzare un numero di porta diverso. Il numero di porta deve essere impostato correttamente nel codice in modo da poter eseguire correttamente l'applicazione di esempio Wingtip Toys alla fine di questa esercitazione. La sezione successiva di questa esercitazione illustra come recuperare il numero di porta host locale e aggiornare la classe PayPal.
Aggiornare il numero di porta LocalHost nella classe PayPal
L'applicazione di esempio Wingtip Toys acquista prodotti navigando al sito di test PayPal e ritornando all'istanza locale dell'applicazione di esempio Wingtip Toys. Per poter PayPal tornare all'URL corretto, è necessario specificare il numero di porta dell'applicazione di esempio in esecuzione in locale nel codice PayPal indicato in precedenza.
Fare clic con il pulsante destro del mouse sul nome del progetto (WingtipToys) in Esplora soluzioni e scegliere Proprietà.
Nella colonna a sinistra selezionare la scheda Web .
Recuperare il numero di porta dalla casella URL progetto .
Se necessario, aggiornare
returnURLecancelURLnella classe PayPal (NVPAPICaller) nel file PayPalFunctions.cs per usare il numero di porta dell'applicazione Web:string returnURL = "https://localhost:<Your Port Number>/Checkout/CheckoutReview.aspx"; string cancelURL = "https://localhost:<Your Port Number>/Checkout/CheckoutCancel.aspx";
A questo punto, il codice aggiunto corrisponderà alla porta prevista per l'applicazione Web locale. PayPal sarà in grado di tornare all'URL corretto nel computer locale.
Aggiungere il pulsante di Checkout PayPal
Ora che le funzioni PayPal primarie sono state aggiunte all'applicazione di esempio, è possibile iniziare ad aggiungere il markup e il codice necessari per chiamare queste funzioni. In primo luogo, è necessario aggiungere il pulsante di checkout che l'utente vedrà nella pagina del carrello acquisti.
Aprire il file ShoppingCart.aspx .
Scorrere fino alla fine del file e trovare il
<!--Checkout Placeholder -->commento.Sostituire il commento con un controllo
ImageButtonin modo che il markup venga sostituito nel modo seguente:<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" />Nel file ShoppingCart.aspx.cs , dopo il
UpdateBtn_Clickgestore eventi vicino alla fine del file, aggiungere ilCheckOutBtn_Clickgestore eventi:protected void CheckoutBtn_Click(object sender, ImageClickEventArgs e) { using (ShoppingCartActions usersShoppingCart = new ShoppingCartActions()) { Session["payment_amt"] = usersShoppingCart.GetTotal(); } Response.Redirect("Checkout/CheckoutStart.aspx"); }Nel file ShoppingCart.aspx.cs aggiungere anche un riferimento a
CheckoutBtn, in modo che venga fatto riferimento al pulsante nuova immagine come indicato di seguito: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; } } }Salvare le modifiche sia nel file ShoppingCart.aspx che nel file ShoppingCart.aspx.cs .
Dal menu selezionare Debug-Build>WingtipToys.
Il progetto verrà ricompilato con il controllo ImageButton che è stato appena aggiunto.
Invia dettagli acquisto a PayPal
Quando l'utente fa clic sul pulsante Checkout nella pagina del carrello acquisti (ShoppingCart.aspx), inizierà il processo di acquisto. Il codice seguente chiama la prima funzione PayPal necessaria per acquistare i prodotti.
Dalla cartella Checkout, apri il file code-behind chiamato CheckoutStart.aspx.cs.
Assicurati di aprire il file code-behind.Sostituire il codice esistente con quello seguente:
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 l'utente dell'applicazione fa clic sul pulsante Checkout nella pagina del carrello acquisti, il browser passerà alla pagina CheckoutStart.aspx . Quando viene caricata la pagina CheckoutStart.aspx , viene chiamato il ShortcutExpressCheckout metodo . A questo punto, l'utente viene trasferito al sito Web di test PayPal. Nel sito PayPal, l'utente immette le credenziali di PayPal, esamina i dettagli di acquisto, accetta il contratto di PayPal e torna all'applicazione di esempio Wingtip Toys in cui viene completato il ShortcutExpressCheckout metodo. Al termine del ShortcutExpressCheckout metodo, reindirizzerà l'utente alla pagina CheckoutReview.aspx specificata nel ShortcutExpressCheckout metodo . In questo modo l'utente può esaminare i dettagli dell'ordine dall'interno dell'applicazione di esempio Wingtip Toys.
Esaminare i dettagli dell'ordine
Dopo la restituzione da PayPal, nella pagina CheckoutReview.aspx dell'applicazione di esempio Wingtip Toys vengono visualizzati i dettagli dell'ordine. Questa pagina consente all'utente di esaminare i dettagli dell'ordine prima di acquistare i prodotti. La pagina CheckoutReview.aspx deve essere creata nel modo seguente:
Nella cartella Checkout aprire la pagina denominata CheckoutReview.aspx.
Sostituire il markup esistente con quanto segue:
<%@ 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>Aprire la pagina code-behind denominata CheckoutReview.aspx.cs e sostituire il codice esistente con il codice seguente:
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"); } } }
Il controllo DetailsView viene utilizzato per visualizzare i dettagli dell'ordine restituiti da PayPal. Inoltre, il codice precedente salva i dettagli dell'ordine nel database Wingtip Toys come OrderDetail oggetto . Quando l'utente fa clic sul pulsante Completa ordine , viene reindirizzato alla pagina CheckoutComplete.aspx .
Annotazioni
Suggerimento
Nel markup della pagina CheckoutReview.aspx si noti che il <ItemStyle> tag viene usato per modificare lo stile degli elementi all'interno del controllo DetailsView nella parte inferiore della pagina. Visualizzando la pagina in Visualizzazione struttura (selezionando Progettazione nell'angolo inferiore sinistro di Visual Studio), quindi selezionando il controllo DetailsView e selezionando Smart Tag (l'icona a forma di freccia in alto a destra del controllo), sarà possibile visualizzare le DetailsView Tasks.
Selezionando Modifica campi, verrà visualizzata la finestra di dialogo Campi . In questa finestra di dialogo è possibile controllare facilmente le proprietà visive, ad esempio ItemStyle, del controllo DetailsView .
Completa l'acquisto
CheckoutComplete.aspx pagina effettua l'acquisto da PayPal. Come indicato in precedenza, l'utente deve fare clic sul pulsante Completa ordine prima che l'applicazione passi alla pagina CheckoutComplete.aspx .
Nella cartella Checkout aprire la pagina denominata CheckoutComplete.aspx.
Sostituire il markup esistente con quanto segue:
<%@ 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>Aprire la pagina code-behind denominata CheckoutComplete.aspx.cs e sostituire il codice esistente con il codice seguente:
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 viene caricata la pagina CheckoutComplete.aspx , viene chiamato il DoCheckoutPayment metodo . Come accennato in precedenza, il metodo DoCheckoutPayment completa l'acquisto dall'ambiente di test di PayPal. Una volta PayPal completato l'acquisto dell'ordine, nella pagina CheckoutComplete.aspx viene visualizzata una transazione ID di pagamento all'acquirente.
Gestire l'annullamento dell'acquisto
Se l'utente decide di annullare l'acquisto, verrà indirizzato alla pagina CheckoutCancel.aspx in cui noterà che l'ordine è stato annullato.
Aprire la pagina denominata CheckoutCancel.aspx nella cartella Checkout .
Sostituire il markup esistente con quanto segue:
<%@ 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>
Gestire gli errori di acquisto
Gli errori durante il processo di acquisto verranno gestiti dalla pagina CheckoutError.aspx . Il code-behind della pagina CheckoutStart.aspx , la pagina CheckoutReview.aspx e la pagina CheckoutComplete.aspx reindirizzeranno ogni pagina alla pagina CheckoutError.aspx in caso di errore.
Aprire la pagina denominata CheckoutError.aspx nella cartella Checkout .
Sostituire il markup esistente con quanto segue:
<%@ 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 pagina CheckoutError.aspx viene visualizzata con i dettagli dell'errore quando si verifica un errore durante il processo di pagamento.
Esecuzione dell'applicazione
Eseguire l'applicazione per vedere come acquistare prodotti. Si noti che l'esecuzione verrà eseguita nell'ambiente di test PayPal. Nessun denaro effettivo viene scambiato.
Assicurarsi che tutti i file vengano salvati in Visual Studio.
Aprire un Web browser e passare a https://developer.paypal.com.
Accedere con l'account sviluppatore PayPal creato in precedenza in questa esercitazione.
Per la sandbox per sviluppatori di PayPal, è necessario eseguire l'accesso all'indirizzo https://developer.paypal.com per testare il checkout rapido. Questo vale solo per il test sandbox di PayPal, non per l'ambiente live di PayPal.In Visual Studio premere F5 per eseguire l'applicazione di esempio Wingtip Toys.
Dopo la ricompilazione del database, il browser aprirà e mostrerà la pagina Default.aspx .Aggiungere tre prodotti diversi al carrello selezionando la categoria di prodotti, ad esempio "Automobili" e quindi facendo clic su Aggiungi al carrello accanto a ogni prodotto.
Il carrello acquisti visualizzerà il prodotto selezionato.Fare clic sul pulsante PayPal per eseguire il checkout.
Il check-out richiederà di disporre di un account utente per l'applicazione di esempio Wingtip Toys.
Fare clic sul collegamento Google a destra della pagina per accedere con un account di posta elettronica gmail.com esistente.
Se non si dispone di un account gmail.com, è possibile crearne uno a scopo di test in www.gmail.com. È anche possibile usare un account locale standard facendo clic su "Registra".
Accedi con il tuo account Gmail e la password.
Fare clic sul pulsante Accedi per registrare l'account gmail con il nome utente dell'applicazione di esempio Wingtip Toys.
Nel sito di test di PayPal aggiungere l'indirizzo di posta elettronica dell'acquirente e la password creati in precedenza in questa esercitazione, quindi fare clic sul pulsante Accedi .
Accettare il criterio di PayPal e fare clic sul pulsante Accetta e continua .
Si noti che questa pagina viene visualizzata solo la prima volta che si usa questo account PayPal. Ancora una volta si noti che questo è un conto di prova, non viene scambiato alcun denaro reale.
Esaminare le informazioni sull'ordine nella pagina di revisione dell'ambiente di test PayPal e fare clic su Continua.
Nella pagina CheckoutReview.aspx verificare l'importo dell'ordine e visualizzare l'indirizzo di spedizione generato. Fare quindi clic sul pulsante Completa ordine .
La pagina CheckoutComplete.aspx viene visualizzata con un ID transazione di pagamento.
Revisione del database
Esaminando i dati aggiornati nel database dell'applicazione di esempio Wingtip Toys dopo l'esecuzione dell'applicazione, è possibile vedere che l'applicazione ha registrato correttamente l'acquisto dei prodotti.
È possibile esaminare i dati contenuti nel file di database Wingtiptoys.mdf usando la finestra Esplora database (finestra Esplora server in Visual Studio) come illustrato in precedenza in questa serie di esercitazioni.
Chiudere la finestra del browser se è ancora aperta.
In Visual Studio selezionare l'icona Mostra tutti i file nella parte superiore di Esplora soluzioni per consentire di espandere la cartella App_Data .
Espandi la cartella App_Data.
Potrebbe essere necessario selezionare l'icona Mostra tutti i file per la cartella.Fare clic con il pulsante destro del mouse sul file di database Wingtiptoys.mdf e scegliere Apri.
Esplora server è visualizzato.Espandere la cartella Tabelle .
Fare clic con il pulsante destro del mouse sulla tabella Orderse selezionare Mostra dati tabella.
Viene visualizzata la tabella Orders .Esaminare la colonna PaymentTransactionID per confermare le transazioni riuscite.
Chiudere la finestra della tabella Orders .
Nell'Esplora server, fare clic con il pulsante destro del mouse sulla tabella OrderDetails e selezionare Mostra dati tabella.
Esaminare i valori
OrderIdeUsernamenella tabella OrderDetails. Si noti che questi valori corrispondono ai valoriOrderIdeUsernameinclusi nella tabella Orders.Chiudere la finestra della tabella OrderDetails .
Fare clic con il pulsante destro del mouse sul file di database Wingtip Toys (Wingtiptoys.mdf) e scegliere Chiudi connessione.
Se la finestra Esplora soluzioni non viene visualizzata, fare clic su Esplora soluzioni nella parte inferiore della finestra Esplora server per visualizzare nuovamente Esplora soluzioni .
Sommario
In questa esercitazione sono stati aggiunti schemi di ordine e dettagli dell'ordine per monitorare l'acquisto dei prodotti. Hai anche integrato la funzionalità PayPal nell'applicazione Wingtip Toys di esempio.
Risorse aggiuntive
Panoramica della configurazione di ASP.NET
Distribuire un'app Web Form ASP.NET sicura con appartenenza, OAuth e database SQL nel servizio app di Azure
Microsoft Azure - Versione di valutazione gratuita
Dichiarazione di non responsabilità
Questa esercitazione contiene codice di esempio. Tale codice di esempio viene fornito "così com'è" senza garanzia di alcun tipo. Di conseguenza, Microsoft non garantisce l'accuratezza, l'integrità o la qualità del codice di esempio. Si accetta di usare il codice di esempio a proprio rischio. In nessuna circostanza Microsoft sarà responsabile in alcun modo per qualsiasi codice di esempio, contenuto, incluso ma non limitato, eventuali errori o omissioni in qualsiasi codice di esempio, contenuto o qualsiasi perdita o danno di qualsiasi tipo incorrere in seguito all'uso di qualsiasi codice di esempio. Si informa l'utente e questi accetta di indennizzare, sollevare e manlevare Microsoft da e contro qualsiasi perdita, richiesta di risarcimento per perdita, infortunio o danno di qualsiasi tipo, inclusi, senza limitazioni, quelli causati o derivanti da materiale che l'utente pubblica, trasmette, utilizza o su cui fa affidamento, comprese, ma non limitatamente alle opinioni espresse.