Pieterjan
Pieterjan

Reputation: 3521

Use PaymentRequest api in ASP.NET Core

I'm trying to use the PaymentRequest javascript API. Up until now I have the following code (repo), which runs quite fine until the browser sends a request to the default_applications url.

The user clicks the pay button, and creates and shows a PaymentRequest

<head>
    <script type="text/javascript">
        function pay() {
            const createRequest = () => new PaymentRequest(
                [
                    {
                        supportedMethods: "https://localhost:7208/pay",
                        // supportedMethods: "https://play.google.com/billing",
                        data: {}
                    },
                ],
                {
                    total: { label: 'Donation', amount: { currency: 'USD', value: '55.00' } },
                    displayItems: [ ... ],
                },
            );

            createRequest().canMakePayment().then(can => {
                createRequest().show().then(function (data) { console.log("Data", data); });
            });
        }
    </script>
</head>
<body>
    <button onclick="pay()">Start payment</button>
</body>

This triggers a HEAD request to https://localhost:7208/pay which is handled like this

app.MapMethods("/pay", [HttpMethods.Head], async (context) =>
{
    context.Response.Headers["Link"] = "</pay/payment-manifest.json>; rel=\"payment-method-manifest\"";
});

Now the browser wants to read the payment manifest, to which I reply with this

app.MapGet("/pay/payment-manifest.json", async (context) =>
{
    await context.Response.WriteAsJsonAsync(new
    {
        default_applications = new string[]
        {
            "https://localhost:7208/manifest.json"
        },
        supported_origins = new string[]
        {
            "https://localhost:7208"
        }
    });
});

Somehow, for a reason I don't understand yet, the browser then wants to fetch my PWA manifest.json, in any case, I send this response back

app.MapGet("/manifest.json", async (context) =>
{
    await context.Response.WriteAsJsonAsync(new
    {
        name = "Example",
        short_name = "Example",
        theme_color = "#1976d2",
        background_color = "#fafafa",
        display = "standalone",
        scope = "/",
        start_url = "/",
        icons = new[] {
            new {
                src = "music_note_192.png",
                sizes = "192x192",
                type = "image/png"
            },
        },
        serviceworker = new {
            src = "worker.js",
            scope = "/",
            use_cache = false,
        }
    });
});

And now the browser also wants access to my service worker, because of this I filled out this field in the manifest above. worker.js returns the following response for now:

(() => {

})();

However, I'm still getting an error in the browser console. And can't figure out how to make this work.

Uncaught (in promise) AbortError: Payment handler did not respond to "paymentrequest" event.

Upvotes: 0

Views: 58

Answers (1)

Jason Pan
Jason Pan

Reputation: 21838

The root cause is missing paymentrequest event handler in your worker.js.

After investigating the repo, this repo is not finished yet, hope the owner will keep to update it.

You can set breakpoint in my test code to check the payment process.

Here is my working sample.

worker.js

// worker.js
self.addEventListener('paymentrequest', function (event) {
  // Handle the payment request
  event.respondWith(handlePaymentRequest(event));
});

async function handlePaymentRequest(event) {
  // Extract payment details
  const methodData = event.methodData;
  const details = event.total;
  const modifiers = event.modifiers;

  // Process the payment (e.g., show a custom payment UI)
  // For demonstration, we'll return a dummy response

  return {
    methodName: methodData[0].supportedMethods,
    details: {
      confirmationNumber: '1234567890', // Custom response data
    },
  };
}

Overview.cshtml

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script type="text/javascript">

        if ('serviceWorker' in navigator) {
            navigator.serviceWorker
                .register('/worker.js')
                .then(function (registration) {
                    console.log('Service Worker registered with scope:', registration.scope);
                })
                .catch(function (error) {
                    console.error('Service Worker registration failed:', error);
                });
        } else {
            console.error('Service Workers are not supported in this browser.');
        }

        function pay() {
            const request = new PaymentRequest(
                [
                    {
                        supportedMethods: "https://localhost:7208/pay",
                        //supportedMethods: "https://play.google.com/billing",
                        data: {}
                    },
                ],
                {
                    total: { label: 'Donation', amount: { currency: 'USD', value: '55.00' } },
                    displayItems: [
                        {
                            label: 'Original donation amount',
                            amount: { currency: 'USD', value: '65.00' },
                        },
                        {
                            label: 'Friends and family discount',
                            amount: { currency: 'USD', value: '-10.00' },
                        },
                    ],
                },
            );

            request.canMakePayment().then(function (canMakePayment) {
                if (canMakePayment) {
                    request.show().then(function (paymentResponse) {
                        console.log("Payment Response:", paymentResponse);

                        paymentResponse.complete('success').then(function () {
                            console.log('Payment completed successfully.');

                            alert('Payment successful!');
                        }).catch(function (err) {
                            console.error('Payment completion failed:', err);
                        });
                    }).catch(function (err) {
                        console.error('Payment failed:', err);
                    });
                } else {
                    console.log('Cannot make payment.');
                    alert('Cannot make payment.');
                }
            }).catch(function (err) {
                console.error('canMakePayment() failed:', err);
            });
        }
    </script>
</head>
<body>
    <button onclick="pay()">Start payment</button>
</body>
</html>

Still has some issue since the owner not use static files like payment-manifest.json and manifest.json, the error like below.

enter image description here

Upvotes: 0

Related Questions