【问题标题】:ASP.Net core sometimes the action controller is called twiceASP.Net 核心有时会调用两次动作控制器
【发布时间】:2017-05-15 13:53:29
【问题描述】:

我有一个应用程序是 ASP.net 核心,并集成了快速支付网关来处理支付。在我的日志文件中,我可以看到支付控制器有时会执行两次。我根据收到请求的时间生成一个 ID,这些 ID 有时相隔 1 秒,有时它们完全相同。这导致仅在发生这种情况的少数情况下对卡进行两次收费。我似乎无法弄清楚是什么触发了这种情况。

以下是我正在使用的代码

用户填写申请表并点击支付按钮,我正在使用此代码快速触发

 $('#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" });
        });

这会以弹出窗口的形式打开快速支付表单,用户在其中输入所有卡信息并点击支付按钮。哪个执行支付控制器

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);
    }

【问题讨论】:

  • 您的控制器上的Index 方法基本上是空的。我们需要更多代码来诊断问题。我会检查您选择的浏览器的Developer Tools 中的Network 选项卡,以实际查看是否有多个请求被触发到您的控制器。除此之外,我在您提供的代码中没有看到任何疯狂的东西表明它正在发送重复的请求。
  • 在我的例子中,罪魁祸首是&lt;head&gt;&lt;/head 标签中的这一行:&lt;link rel="manifest" href="site.webmanifest"&gt;。在我删除它之后,重复的请求就永远消失了。

标签: c# model-view-controller asp.net-core spreedly


【解决方案1】:

这不是 ASP.NET Core 问题。我 99% 确定实际上有多个请求来自客户端,而 ASP.NET Core 只是按预期处理它们。

您可以选择在页面上放置一个 guid 或其他标识符,然后将其与请求一起发送。在您的 Controller 中,检查您的缓存或会话以查看该标识符是否已存在。如果是,则抛出异常或返回 Ok() 或记录发生情况或在这种情况下您想要执行的任何操作,但不要从卡中扣款。

【讨论】:

  • 我会生成一个请求 ID 而不是页面 ID(或者两者都生成),因此您可以查看控制器是否在来自同一页面的两个请求、来自两个不同页面的两个请求或确实被调用由于其中一个中间件中的错误而被调用了两次。
  • 我已经有一个动作属性来处理这个问题,但在某些情况下,这段代码仍然无法捕获请求。放入此代码后,它实际上大大减少了重复请求的数量。我已更新我的帖子以显示我正在使用的重复请求代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多