33-3 Intégration de Stripe Checkout
Installer Stripe.net
Stripe propose une librairie pour .NET facilitant la communication avec ses API, en plus d'offrir des objets et fonctions facilitant l'interaction avec Stripe. Il est possible d'installer cette dernière via NuGet
.
- Sous le projet
Mvc
->Manage NuGet Packages
- Rechercher
Stripe.net
- Installer la librairie dans le projet
Mvc
Configurer le service Stripe
La librairie Stripe.net
vient avec un service appelé SessionService
responsable de créer des sessions de Checkout
.
Cependant, pour utiliser ce service, on doit le rendre disponible pour injection de dépendance en plus de configurer Stripe.Net
pour utiliser la clé privée provenant de appsettings
.
Dans Program.cs
du projet MVC, ajoutez à la liste de services disponibles SessionService
et utilisez la clé secrète de appsettings pour la configuration de Stripe
.
// Stripe
builder.Services.AddScoped<SessionService>();
string secretKey = builder.Configuration["Stripe:SecretKey"]!;
StripeConfiguration.ApiKey = secretKey;
IMPORTANT: importez SessionService
de Stripe.Checkout
.
Je propose de mettre l'injection du service directement dans program.cs
plutôt que dans le fichier partagé dans le dossier Shared
puisqu'il s'agit d'une dépendance qui ne sera pas utilisée par les autres projets (ex.: API). En effet, l'achat avec Stripe est propre au projet MVC.
Créer une session Stripe
Tout commence par une session Stripe. Une session vient avec un identifiant unique fourni par Stripe (id
) et les informations de la commande.
C'est ce qui nous permet de rediriger l'utilisateur vers le site de Stripe pour la prise de paiement et que Stripe puisse être en mesure de récupérer le contenu de la commande. En effet, en renvoyant l'utilisateur vers Stripe pour le paiement, on inclut le id
de session unique.
Lorsque le paiement sera effectué, Stripe redirigera vers notre site en incluant le id
de session. C'est ce qui permettra à notre tour de compléter la commande.
-
Dans le contrôleur d'achat, injectez SessionService pour pouvoir l'utiliser et créer une session Stripe. Par exemple:
Snowfall.Web.Mvc/Controllers/AchatsController.csprivate readonly IEvenementService _evenementService;
private readonly IInscriptionService _inscriptionService;
private readonly IPrixService _prixService;
private readonly UserManager<ApplicationUser> _userManager;
private readonly SessionService _stripeSessionService;
public InscriptionsController(
IEvenementService evenementService,
IInscriptionService inscriptionService,
IPrixService prixService,
UserManager<ApplicationUser> userManager,
SessionService stripeSessionService)
{
_evenementService = evenementService;
_inscriptionService = inscriptionService;
_prixService = prixService;
_userManager = userManager;
_stripeSessionService = stripeSessionService;
} -
Toujours dans votre contrôleur d'achat, juste après avoir calculé le prix de la commande, débutez la création d'une session Stripe. Une session Stripe requiert un objet de type
SessionCreateOptions
contenant les options associées à la session: les items, le prix, etc. On crée le tout après avoir calculé le prix puisque nous aurons besoin des informations de prix.Snowfall.Web.Mvc/Controllers/AchatsController.cspublic async Task<IActionResult> Create()
{
//...
Prix prix = _prixService.CalculerPrix(evenement);
var options = new SessionCreateOptions();
Session session = _stripeSessionService.Create(options);
//...
} -
À son strict minimum, les options doivent contenir le mode, une URL de retour en cas de paiement réussi et une URL de retour en cas d'annulation du client. Modifiez pour ajouter ces options.
Snowfall.Web.Mvc/Controllers/AchatsController.csvar options = new SessionCreateOptions
{
Mode = "payment",
SuccessUrl = // URL de retour ici
CancelUrl = // URL en cas d'annulation
};
Session session = _stripeSessionService.Create(options); -
Nous avons déjà une sorte d'URL de succès, soit l'action
Confirmation
du contrôleur, mais rien en cas d'annulation. C'est normal, il n'y avait pas vraiment de concept de paiement, donc aucune façon d'annuler ce processus. Pour supporter ce cas de figure, créez une actionAnnuler
, répondant à une action HTTP de typeGet
et acceptant un identifiant de session stripe en paramètre via son URL.[HttpGet("[Action]")]
public async Task<IActionResult> Annuler([FromQuery] string sessionId)
{
return RedirectToAction("Index", "Evenements");
}infosessionId
sera fourni par Stripe en cas d'annulation. La fonction contiendra plus de code, mais pour l'instant contentons-nous de retourner une redirection vers la page d'accueil.La mention
[FromQuery]
est optionnelle, elle ne fait que préciser que le paramètre proviendra duQuery String
(?sessionId=...
). -
Il est maintenant possible de compléter les URLs de succès et d'annulation dans l'action
Create
puisque les deux actions associées sont en place.var options = new SessionCreateOptions
{
Mode = "payment",
SuccessUrl = Url.Action("Confirmation", "Achats", null, Request.Scheme),
CancelUrl = Url.Action("Annuler", "Achats", null, Request.Scheme)
};infoOn utilise ici
Url.Action
puisqu'il faut une URL complète (incluanthttp://...
). En effet, on envoie ces URL à Stripe et Stripe doit être en mesure de rediriger à son tour vers notre site. Il a donc besoin d'une URL complète -
Ensuite, lorsque le paiement sera complété et que Stripe redirigera vers notre application, on doit obtenir de ce dernier le
id
de session. Pour ce faire, on peut fournir à Stripe dans nos URL de succès et de retour un genre de gabarit d'URL avec une variable qu'il pourra remplacer par le id de session. Cette variable est prédéfinie par Stripe et doit être nommée{CHECKOUT_SESSION_ID}
. Ainsi, modifiez les URL de retour et d'annulation comme suit:var options = new SessionCreateOptions
{
Mode = "payment",
SuccessUrl = Url.Action("Confirmation", "Achats", null , Request.Scheme) + "?sessionId={CHECKOUT_SESSION_ID}",
CancelUrl = Url.Action("Annuler", "Achats", null, Request.Scheme) + "?sessionId={CHECKOUT_SESSION_ID}",
};
Session session = _stripeSessionService.Create(options);infoDans le paramètre d'URL
?sessionId={CHECKOUT_SESSION_ID}
, la portion{CHECKOUT_SESSION_ID}
sera remplacée par un réel identifiant de session et c'est Stripe qui fera cette opération.Au fond, on lui dit que cette portion de l'URL peut être remplacée par son identifiant.
-
Puis, lors de la création du DTO de d'achat, il faut assigner le statut du paiement (En attente) et l'identifiant de la session Stripe ayant été créé. Modifiez la création du DTO dans l'action
Create
pour y inclure ces deux nouveaux attributs.Snowfall.Web.Mvc/Controllers/AchatsController.cs//...
var options = new SessionCreateOptions
{
Mode = "payment",
SuccessUrl = Url.Action("Confirmation", "Inscriptions", null , Request.Scheme) + "?sessionId={CHECKOUT_SESSION_ID}",
CancelUrl = Url.Action("Annuler", "Inscriptions", null, Request.Scheme) + "?sessionId={CHECKOUT_SESSION_ID}",
};
Session session = _stripeSessionService.Create(options);
Inscription inscription = new Inscription
{
UtilisateurId = utilisateur.Id!,
// ...
StatutPaiement = StatutPaiement.Attente,
StripeSessionId = session.Id
};
//... -
Pour la suite, assurez vous que vous ne videz pas le contenu du panier dans la fonction
Create
. En effet, la commande est temporaire à cette étape-ci. Ainsi, si vous avez (vous devriez) une ligne similaire à celle-ci, supprimez-la.//...
// Ligne à retirer si présente!
HttpContext.Session.Remove("Panier");
//... -
Finalement, après l'insertion dans la BD, autrefois on redirigeait vers la page de confirmation directement, mais il est maintenant nécessaire de passer par Stripe afin de prendre le paiement. Redirigez-vers plutôt l'URL fournie par Stripe contenant l'identifiant de session.
//return RedirectToAction("Confirmation", new {id = inscription.Id});
return new RedirectResult(session.Url);
Test
Vous pouvez essayer d'appuyer sur le bouton de confirmation de l'achat (que j'ai renommé "procéder au paiement" dans mon cas pour être plus clair).
Malheureusement, vous obtiendrez l'erreur suivante:
L'erreur nous indique que Stripe, en mode payment
requiers un paramètre line_items
, soit les articles à acheter et leur prix.
En effet, on n'a pas fourni de détails quant au prix ni aux articles! Nous verrons cela à la prochaine étape.