首页 > 解决方案 > 防止来自用户的并发控制器请求

问题描述

我的 ASP.Net MVC 项目中有一个控制器操作,不应允许同一用户同时执行该操作。当用户提交请求 #1 并且在请求 #1 仍在运行期间,所有其他请求都应被拒绝。这个逻辑必须基于用户。

我写了一些代码,我认为它可以工作

由于我在 localhost 上进行测试时遇到问题,并且它是我网站的一个敏感部分,如果您能查看代码并给我一些反馈,我将不胜感激!

更新

我将下面的代码发布到生产环境中,曾经有一次用户创建了一个锁但没有解锁的情况。我不知道问题出在哪里。

控制器

public class LockTestController : Controller
    {
        public string Submit(int userId)
        {
            try
            {
                if (TransactionLockRepository.HasLock(userId))
                    return DateTime.Now + $"Err: UserId {userId} already requested already ";

                //todo: do important stuff an user should not execute concurrently

                TransactionLockRepository.RemoveLock(userId);
                return DateTime.Now + " Submit successfully. UserId: " + userId + " ";
            }
            catch (Exception e)
            {
                TransactionLockRepository.RemoveLock(userId);
                Debug.WriteLine(e);
                return  DateTime.Now + " Error " + e;
            }
        }
    }

锁库

public static class TransactionLockRepository
    {
        private static readonly ConcurrentBag<int> UserLocks = new ConcurrentBag<int>();
        private static readonly object _lockInsert = new object();
        private static readonly object _lockRemove = new object();

        public static bool HasLock(int userId)
        {
            lock (_lockInsert)
            {
                var i = userId;
                var hasLock = UserLocks.TryPeek(out i);
                if (hasLock)
                    return true;
                UserLocks.Add(userId);
                return false;
            }
        }

        public static bool RemoveLock(int userId)
        {
            lock (_lockRemove)
            {
                var i = userId;
                UserLocks.TryTake(out i);
                return i == userId;
            }
        }
    }

我希望只有当 userId 在 Lock Repo 中时请求才会被阻止。其他用户不应受到影响

标签: c#asp.net-mvcmodel-view-controller

解决方案


我认为这不会一直有效。如果两个动作请求HasLock同时调用方法怎么办?hasLock并且这两个请求在执行代码行之前依次将变量设置为 false UserLocks.Add(userId);。在这种情况下,您可能需要在 HasLock 方法中使用 lock :

private static object _lockObj = new object();
public static bool HasLock(int userId)
{
   lock(_lockObj)    
   {
     var i = userId;
     var hasLock = UserLocks.TryPeek(out i);
     if (hasLock)
         return true;
     UserLocks.Add(userId);
     return false;
   }
}

推荐阅读