I'm trying to build a custom payment flow using Stripe. It's working locally, but when I try to put it online, I get an error after a certain time. I asked my web hosting service if they put any filter, but apparently not. You'll find the code bellow. For the Javascript, I basically copy pasted the code given by Stripe. Also, I don't get any payment intent on the Stripe end, so I think my web app can't connect to Stripe. Visually the form where the user is supposed to enter his card number etc isn't appearing.
The error I get after a certain time on the payment intent page
The server side code (C#):
[Authorize]
[Route("/create-payment-intent")]
[ApiController]
public class PaymentIntentApiController : Controller
{
private readonly UserManager<AppUser> userManager;
private readonly ApplicationDbContext db;
public PaymentIntentApiController(UserManager<AppUser> userManager, ApplicationDbContext db)
{
this.userManager = userManager;
this.db = db;
}
[HttpPost]
public async Task<ActionResult> Create(ProductViewModel request)
{
if (request == null)
{
return RedirectToAction("Checkout", "Payment");
}
ComplexDbOperations cdo = new ComplexDbOperations(db);
Data.Objects.Product product = new Data.Objects.Product { period = request.period, sub = request.subscription };
int price = ProductViewModel.calculateStripePrice(await cdo.getPricesAsync(product.ToRole().ToString()));
if (price <= 0)
{
return RedirectToAction("Checkout", "Payment");
}
AppUser user = await userManager.GetUserAsync(User);
if (user == null) return RedirectToAction("Index", "Home");
var paymentIntents = new PaymentIntentService();
var paymentIntentOptions = new PaymentIntentCreateOptions
{
Amount = price,
Currency = "chf",
Description = string.Format("Abonnement {0} pour {1}, Periode : {2}", request.subscription.ToString(), user.Email, request.period.ToString()),
Metadata = new Dictionary<string, string>
{
{"Abonnement", request.subscription.ToString()},
{"Periode", request.period.ToString() },
{"UserId", user.Id },
{"UserEmail", user.Email },
{"subCode", ((int)request.subscription).ToString()},
{"periodCode", ((int)request.period).ToString() },
}
};
var paymentIntent = paymentIntents.Create(paymentIntentOptions);
return Json(new { clientSecret = paymentIntent.ClientSecret });
}
}
What I've modified from Stripe on the client side code (js) :
// The items the customer wants to buy
var purchase = {
period: parseInt(document.getElementById("period").value),
subscription: parseInt(document.getElementById("subscription").value)
};
// Disable the button until we have Stripe set up on the page
document.querySelector("button").disabled = true;
fetch("/create-payment-intent", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(purchase)
})... (stripe code continuing)
Can you please help me ? I don't even know how I can get more details on the error as I can't debug the program when it's online.
Thanks in advance.
[Update] I logged the server error and got :
System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (api.stripe.com:443)
I finally know what was the problem so I'll explain what it was and how to solve it if someone encounters the same error.
The first thing I did was, as suggested by karllekko, to check the server logs when it was running on the hosted service. For that, I used Serilog which is a package that allows you to store the logs into a file (It was the simpliest solution for me). I then got a more precise error :
HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time...
From this error, I knew I wasn't able to get to stripe's servers. I found a simple ping function in C# that checks if my assumption was right and it was.
I then checked with my host service provider how I could access an external IP: they use a proxy server for security reasons.
I added this code before creating the payment intent which uses the proxy server :
var handler = new HttpClientHandler
{
Proxy = new WebProxy(proxyServer),
UseProxy = true,
};
var httpClient = new HttpClient(handler);
var stripeClient = new StripeClient(
apiKey: secretApiKey,
httpClient: new SystemNetHttpClient(httpClient)
);
StripeConfiguration.StripeClient = stripeClient;
I hope if someone encounters the same error he will be able to solve the problem with this answer.