- ABP Framework version: v8.2.2
- UI Type: Blazor Server
- Database System: EF Core (SQL Server)
- Tiered (for MVC) or Auth Server Separated (for Angular): no
We use the PaymentModule for payment processing via Stripe. Because we want to store various additional information (e.g. about the invoice) in the payment request, we have derived from the StripePaymentGateway and overwritten the CompleteAsync & HandleWebhookAsync methods, for example.
Now we always have concurrency exceptions because the PaymentModule in the PaymentRequestAppService probably also updates the PaymentRequest at the same time.
We have secured our methods with a semaphore so that the processing of our webhook events is synchronized and they cannot access the PaymentRequest at the same time. I have the code from your StripePaymentRequestGateway and we have overwritten all the corresponding methods there, so no relevant code is executed there.
But what happens in your PaymentRequestAppService is still a black box for us.
could you provide me with the code? Preferably from the whole PaymentModule, if that is not possible, then at least from the PaymentRequestAppService.
how should the problem be solved from your point of view? If you send events to the distributed event bus in the app service, then I won't be able to synchronize this with my own event processing, will I?
Thanks, Adrian
38 Answer(s)
-
0
I will send you the new log file by e-mail in about 30 minutes...
OK, I will check the logs.
-
0
Update for those who also have this problem: It works with a unit of work with
IsolationLevel.Serializable
because a lock is then set at database level.using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true, isolationLevel: IsolationLevel.Serializable)) { // get the entity // update the entity await uow.CompleteAsync(cancellationToken); }
-
0
Thanks ageiter
-
0
As I wrote yesterday in the mail to you @maliming, I have now changed my strategy and use the StripePaymentGateway almost without any changes on my part. Only at the end with CompleteAsync I do other things according to your code and retrieve e.g. the customer and billing information.
Now I have noticed that there is an error in the HandleCustomerSubscriptionUpdateAsync method when calling the StripePaymentGateway. I assume it is because the external SubscriptionId is not yet saved in the PaymentRequest at the time of the call. You should actually be able to reproduce this error.
The SubscriptionId from Stripe is saved in the HandleCheckoutSessionCompletedAsync() or CompleteAsync() method. However, since the update comes before, this ID is not yet present on the PaymentRequest and so this error occurs.
Here is the log, enriched with my additional log messages from my wrapper class:
2025-01-17 08:53:12.473 +00:00 [INF] PalmaPaymentRequestAppService.CreateAsync, Begin create payment request. ThreadId='54' 2025-01-17 08:53:12.511 +00:00 [INF] PalmaPaymentRequestAppService.CreateAsync, End create payment request. ThreadId='54' 2025-01-17 08:53:13.195 +00:00 [INF] PalmaPaymentRequestAppService.StartAsync, Begin start payment request for payment gateway 'stripe'. ThreadId='86' 2025-01-17 08:53:14.024 +00:00 [INF] PalmaPaymentRequestAppService.StartAsync, End start payment request for payment gateway 'stripe'. ThreadId='54' 2025-01-17 08:53:29.025 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync: Begin handle webhook event 'checkout.session.completed' for payment gateway 'stripe'. ThreadId='42' 2025-01-17 08:53:29.069 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync: Begin handle webhook event 'customer.subscription.updated' for payment gateway 'stripe'. ThreadId='42' 2025-01-17 08:53:29.130 +00:00 [ERR] ---------- RemoteServiceErrorInfo ---------- { "code": null, "message": "There is no entity PaymentRequest with id = !", "details": null, "data": null, "validationErrors": null } 2025-01-17 08:53:29.130 +00:00 [ERR] There is no such an entity given id. Entity type: Volo.Payment.Requests.PaymentRequest Volo.Abp.Domain.Entities.EntityNotFoundException: There is no such an entity given id. Entity type: Volo.Payment.Requests.PaymentRequest at Volo.Payment.EntityFrameworkCore.EfCorePaymentRequestRepository.GetBySubscriptionAsync(String externalSubscriptionId, CancellationToken cancellationToken) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync() at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed) at Volo.Payment.Stripe.StripePaymentGateway.HandleCustomerSubscriptionUpdatedAsync(Event stripeEvent) at Volo.Payment.Stripe.StripePaymentGateway.HandleWebhookAsync(String payload, Dictionary`2 headers) at Volo.Payment.Requests.PaymentRequestAppService.HandleWebhookAsync(String paymentGateway, String payload, Dictionary`2 headers) at Palma.Payments.PalmaPaymentRequestAppService.HandleWebhookAsync(String paymentGateway, String payload, Dictionary`2 headers) in D:\a\1\s\Source\Palma\src\Palma.Application\Payments\PalmaPaymentRequestAppService.cs:line 60 at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync() at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync() at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync() at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope) at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed) at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo) at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync() at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation) at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed) at Volo.Payment.Requests.PaymentRequestController.HandleWebhookAsync(String paymentMethod, String payload, Dictionary`2 headers) at lambda_method6557(Closure, Object) at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) 2025-01-17 08:53:29.310 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync: End handle webhook event 'checkout.session.completed' for payment gateway 'stripe'. ThreadId='42' 2025-01-17 08:53:29.485 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync: Begin handle webhook event 'customer.subscription.created' for payment gateway 'stripe'. ThreadId='42' 2025-01-17 08:53:29.494 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync: End handle webhook event 'customer.subscription.created' for payment gateway 'stripe'. ThreadId='42' 2025-01-17 08:53:31.813 +00:00 [INF] PalmaPaymentRequestAppService.CompleteAsync, Begin complete payment request for payment gateway 'stripe'. ThreadId='54' 2025-01-17 08:53:32.915 +00:00 [INF] PalmaPaymentRequestAppService.CompleteAsync, End complete payment request for payment gateway 'stripe'. ThreadId='36' 2025-01-17 08:53:43.938 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync: Begin handle webhook event 'customer.subscription.updated' for payment gateway 'stripe'. ThreadId='43' 2025-01-17 08:53:43.987 +00:00 [INF] PalmaPaymentRequestAppService.HandleWebhookAsync: End handle webhook event 'customer.subscription.updated' for payment gateway 'stripe'. ThreadId='43'
This is the method from ABP StripePaymentGateway:
protected virtual async Task HandleCustomerSubscriptionUpdatedAsync(Event stripeEvent) { var paymentRequest = await PaymentRequestRepository.GetBySubscriptionAsync( (string)stripeEvent.Data.RawObject.id); var paymentUpdatedEto = ObjectMapper.Map<PaymentRequest, SubscriptionUpdatedEto>(paymentRequest); paymentUpdatedEto.PeriodEndDate = ConvertToDateTime((int)stripeEvent.Data.RawObject.current_period_end); await EventBus.PublishAsync(paymentUpdatedEto); }
-
0
A possible bugfix / solution to this problem would be to also save the PaymentRequestId in the metadata of the subscription. Then you would not have to search for the PaymentRequest using the ExternalSubscriptionId, instead you would have the PaymentRequestId available directly.
I have now changed this for me and it works.
The adjustments in the StripePaymentGateway would be as follows:
public virtual async Task<PaymentRequestStartResult> StartAsync(PaymentRequest paymentRequest, PaymentRequestStartInput input) { ... var options = new SessionCreateOptions { ... Metadata = new Dictionary<string, string> { { StripeConsts.ParameterNames.PaymentRequestId, paymentRequest.Id.ToString()}, }, // THIS IS THE CHANGE YOU SHOULD MAKE // Add metadata to the subscription SubscriptionData = new SessionSubscriptionDataOptions() { Metadata = new Dictionary<string, string> { { StripeConsts.ParameterNames.PaymentRequestId, paymentRequest.Id.ToString() } } } }; ... }
HandleCustomerSubscriptionUpdatedAsync
would be as follows:protected override async Task HandleCustomerSubscriptionUpdatedAsync(Event stripeEvent) { var paymentRequestId = Guid.Parse(stripeEvent.Data.RawObject.metadata[StripeConsts.ParameterNames.PaymentRequestId]?.ToString()); var paymentRequest = await PaymentRequestRepository.GetAsync(paymentRequestId); var paymentUpdatedEto = ObjectMapper.Map<PaymentRequest, SubscriptionUpdatedEto>(paymentRequest); paymentUpdatedEto.PeriodEndDate = ConvertToDateTime((int)stripeEvent.Data.RawObject.current_period_end); await EventBus.PublishAsync(paymentUpdatedEto); }
Additional improvements in the StripePaymentGateway:
- Also adjusts method
HandleCustomerSubscriptionDeletedAsync
described above - Always uses the constant
StripeConsts.ParameterNames.PaymentRequestId
(notGuid.Parse(session.Metadata["PaymentRequestId"])
)
Here is the whole
StartAsync
method:public virtual async Task<PaymentRequestStartResult> StartAsync(PaymentRequest paymentRequest, PaymentRequestStartInput input) { var purchaseParameters = PurchaseParameterListGenerator.GetExtraParameterConfiguration(paymentRequest); var currency = paymentRequest.Currency.IsNullOrEmpty() ? purchaseParameters.Currency : paymentRequest.Currency; var lineItems = new List<SessionLineItemOptions>(); foreach (var product in paymentRequest.Products) { var lineItem = new SessionLineItemOptions { Quantity = product.Count, }; if (product.PaymentType == PaymentType.Subscription) { var gatewayPlan = await PlanRepository.GetGatewayPlanAsync(product.PlanId.Value, StripeConsts.GatewayName); lineItem.Price = gatewayPlan.ExternalId; } if (product.PaymentType == PaymentType.OneTime) { lineItem.PriceData = new SessionLineItemPriceDataOptions { UnitAmountDecimal = Convert.ToDecimal(product.UnitPrice) * 100, Currency = currency, ProductData = new SessionLineItemPriceDataProductDataOptions { Name = product.Name, Metadata = new Dictionary<string, string> { { "ProductCode", product.Code } } } }; } lineItems.Add(lineItem); } var options = new SessionCreateOptions { Locale = purchaseParameters.Locale, PaymentMethodTypes = purchaseParameters.PaymentMethodTypes, LineItems = lineItems, Mode = modeMapping[paymentRequest.Products.First().PaymentType], SuccessUrl = input.ReturnUrl, CancelUrl = input.CancelUrl, Metadata = new Dictionary<string, string> { { StripeConsts.ParameterNames.PaymentRequestId, paymentRequest.Id.ToString()}, }, // Add metadata to the subscription SubscriptionData = new SessionSubscriptionDataOptions() { Metadata = new Dictionary<string, string> { { StripeConsts.ParameterNames.PaymentRequestId, paymentRequest.Id.ToString() } } } }; var sessionService = new SessionService(); var session = await sessionService.CreateAsync(options); return new PaymentRequestStartResult { CheckoutLink = "https://js.stripe.com/v3/", ExtraProperties = { { StripeConsts.ParameterNames.PublishableKey, StripeOptions.PublishableKey}, { StripeConsts.ParameterNames.SessionId, session.Id} } }; }
- Also adjusts method
-
0
Many thanks for your solution. 👍
I will check our payment module
-
0
Your ticket has been refunded.
-
0
Thank you very much. Could you let me know in which version this has been implemented?
-
0
hi
Maybe 9.2
-
0
One last question about the payment process. You have probably also seen in my logs (which I sent you by e-mail) that the following error message always appears at the beginning of a payment request (after the StartAsync):
2025-01-16 19:55:43.645 +00:00 [INF] PalmaPaymentRequestAppService.StartAsync, Begin start payment request for payment gateway 'stripe'. ThreadId='37' 2025-01-16 19:55:44.898 +00:00 [INF] PalmaPaymentRequestAppService.StartAsync, End start payment request for payment gateway 'stripe'. ThreadId='38' 2025-01-16 19:55:45.102 +00:00 [WRN] The operation was canceled. System.OperationCanceledException: The operation was canceled. at System.Threading.CancellationToken.ThrowOperationCanceledException() at Microsoft.Extensions.Caching.StackExchangeRedis.RedisCache.GetAsync(String key, CancellationToken token) at Volo.Abp.Caching.DistributedCache`2.GetAsync(TCacheKey key, Nullable`1 hideErrors, Boolean considerUow, CancellationToken token) 2025-01-16 19:55:45.173 +00:00 [ERR] Error when dispatching 'OnDisconnectedAsync' on hub. System.Threading.Tasks.TaskCanceledException: A task was canceled. at Volo.Abp.Threading.SemaphoreSlimExtensions.LockAsync(SemaphoreSlim semaphoreSlim, CancellationToken cancellationToken) at Volo.Abp.Caching.DistributedCache`2.GetOrAddAsync(TCacheKey key, Func`1 factory, Func`1 optionsFactory, Nullable`1 hideErrors, Boolean considerUow, CancellationToken token) at Volo.Abp.Identity.IdentityDynamicClaimsPrincipalContributorCache.GetAsync(Guid userId, Nullable`1 tenantId) at Volo.Abp.Identity.IdentityDynamicClaimsPrincipalContributor.ContributeAsync(AbpClaimsPrincipalContributorContext context) at Volo.Abp.Security.Claims.AbpClaimsPrincipalFactory.InternalCreateAsync(AbpClaimsPrincipalFactoryOptions options, ClaimsPrincipal existsClaimsPrincipal, Boolean isDynamic) at Volo.Abp.Security.Claims.AbpClaimsPrincipalFactory.CreateDynamicAsync(ClaimsPrincipal existsClaimsPrincipal) at Volo.Abp.AspNetCore.SignalR.Authentication.AbpAuthenticationHubFilter.HandleDynamicClaimsPrincipalAsync(ClaimsPrincipal claimsPrincipal, IServiceProvider serviceProvider, HubCallerContext hubCallerContext, Boolean skipCheckDynamicClaimsInterval) at Volo.Abp.AspNetCore.SignalR.Authentication.AbpAuthenticationHubFilter.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.HubFilterFactory.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.HubFilterFactory.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.HubFilterFactory.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.HubFilterFactory.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnDisconnectedAsync(HubConnectionContext connection, Exception exception) at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnDisconnectedAsync(HubConnectionContext connection, Exception exception) at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.HubOnDisconnectedAsync(HubConnectionContext connection, Exception exception) 2025-01-16 19:55:45.203 +00:00 [ERR] Failed disposing connection 3FgE5QW7nXvr8qTHdKaf_A. System.Threading.Tasks.TaskCanceledException: A task was canceled. at Volo.Abp.Threading.SemaphoreSlimExtensions.LockAsync(SemaphoreSlim semaphoreSlim, CancellationToken cancellationToken) at Volo.Abp.Caching.DistributedCache`2.GetOrAddAsync(TCacheKey key, Func`1 factory, Func`1 optionsFactory, Nullable`1 hideErrors, Boolean considerUow, CancellationToken token) at Volo.Abp.Identity.IdentityDynamicClaimsPrincipalContributorCache.GetAsync(Guid userId, Nullable`1 tenantId) at Volo.Abp.Identity.IdentityDynamicClaimsPrincipalContributor.ContributeAsync(AbpClaimsPrincipalContributorContext context) at Volo.Abp.Security.Claims.AbpClaimsPrincipalFactory.InternalCreateAsync(AbpClaimsPrincipalFactoryOptions options, ClaimsPrincipal existsClaimsPrincipal, Boolean isDynamic) at Volo.Abp.Security.Claims.AbpClaimsPrincipalFactory.CreateDynamicAsync(ClaimsPrincipal existsClaimsPrincipal) at Volo.Abp.AspNetCore.SignalR.Authentication.AbpAuthenticationHubFilter.HandleDynamicClaimsPrincipalAsync(ClaimsPrincipal claimsPrincipal, IServiceProvider serviceProvider, HubCallerContext hubCallerContext, Boolean skipCheckDynamicClaimsInterval) at Volo.Abp.AspNetCore.SignalR.Authentication.AbpAuthenticationHubFilter.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.HubFilterFactory.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.HubFilterFactory.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.HubFilterFactory.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.HubFilterFactory.OnDisconnectedAsync(HubLifetimeContext context, Exception exception, Func`3 next) at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnDisconnectedAsync(HubConnectionContext connection, Exception exception) at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnDisconnectedAsync(HubConnectionContext connection, Exception exception) at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.HubOnDisconnectedAsync(HubConnectionContext connection, Exception exception) at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.RunHubAsync(HubConnectionContext connection) at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.OnConnectedAsync(ConnectionContext connection) at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.OnConnectedAsync(ConnectionContext connection) at Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionContext.ExecuteApplication(ConnectionDelegate connectionDelegate) at Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionContext.WaitOnTasks(Task applicationTask, Task transportTask, Boolean closeGracefully) at Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionContext.DisposeAsync(Boolean closeGracefully) at Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager.DisposeAndRemoveAsync(HttpConnectionContext connection, Boolean closeGracefully, HttpConnectionStopStatus status)
Why is this the case? How can I correct this?
-
0
hi
A task was canceled.
This is usually because the http(web hook) request was canceled.
-
0
It just irritates me because it always happens (every time) after the StartAsync. So when redirecting to the PaymentGateway. At a time when no WebHooks are being received.
Maybe it has something to do with the way I submit the request...
private async Task RedirectToPaymentGateway(Guid paymentRequestId) { var tokens = Antiforgery.GetAndStoreTokens(HttpContextAccessor.HttpContext); var requestToken = tokens.RequestToken; var uri = $"/Payment/GatewaySelection?paymentRequestId={paymentRequestId}"; await JSRuntime.InvokeVoidAsync("eval", $@" (function() {{ var form = document.getElementById('PaymentGatewaySelectionForm'); // Check if the antiforgery token is present in the form, if the token is not present, create a new hidden input field for the token var tokenInput = form.querySelector('input[name=__RequestVerificationToken]'); if (!tokenInput) {{ tokenInput = document.createElement('input'); tokenInput.type = 'hidden'; tokenInput.name = '__RequestVerificationToken'; form.appendChild(tokenInput); }} // Set the value of the token tokenInput.value = '{requestToken}'; // Update the form's action with the new URI and submit the form form.action = '{uri}'; form.submit(); }})(); "); }
-
0
hi
Can you check your question in Chrome dev-tool?
You can consider moving the
js code
to a function(PostPaymentGatewaySelectionForm
), thenInvoke
this function in blazor.await JSRuntime.InvokeVoidAsync("PostPaymentGatewaySelectionForm")
By the way, can you share the cs files you have overwritten? I will check and merge into the payment module.
Thanks.