ASP.NET Webforms Payment with Stripe

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so we already have a simple episode about implementing stripe checkout with web forms and i've received a few questions about how to implement this uh as just like a simple payment flow that's directly hosted on your own custom asp.net webforms page so i want to just quickly run through how i might implement that i'm not going to interact with the database database at all i don't know you know everyone's database layer is going to vary whether you're using entity framework or directly interacting with the database in some other way so i'm not going to touch the database but we'll talk we'll talk about it and i want to just like go through the patterns that are in asp.net web forms that are different from what you're going to see in asp.net mvc so namely the you know the work that we generally show for stripe integrations with these fetch calls from the client that are making you know ajax calls back to the back end to some page that is going to return or some to some server endpoint that's going to return json it works a little differently um in the asp.net world so i wanted to just kind of walk through that and show that so to to accept a payment we're going to need to do three things we're going to create a payment intent on the server and that is an object that represents the amount and the currency to charge the customer and the way we do this is we're actually going to make an api call from the code behind on page load that's going to be sent to stripe and then stripe is going to return an in an instance of a payment intent object then we're going to collect payment details on the client so on the front end we'll use stripe.js and elements to put a credit card form on the page where the user can enter their credit card details and so we'll collect those and tokenize that and so the the tokenization step is going to send the credit card details directly from the front end to stripe and then stripe will respond with with a payment method and that payment method will be used to confirm the payment intent and depending on the customer's bank if they're located in the european economic area then they might the bank might require 3d secure or some secure customer authentication which is like a next step that's required to authenticate payment and just give permission to collect payment and so i wanted to go through that and then i wanted to also briefly cover how to implement a webhook handler with one of these standard ashx i believe they're called the or that's the extension so um let's jump into it so i'm gonna start just from scratch here we've got visual studio 2019 for mac and i'm going to say i want to create a new asp.net web form project uh okay we'll say next yeah we don't uh we're not gonna write a unit test today so i'm gonna skip that the project name here i'm gonna call it uh accept a payment webform.net.net webform accept a payment we're going to use get and it's just going to live there okay so cool all right so this gives us just a basic page and if we click run and fire this up and take a look at what we get here is the resulting page it just has a button that says click me and when you click it it says you clicked me so coming back over here um the way this is happening is that in the code behind in the c sharp code behind we have this button clicked handler that is running and executing this button text we don't actually want to use that but we are going to use this form in this page to handle our clicking so i just deleted the button click handler on the back end i'm going to remove the on click here and just rename the text of the button to pay okay so before we go too far let's install some dependencies so i'm going to say manage new get references i'm going to add stripe.net this is the stripe client library the sdk the whatever you want to call it that allows us to um interact with the stripe api and make api requests to stripe with our um with within any dotnet code uh the next thing i wanted to do is uh in previous episodes we kind of just like hard coded the secret api key directly into the code behind um i'm not going to go over using app secrets today but you'll want to manage your app secrets carefully and not just hard code your api keys in here i would say go research how to securely manage your api keys so in global.asax when the application runs i'm going to globally set our uh our api key here so i'm going to import the stripe library and i'm going to say stripe configuration.api key is equal to i'm going to just dump in my api key okay i'll paste that there and so this will when the when the application starts it's going to globally set our api key then we don't have to do this on every page where we might use stripe next let's uh let's install the next dependency which is stripe js so this is a client-side library it's going to live in the likely in the head of your html page if you have if you're using um one of the layouts the master the master pages you want to put the stripe you want to import stripe.js on the master page so i'm just going to go to stripe.js the stripe.js documentation here and this is the script tag that we want to use it says including stripe.js here we'll click copy and then we'll dump that directly into the head tag you do not want to use async or defer or anything fancy unless you're super familiar with what you're doing and you're you're sure that the javascript that's running is running in the order that you expect okay so now what i want to do is i'm gonna uh let's see so yeah there's a couple of different ways that we could do this um the way that i'm gonna do it now is just assuming that you already know the amount that the customer is going to pay when they arrive at your page okay so if you don't already know how much they're gonna pay and you need to collect up and build up the context of some cart um you'll have to do this you'll have to like figure out the logic for um building up the cart up to the point where you're going to make the payment but we're going to just assume that um this person is going to pay like you know 100 usd and god i hate that visual studio code like autocompletes the wrong thing there that is okay oh gosh all right so we've got our form we have a button on our form we need a div with the id it doesn't matter what the id is but i like to follow the convention and um watch like if i push the close bracket here if i type the close bracket that okay this is so annoying oh my gosh okay that doesn't make any sense like none of those hotkeys or the order of the keys that i'm pressing make any sense i don't usually work inside of visual studio but i'm trying to because i feel like it's probably most familiar for folks that are working with asp.net web forms so the id of the div that i'm creating here is going to be card element now this div is going to be where the card element is rendered so card element is rendered here okay and all right so let's refresh our page or fire our page back up and take a look okay so you see the the content here card element is rendered here and if we inspect that we see that inside of the contents of this div we are still seeing card element is rendered here so the next step is that we want to write a little bit of javascript on the client that will replace the contents of this and is going to mount a stripe.js element here okay now generally it doesn't really matter where you put this as long as okay so the code that you're writing in this script tag in this inline script tag is going to want to interact with this div element so this div element must be loaded and it must be rendered into the dom or into the browser has to be loaded into the browser before we can uh interact with it and so the way that we do that is we want to listen we're going to like our javascript code that's going to execute immediately is just going to register a listener for an event and that event is going to say when the entire document is loaded execute this function and that looks like this so we're going to say document.add event listener dom content loaded and when this event happens the function like after all of the content is loaded into the dom this function will execute we don't want to execute any of the code that's going to depend on elements that are inside of the page we don't want to run any of that code until the the document is loaded so we're going to listen for dom content loaded then the first thing we need to do is create a variable to hold an instance of the stripe object on the client now this this object can take a number of arguments but at a minimum we have to pass the first argument which is a string and the value of that string is our publishable key okay i'm going to drop that there the next thing we want to do is create an instance of this elements object so we're going to say elements is equal to stripe.elements the next thing we want to do is create a specific element and that is going to be of type card and we're going to mount it on this card element spot here so i'm going to say var card element is equal to elements.create card and then we can say card element.mount and pass in the css selector for this div and so since we're going to use the id we're going to start this with a pound sign and then say card element okay now if we refresh our page you'll see that no longer does it say card element is mounted here and instead we have these controls where we can type in credit card details and notice that there's like all this interactive stuff that's happening you see the card sort of flip around a common test card number is 4242-4242 this is going to be the most common stripe test card we are in test mode okay so we have our element and it's registered but when we click pay nothing happens we're getting we're posting back to default we're posting back and hitting our aspx handler but nothing is happening yet because we haven't created a payment intent and we aren't handling any of the the future steps so let's um this is actually a pretty good start right we're registering the element and that's showing on the page so that is good so i'm going to save this and then i'm going to go to the code behind and here i want to add some some logic for when the page loads so i'm going to say like a protected void page load okay now within these page load within this page load function we can ask is this a postback meaning was a post request received at default.aspx and if a post request was received we're going to do something different than if a get request was received so if if there if it wasn't postback then here we're going to create a payment intent expose its client secret publicly okay and then otherwise um we want to like handle post request from form submission this is likely where you're gonna like uh put the payment information in the database like uh create an order etc etc like you might there's there's a number of different things that you might do when the form is submitted there but here when we want to create the payment intent let's do that like so in this case we are going to import the stripe library again using stripe okay we're going to say var options is a new payment intent create options and the payment intent create options is going to accept the amount which is going to be an integer value in cents the currency which is going to be a string value for the currency and then you might also specify the payment method types and this is going to be a list of strings new list of string and here we just pass card as the payment method type that we're supporting in this case and i probably don't have collection generic yet so using system.collect [Music] okay and now we have some options this is going to be the data that's sent to the stripe api when we're creating a payment intent and again we're going to do this on page load so when someone gets the page before the html is rendered and sent back to the user we are going to make an api call on the server to stripes api and receive back a payment intent object so next we need to create a service we're going to say new payment intent service this is the just like the typical structure for making an api call and then we're going to say var payment intent is equal to service dot create and then we're gonna pass in options now uh the result of this this method call here is gonna be an api call and we're gonna get the response and this object is gonna be an instance of a stripe payment intent now the payment intent is going to have a client secret property and this client secret property is a string value that represents the client secret of this payment intent and we want that on the front end so that we can confirm the payment intent and and pay it so at this point we haven't actually passed in any payment method details yet so we need to pass this client secret back to the client and the way that i'm going to do that in asp.net web forms is i'm going to create a public string called client secret and i'm going to set the value of that client secret equal to the client secret of the payment intent returned from the api call now by making this a public string in the code behind we can then use it on the client in our javascript by using these uh the percent bracket equals actually i'm going to put it down here just so we can see what what it looks like so we'll just say span payment intent id is equal to uh client secret so you should do this too just for testing um as you're building oh my gosh that's annoying holy smokes can i disable that oh visual studio wow that is frustrating okay uh we're going to refresh the page here remove default dot aspx and the name client secret doesn't exist in the current context because i didn't restart the server okay so now we have the payment intent oh i said id but this is it's the client secret so it actually starts with the id of the payment intent and then it has this client secret it's totally cool to pass this back to the client it's fine to share the client secret back with the one customer who's going to pay um this id is not useful this seek the client secret is not useful without the um the api keys that are related to your account so um it is totally cool to have this just embedded in the html and that looks exactly like what we want the next step is to take this client secret and pass that into pass the client secret and then pass this whole card element reference to the entire card element into a method on stripe.js called confirm card payment so we're gonna do that now so here we'll say um yeah so we need to add a uh submission form submission handler so that this form doesn't automatically post back to str uh to the the code behind so i'm gonna change the form id to payment form and save and then i'm gonna say um let's grab reference to the payment form so var form is equal to document dot get element by id payment form so now i'm passing in the id here so you get element by id this payment form id matches this id in here now we're going to say form dot add event listener submit the submit event is what i want to listen for and i'm going to the second argument to add event listener is a function this callback function that will take as its first argument reference to the event that happened and we want to ensure that we're preventing the default so eat up prevent default will make it so that the default for submitting this form back to the server is not done like we don't want it to post back to the server we do want to add method post here i believe not that it matters a ton but the reason why we want to prevent the default is that we need to at this point take the reference of this card element which now has the payment details entered and take the client secret that we were rendering for the payment intent client secret here and we need to confirm that card payment with those payment details so the way this works is we call stripe dot confirm card payment and the first argument is the client secret client secret and we have to put quotes around this because otherwise it'll just render the raw uh value for the client secret into the javascript but this needs to be a string value so we wrap it with quotes single or double doesn't matter javascript doesn't care and then the second argument is going to be this options block where we can say payment method and at a minimum we need to pass the cart reference to the card element now by default you don't have to pass anything else like often times our examples will show billing details and this will include a name and we'll fill it in with a default string jenny rosen right technically you could pass more billing details and indeed you likely want to collect several billing details and you can do so in this form by adding inputs so let's just do that input type is a text and we'll say the id is name and run at equal server and i'm going to set the value to jenny rosen so we don't have to always type it and that should be good okay so this is going to be a text input now in order to pass this name value here and use the name value that was collected in this text input we need to grab reference to that text input box and then pass its value here so before the form is submitted i might say var name input is equal to document.getelement by id name okay that's going to be the name input box and then here instead of passing this raw string in line i can say name dot value all right great so this stripe.confirm card payment is going to return a promise so we can if we're comfortable with using async away in modern javascript we can await this i'm trying to keep this um just es5 in like very traditional so that it should work as expected for most asp.net web form scenarios where you might be in like some old browsers or something okay so i'm going to pass instead of using async await you can also chain on.then and this will take a callback function and that that callback will be um this callback function will be called on the once the confirmed card payment step is done now this call to stripe.confirm card payment again is taking the card details out of the card element they're going to be passed to stripe stripes going to store those securely and or you know work with those securely to tokenize them and it's going to return back a token and if that card also required some next actions then confirm card payment will also present a modal that will collect those details from the user um so we'll take a look at what that looks like so in the result here we we likely want to do a couple of things so if result.error so if the result has an error property then something failed as part of this confirmed card payment step and we need to show the user some error i'm just going to alert result error dot message but in practice you likely want to like make that pretty okay and then otherwise if there is no error then we'll just say console.log like successful payment and that'll be wiped out because we're going to call form dot submit and this call to form.submit is actually going to submit the form back to the code behind which can then take any actions based on what the form what other information the form was collecting so maybe the form was you know some sort of order form where you're picking out a bunch of choices about your product that you're purchasing we know that it's gonna be a hundred dollar pop product but we don't necessarily know do they want the blue one or the yellow one and so you might be passing other data back uh to your code behind all right so at this point we've got our uh our stuff all set up so we when the page is fully loaded we're gonna initialize an instance of stripe we're going to set up some elements okay so this is like set up elements and this is saying like uh when the form is submitted we are going to tokenize payment details and confirm the payment intent all right and then um yeah so we're going to log six if it was a successful payment or not now back let's yeah let's just let's walk through this so if i refresh the page well let's stop start um yeah refresh the page and i'm going to open the so i'm working in chrome here i'm going to right click and say inspect so that i can see what's happening here so i'll make this a little bigger so from the sources tab in your chrome developer tools you can click on a line in the gutter and see what's happening i'm just going to click on line 20 so that we can get into the form submission so you'll notice that we have our name input here jenny rosen is typed in we've got our card element i'm going to enter 4242 and we're going to fill out just like the basic details we'll click pay and that breaks into this click handler it's not submitting it back to the code behind yet we're going to run some javascript first and we we're telling the browser that by calling e.prevent default right here so we know that our our form handler or our form submit handler is actually you know stopping execution in confirm card payment we want to make sure that the client secret is being rendered here and it is and it matches what's what's up there so that's good our cart element still refers to something on the page that's great and so when i click play here this is going to make the request to stripe from the client directly to stripe and then if it worked out we'll get some response so we got back the result here in the result we see a payment intent object and it has all this data and the status is succeeded that means we collected a payment so that is we are already we are already collecting a payment just with with asp.net webform so um there is no error property so we're going to go over to console.log the successful payment and now we're going to form we're going to click form submit and that's going to send a post request back to our back to our code behind okay so that's it that's the whole thing that's how it works you the only thing that's different here on this page is that now we're looking at default.aspx and uh it's hard to tell that it was actually posted back but um it was and even before the the post request was sent back to our server the charge was already completed and already successful that happens on the client and in order to do any sort of fulfillment for this payment we want to implement a webhook handler so when someone successfully pays we just saw that we're going to get back into this callback here that's great but there is a there's a risk that someone clicks pay and then they close the browser tab or their network goes down or something happens where after we know that there is a successful payment there is some disconnection between the the customer's browser in our server and so rather than handling any fulfillment directly from the like success callback of stripe.confirm card payment instead we need to implement a webhook handler so let's go do that next and talk about webhooks okay so a web hook is going to is a tool for a third party to notify you of something happening of some event happening it's a push notification from an api from some third party they're telling you hey payment intent was successful or customer was created or account was updated or whatever right and so when that api call comes from a third party directly to our application there's no ui no user ever sees a web hook okay they don't see anything about the web hook they don't see anything about the event there's no interaction there's no ui this is purely something that is going to be sent from server to server it's an api call from someone else to you and so in order to receive that api call we need to set up a webhook handler so i'm going to create a new file and this is going to be called a web handler with code behind i'm going to name it webhooks okay web handler with code behind click new this creates an ashx file ashx so now we're going to have some route that's called like um you know localhost i think it's eighty eight thousand maybe slash web hooks dot a s h x and uh third parties can send post requests to our endpoint and we're gonna process that request and handle the data that's coming in in this case from stripe so um in order to handle web hooks we have there are some documentation over here web looks build so if you go to web hooks control or like the web hooks documentation on stripe.com you'll see if you go to net there's a whole bunch of stuff here but this is again implemented for asp.net mvc but some of these things are going to apply so the first is that we need to have our endpoint secret so the endpoint secret is the first piece of data that we want um and so let's go find the uh bar endpoint secret as you uh it says this is going to be yeah it's going to be a string value and we're going to test our web hook handler today with um the stripe cli so we're going to say if you want to just get the the endpoint secret you can say stripe listen dash dash print secret and this will give you the a web hook endpoint secret for working with the stripe cli um in practice you can also just say stripe listen dash dash forward to local host and i can i can never remember the port that this is being okay so 8080 slash web hooks dot a-s-h-x okay so now um stripe listen stripe is is a command that comes from the stripe cli the stripe command line tool and by running this command you will set up a direct connection between stripe and your local machine and when events happen on your stripe account they'll be forwarded to this um to this url so a post request will be sent to this url uh when an event happens on your account so this is another way to get the endpoint secret is that when you start the listener it will print it out now the listener is just going to hang that's fine it's listening for and waiting for requests you want to just leave the tab there and leave that running but we do want to put in our web hook endpoint secret here the endpoint secret allows us to verify the authenticity of the request and ensure that it did indeed come from stripe so um all right so we've got our endpoint secret we also need the the raw json payload and so we can say var json is equal to a new stream reader and we want to pass in like the raw request body which is available on context context dot so this http context that was passed in dot request dot input stream and then here we can call read dot read to end i believe okay now this stream reader is coming from something dot io how do we fix this using system.io and then finally we want the signature and that's going to come from context.request.headers stripe signature okay so now we're going to um try to verify the authenticity of this and we need a try catch block okay console.right line e if it fails um throw e all right so while we're trying to uh okay so the function that we want to call is on event utility so this comes with again with stripe.net library i'm going to say var stripe event is equal to event utility okay so now we need we definitely need to import stripe using a stripe um and then we can kill this reference and say eventually.construct event and this is going to take those three arguments so the json the header and then the secret so i'm going to pass in json the signature and the secret endpoint secret all right so that is going to this construct event method on the event utility is taking in the raw json payload it's taking in the signature from the request headers and then it's taking in the endpoint secret that we got for our webhook endpoint now every single webhook endpoint is going to have a unique endpoint secret so if you create multiple from your dashboard they will all have different web hook secrets so you want to make sure that like if you're in dev or if you're in test or ci or whatever you're using the right secret string value this is again something that you likely want to manage you you definitely want to manage it as you would any api keys or secret keys but i would say depend it all depends on your application and how you're handling other secrets so now that we have this stripe event we can switch on its type stripe event dot type and depending on the type case events dot and then there's a whole bunch of stripe events or like web hook event types here tons and tons and tons the one we care about when we're collecting when we're just accepting a payment is payment intent succeeded and i think um i can't remember if it just works like do i have to put a dollar sign in front okay and then here we can just say like stripe event dot type so that'll show us the other event types that we're receiving and then here for payment intent succeeded i just want to show how to like deserialize this so we can say var payment intent we can get the payment intent the actual payment intent object out of uh the stripe event object that we just like constructed this event from or deserialize it into so stripe event.data.object is the data for a payment intent and now we want to cast that to a payment intent and this should allow us to um say like res like payment succeeded and then we can just put like the id of the payment intent maybe um payment intent id and let's also do for and then the the amount so payment intent dot amount okay and why is this red [Music] can fall through oh right and then we have to break right okay it's been a long time since i've used asp.net web from web forms okay cool so we're constructing the event and we're going to switch on its event type um there's a whole bunch of different event types the one we care about in this case is payment intent succeeded we're going to print this out again in practice this is where you might look up the payment in the database and update its state you might also like um fulfill the order you know send a customer email tons of different things that you might do at this point based on this request that you're receiving from stripe okay so let's test it out let's stop this start it again so this webhooks ashx again is not a customer facing thing so customers don't see this page so from the command line from stripe cli you can do stripe trigger and then the name of the event so in this case payment intent dot succeeded and this will take all of the actions through the api to result in a payment intent succeeded event and i see here we're getting 500 so something is failing in our handler let's see if we can figure it out based on the console here let's see if i can make this huh i can't make that bigger all right so what have we got going on uh let's clear it out let's make one more request and all right the signature for the web hook is not present in the signature header so did this not work what's wrong let's say console.rightline signature and consoled uh right line uh signature and then let's restart it just to see where this is coming from or if this is coming through also i forgot one thing and that is that when you start a listener you the events the api version that stripe is using to generate the event json payload is the same is by default the same api version as your account um unless you explicitly set the api version on the webhook endpoint when you're configuring it in the dashboard in the case of stripes cli you can say dash l and this will use the this this will use the latest api version for events we want to use dash l because and we want to make sure that we're using the right api version for our version of stripe.net because stripe.net is pinned to a specific api version and we want to make sure that we're deserializing that json into the correct object types and that will be able to so i'm going to restart this with dash l so that it's using the latest api version then i'm going to re-trigger this payment intent succeeded event and come back over here and see if there's anything different so it looks like the signature is definitely in there the signature for the web hook is not present in the signature header why are we getting that signature for the webpage number stripe signature header huh stripe signature i'm going to try to just put it directly in line here i know that shouldn't have any bearing on it double check this is spilled right okay i mean the we see the signature is there that is the signature that we want to pull out so i don't know what's going on uh okay i'm just going to delete that stop start and this is what is this the right endpoint secret no i don't know how that changed all right let's try this again is that different no huh i must not have copied the whole thing okay so i think my um the endpoint secret that i had was wrong it wasn't it was like only part of it it was missing the last like five characters for some reason let's see if that worked okay so here we go got payment intent uh payment intent created and we get okay so in the log for stripe listen now we see the 200 is coming back so if we trigger the payment intense exceeded event in the stripe list and log we see that payment intent succeeded is firing and in the console in visual studio we can see at the bottom here payment intent succeeded for 20 that's because the test when we say stripe trigger payment intent succeeded it's creating a test payment intent and that was for 20 dollars but that's not necessarily what ours will be so let's go check out hours we're going to refresh the page here and let's also use an sca test card so i'm going to say um sca test is the name of the the customer and then i'm going to use the the card that ends in 3155. this is another stripe test card but this one when you try to pay in test mode it will present you with this modal and this modal will in in production the content of this modal will be presented by the bank by the issuing bank of the customer but in test we're presenting just like a test payment confirmation page from stripe so when we click on complete authentication now our payment is successful and we're redirected back over here now if we go back to our terminal we see that we did receive payment for this uh i guess this one was like yeah 20 and this one's 100 so um okay i think that's all that i wanted to talk about um yeah i hope hopefully this is useful uh if you have questions comments concerns if you have answers to some of the questions that i had while going through this about you know maybe where you put secrets or generally how you might store things in the database would love to see those in the comments and hey if you're liking the content that's on this channel you're finding it useful i would really appreciate a subscribe so uh yeah that's it until next time cheers
Info
Channel: CJ Avilla
Views: 5,033
Rating: undefined out of 5
Keywords: .net core, 3d secure 2, Asp.net webforms, payment gateway integration, payment gateway tutorial, stripe api, PaymentIntent, Stripe, Stripe.net, Stripe-dotnet, Stripe Elements, Credit card
Id: CGpMRtdxvmQ
Channel Id: undefined
Length: 43min 41sec (2621 seconds)
Published: Fri Jan 15 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.