C# Net内核有时会调用动作控制器两次

C# Net内核有时会调用动作控制器两次,c#,model-view-controller,asp.net-core,spreedly,C#,Model View Controller,Asp.net Core,Spreedly,我有一个应用程序是ASP.net的核心,并集成了快速支付网关处理付款。在我的日志文件中,我可以看到有时支付控制器执行两次。我根据收到请求的时间生成一个ID,ID有时相隔1秒,有时正好在同一时间。这导致在发生这种情况时,仅在少数情况下对卡收取两次费用。我似乎不知道是什么触发了这一切 下面是我正在使用的代码 用户填写申请表,然后在“支付”按钮上单击“我正在使用此代码快速触发” $('#REG').click(function () { var options = {

我有一个应用程序是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" });
        });
这将以弹出窗口的形式打开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     
}
公共异步任务索引(DynamicViewModel模型)
{
if(ModelState.IsValid)
{
尝试
{
if(TempData.ContainsKey(“PaymentFlag”)&&!String.IsNullOrEmpty(TempData[“PaymentFlag”].ToString())
{
//一些调用少量异步方法的代码逻辑
//根据当前请求的时间生成id
“APP-”+DateTime.Now.ToString(“yyyyMMddHmmss-”)+model.UserID;
//…这里有其他代码
}
我生成的id被记录在日志文件中,我可以看到,在日志文件中,它为一个id完全相同或有1秒差异的客户运行了两次。我已经测试了双击场景,还输入了一些代码来防止双击。但我仍然不明白为什么有时候会出现这种情况笔。这种情况并不常见。就像100次付款中发生的一种情况

我有一个action属性来处理重复的请求。在输入这段代码后,它确实停止了重复请求的数量,但并没有完全停止。在少数情况下,仍然有一些控制器如何被调用两次

[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);
    }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
公共类NodeUpplicateRequestAttribute:ActionFilterAttribute
{
公共请求=10;
//发生故障时将显示的错误消息
//过分的要求
public string ErrorMessage=“检测到过多的请求尝试。”;
//这将存储将错误重定向到的URL
公共字符串重定向URL;
公共覆盖无效OnActionExecuting(ActionExecutingContext filterContext)
{
//存储我们的HttpContext(以便于参考和代码简洁)
var request=filterContext.HttpContext.request;
//存储我们的HttpContext.Cache(以便于参考和代码简洁)
var cache=filterContext.HttpContext.RequestServices.GetService();
//从原始请求获取IP地址(示例)
var originationInfo=request.HttpContext.Connection.RemoteIpAddress.ToString()?request.HttpContext.Features.Get()?RemoteIpAddress.ToString();
//附加用户代理
originationInfo+=请求.Headers[“用户代理”].ToString();
//现在我们只需要目标URL信息
var targetInfo=request.HttpContext.request.GetDisplayUrl()+request.QueryString;
//为字符串生成一个哈希(附加字符串的每个字节)
//将值转换为单个哈希字符串
var hashValue=string.Join(“,MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(originationInfo+targetInfo))。选择(s=>s.ToString(“x2”);
字符串缓存;
//检查哈希值是否包含在缓存中(指示重复请求)
if(cache.TryGetValue(hashValue,out cachedHash))
{
//将错误消息添加到模型并重定向
}
其他的
{
//使用hashValue将空对象添加到缓存
//到密钥(这将设置将决定
//如果请求有效或无效)
var opts=new MemoryCacheEntryOptions()
{
SlidingExpiration=TimeSpan.FromSeconds(延迟请求)
};
Set(hashValue、cachedHash、opts);
}
base.OnActionExecuting(filterContext);
}

这不是ASP.NET核心问题。我99%确定实际上有多个来自客户端的请求,ASP.NET核心只是按照它的本意处理它们


您可以选择在页面上放置guid或其他标识符,并将其与请求一起发送。在控制器中,检查缓存或会话以查看该标识符是否已存在。如果已存在,则引发异常或返回Ok()或者记录事件或在这种情况下您想做的任何事情,但不要向卡收费。

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


您可以选择在页面上放置guid或其他标识符,并将其与请求一起发送。在控制器中,检查缓存或会话以查看该标识符是否已存在。如果已存在,则引发异常或返回Ok()或者记录事件或在这种情况下您想做的任何事情,但不向卡收费。

我会生成一个请求ID而不是页面ID(或者两者兼而有之),因此您可以看到控制器是否在来自同一页面的两个请求、来自两个不同页面的两个请求上被调用,或者确实是因为其中一个中间件中的错误而被调用了两次。我已经有了一个action属性来处理此问题,但在某些情况下,此代码仍然无法捕获请求。在输入此代码后实际上减少了重复请求的数量。我已经更新了我的帖子,以显示我正在使用的重复请求代码。我将生成一个请求ID而不是页面ID(或者两者都可以),这样您就可以看到控件