Trying over a week so far with no success, to find out why I can’t get the response from my controller.
- Note I am not fluent in JS, only C#, but I already have a good understanding of what the fetch does.
- Now learning ASP.NET Core, but still somewhere under junior level in my overall C# and .Net experience maybe.
- It is regarding the process of redirecting to Stripe checkout, but fetch and the method as mentioned, can’t agree around 200.
- Originally the controller was a normal MVC controller but among many things tried, I made it also an API controller, hoping something which I apparently don’t understand, might fix the issue with its method.
Turned over the web upside down searching for similar issues, and I have no other options except reaching to you guys, many experienced devs here. - The method functions 100%, I mean the logic inside. It returns a session object.
The API version returns the session; the MVC version returnsthis.Json(session);
I know that both versions work because I was debugging them by entering inside after a button click - Its all happening on localhost, therefore I provided
credentials: 'include'
in the headers… if I am correct. - Trying anything with Postman with authorization of course, but no luck so far.
- Firefox Debugging currently throws no errors when going through the fetch.
The Questions:
– Does the fetch function properly according to my code?
– Is the controller prepared to get the payment id from the JSON body of the request?
– When I hardcode the paymentId inside the controller so that I don’t expect any parameter, why this doesn’t work as well (the fetch has session undefined)?
Here is the fetch in my Pay.cshtml view
<script src="https://js.stripe.com/v3/"></script>
<div id="checkout">
<form id="payment-form">
<div class="row d-flex justify-content-center">
<div class="col-6 py-4 text-center">
<button id="checkout-button"
value="Pay"
class="btn btn-sm btn-labeled btn-primary">
<span class="btn-label">
<ion-icon name="card-outline"></ion-icon>
</span>Pay $ @Model.Amount
</button>
</div>
</div>
</form>
</div>
<script>
var stripe = Stripe('@HomyTestPublishableKey');
var payButton = document.getElementById('checkout-button');
payButton.addEventListener('click', function(event) {
event.preventDefault();
stripe.redirectToCheckout({
sessionId: sessionId
});
});
var sessionId;
var paymentId = '@Model.Id';
fetch("/api/payment/createsession/", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify({id: paymentId })
}).then(function(r) {
return r.json();
}).then(function(response) {
sessionId = response.id;
})
.catch(error => console.error('Error:', error));
</script>
The method in the API Controller looks like this:
// Create PaymentSession
[HttpPost]
[Route("createsession")]
public async Task<Session> CreateSession([FromBody]string id)
{
var userId = this.userManager.GetUserId(this.User);
var payment = await this.paymentService.GetPaymentDetailsAsync(id, userId);
var successStringUrl = "https://localhost:44319/Checkout/success?session_id={CHECKOUT_SESSION_ID}";
var cancelStringUrl = "https://localhost:44319/Checkout/cancel";
var options = new SessionCreateOptions
{
PaymentMethodTypes = new List<string>
{
"card",
},
LineItems = new List<SessionLineItemOptions>
{
new SessionLineItemOptions
{
Quantity = 1,
Amount = (long)payment.Amount * 100,
Currency = CurrencyUSD,
Description = $"Payment Id: {payment.Id} for rental at {payment.RentalAddress}",
Name = $"Rent Payment for {DateTime.UtcNow.Month} | {DateTime.UtcNow.Year} for rental at {payment.RentalAddress}",
},
},
PaymentIntentData = new SessionPaymentIntentDataOptions
{
ApplicationFeeAmount = (long)((payment.Amount * 0.01m) * 100),
CaptureMethod = "manual",
TransferData = new SessionPaymentIntentTransferDataOptions
{
Destination = payment.ToStripeAccountId,
},
},
SuccessUrl = successStringUrl,
CancelUrl = cancelStringUrl,
};
var service = new SessionService();
Session session = service.Create(options);
return session; // the MVC version returns Task<IActionResult> of this.Json(session);
}
The options method of Stripe is not important, its only importnat why the fetch can’t get anything. and what am I doing fundamentally wrong.
Here is a Stripe engineer CJ Avilla, demonstrating this with PHP and JS but you could get an idea.
After minute mark 20:30 you want to see him creating the fetch and later on, how checkout flow cicks in.
https://www.youtube.com/watch?v=VQ5jccnZ2Ow&t=1160s
Will appreciate any suggestions. Throw them to me.
Anyone with serious experience and a little time to dig in, I can provide access to the private github repo (its my first web project and I have to defend it at the end of the ASP.NET Core course at SoftUni).
Thank you!
P.S.
Edit 1:
Added binding model for the Id param, as I was wrongly expecting string but passing json object. However this still does not prove or allow the method to be accessed by the fetch…
Screen-shot added from my browser debugging.
Edit 2:
This code return Status 400 in console
fetch("https://localhost:44319/api/payment/createsession", {
method: 'POST',
mode: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
body: JSON.stringify({ id: paymentId })
})
.then(r => r.json().then(data => ({status: r.status, body: data})))
.then(obj => console.log(obj));
2
Answers
Your
CreateSession
action accepts a string-type parameterid
, on your JavaScript client side, you can pass data through request body like below.Besides, if you’d like to make your action can handle
body: JSON.stringify({id: paymentId })
well from client, you can also modify your action to accept a custom model parameter, like below.MyTestModel class