skip to Main Content

Trying over a week so far with no success, to find out why I can’t get the response from my controller.

  1. Note I am not fluent in JS, only C#, but I already have a good understanding of what the fetch does.
  2. Now learning ASP.NET Core, but still somewhere under junior level in my overall C# and .Net experience maybe.
  3. It is regarding the process of redirecting to Stripe checkout, but fetch and the method as mentioned, can’t agree around 200.
  4. 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.
  5. The method functions 100%, I mean the logic inside. It returns a session object.
    The API version returns the session; the MVC version returns this.Json(session);
    I know that both versions work because I was debugging them by entering inside after a button click
  6. Its all happening on localhost, therefore I provided credentials: 'include' in the headers… if I am correct.
  7. Trying anything with Postman with authorization of course, but no luck so far.
  8. 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 &nbsp; $ @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.
I have several break-points but the one that needs to be hit and is not, is shown by CJ at mark 23:28, this is my code line <code>sessionId = response.id;</code>

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


  1. why the fetch can’t get anything. and what am I doing fundamentally wrong

    Your CreateSession action accepts a string-type parameter id, on your JavaScript client side, you can pass data through request body like below.

    body: JSON.stringify(paymentId)
    

    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.

    [HttpPost]
    [Route("createsession")]
    public async Task<Session> CreateSession([FromBody]MyTestModel myTestModel)
    {
        var id = myTestModel.id;
    
        //your code logic here
        //...
    

    MyTestModel class

    public class MyTestModel
    {
        public string id { get; set; }
    }
    
    Login or Signup to reply.
  2. let serverResponse = await fetch('https://localhost:{port}/api/payment/createsession/',
                {
                    method: 'POST',
                    mode: 'cors',
                    headers: {
                        'Accept': 'application/json'
                    },
                    body: JSON.stringify({ id: paymentId })
                }
            );
            serverResponse.json().then(function (data) {
                // server response value come to "data" variable
                debugger;
            });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search