简体   繁体   中英

ASP.Net core sometimes the action controller is called twice

I have an application is ASP.net core and have integrated spreedly payment gateway for processing the payments. In my log files I can see that sometimes the payment controller executes twice. I generate an ID based on the time the request was received and the ID's are sometimes apart by 1 sec or at sometimes they are at the exact same time. This is resulting in charging the card twice only for few cases when this is happening. I cant seem to figure out what could be triggering this.

Following is the code that I am using

The user fills the application form and on the pay button click I am using this code to trigger spreedly

 $('#REG').click(function () {
            var options = {
                company_name: "abcd",
                sidebar_top_description: "Fees",
                sidebar_bottom_description: "Only Visa and Mastercard accepted",
                amount: "@string.Format("{0:c}",Convert.ToDecimal(Model.FeeOutstanding))"
            }
            document.getElementById('payment').value = 'App'
            SpreedlyExpress.init(environmentKey, options);
            SpreedlyExpress.openView();
            $('#spreedly-modal-overlay').css({ "position": "fixed", "z-index": "9999", "bottom": "0", "top": "0", "right": "0", "left": "0" });
        });

This opens the spreedly payment form as a popup where the user enters all the card information and hits the pay button. Which executes the payment controller

public async Task<IActionResult> Index(DynamicViewModel model)
{
    if (ModelState.IsValid)
    {
        try
        {
            if (TempData.ContainsKey("PaymentFlag") && !String.IsNullOrEmpty(TempData["PaymentFlag"].ToString()))
            {
                // Some code logic that calls few async methods
                //generate a id based on the time of current request
                "APP-" + DateTime.Now.ToString("yyyyMMddHmmss-") + model.UserID;

                // ... Other code here     
}

The id that I generate is logged and I can see that some times in the log file that it ran twice for a customer with the ID having either the exact same time or there was a 1 sec difference. I have tested the double click scenario and also have put in some code to prevent double clicks. But still I cant seem to understand why sometimes this happens. It is not frequent. Its like 1 case that happens in 100 payments.

I have an action attribute to handle the duplicate requests. After putting in this code it did stopped the number of duplicate requests but not completely. Still in few cases some how the controllers gets called twice.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class NoDuplicateRequestAttribute : ActionFilterAttribute
{
    public int DelayRequest = 10;
    // The Error Message that will be displayed in case of 
    // excessive Requests
    public string ErrorMessage = "Excessive Request Attempts Detected.";

    // This will store the URL to Redirect errors to
    public string RedirectURL;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Store our HttpContext (for easier reference and code brevity)
        var request = filterContext.HttpContext.Request;
        // Store our HttpContext.Cache (for easier reference and code brevity)
        var cache = filterContext.HttpContext.RequestServices.GetService<IMemoryCache>();

        // Grab the IP Address from the originating Request (example)
        var originationInfo = request.HttpContext.Connection.RemoteIpAddress.ToString() ?? request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();

        // Append the User Agent
        originationInfo += request.Headers["User-Agent"].ToString();

        // Now we just need the target URL Information
        var targetInfo = request.HttpContext.Request.GetDisplayUrl() + request.QueryString;

        // Generate a hash for your strings (appends each of the bytes of
        // the value into a single hashed string
        var hashValue = string.Join("", MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(originationInfo + targetInfo)).Select(s => s.ToString("x2")));
        string cachedHash;
        // Checks if the hashed value is contained in the Cache (indicating a repeat request)
        if (cache.TryGetValue(hashValue,out cachedHash))
        {
            // Adds the Error Message to the Model and Redirect

        }
        else
        {
            // Adds an empty object to the cache using the hashValue
            // to a key (This sets the expiration that will determine
            // if the Request is valid or not)
            var opts = new MemoryCacheEntryOptions()
            {
                SlidingExpiration = TimeSpan.FromSeconds(DelayRequest)
            };
            cache.Set(hashValue,cachedHash,opts);
        }
        base.OnActionExecuting(filterContext);
    }

This isn't an ASP.NET Core issue. I'm 99% certain there are in fact multiple requests coming from the client and ASP.NET Core is simply handling them as it is meant to.

An option for you would be to put a guid or other identifier on the page and send it with the request. In your Controller, check your cache or session to see if that identifier already exists. If it does, throw an exception or return Ok() or log the occurrence or whatever you want to do in that case but don't charge the card.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM