2017-05-15 98 views
1

我有一個應用程序是ASP.net的核心,並已經集成了一個用於處理付款的純粹支付網關。在我的日誌文件中,我可以看到有時付款控制器執行兩次。我根據收到請求的時間生成一個ID,ID有時會相隔1秒,或者有時它們完全在同一時間。這會導致在發生這種情況時僅爲少數情況對卡充電兩次。我似乎無法弄清楚什麼可能觸發這一點。ASP.Net內核有時動作控制器被調用兩次

以下是我使用

用戶填寫申請表,並在付款按鈕點擊我使用此代碼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" }); 
     }); 

這將打開spreedly支付形式的代碼用戶輸入所有卡信息並點擊付款按鈕的彈出窗口。它執行支付控制器

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  
} 

我生成ID登錄,我可以看到,在日誌文件中的某些時候,它與具有兩種完全相同的時間或ID的客戶跑了兩次,有一個1秒的差距。我測試了雙擊方案,並且已經放入了一些代碼來防止雙擊。但我似乎不能理解爲什麼有時會發生這種情況。這並不常見。它就像發生在100次付款中的1例。

我有一個操作屬性來處理重複的請求。放入此代碼後,它確實停止了重複請求的數量,但不完全。在少數情況下,一些控制器如何被調用兩次。

[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); 
    } 
+0

你的控制器上的'Index'方法基本上是空的。我們需要更多代碼來診斷問題。我會檢查您選擇的瀏覽器的「開發人員工具」中的「網絡」選項卡,以查看是否有多個請求被觸發到您的控制器。除此之外,我沒有看到你提供的代碼中有什麼瘋狂的事情,表明它發送了重複的請求。 – Cameron

回答

0

這不是ASP.NET核心問題。我99%確定實際上有多個來自客戶端的請求,ASP.NET Core只是簡單地處理它們。

您的一個選擇是在頁面上放置一個guid或其他標識符並將其與請求一起發送。在您的Controller中,檢查您的緩存或會話以查看該標識符是否已存在。如果是這樣,拋出異常或返回Ok()或記錄事件或任何你想要做的事情,但不要爲這張卡收費。

+0

我會生成一個請求ID而不是頁面ID(或者兩者都有),所以你可以看到控制器是在兩個來自同一個頁面的請求,兩個不同頁面的兩個請求,還是由於其中一箇中間件。 –

+0

我已經有一個動作屬性來處理這個,但仍然不知何故,這種代碼在某些情況下也無法捕捉請求。放入此代碼後,它實際上大幅降低了重複請求的數量。我更新了我的帖子以顯示我正在使用的重複請求代碼。 –