У нас есть устаревшая среда ASP.NET 2.0, в которой каждое выполнение страницы аутентифицируется для определенного пользователя, и поэтому у меня есть целое число, представляющее идентификатор вошедшего в систему пользователя.
На одной из страниц мне нужно запустить некоторый код, где я хочу запретить пользователю выполнять повторяющиеся действия. Трудно гарантировать, что это не может произойти, даже несмотря на то, что мы проводим базовую проверку предотвращения дублирования.
Очевидно, я мог бы создать статический объект и выполнить lock(myObject) { ... }
весь фрагмент кода, чтобы попытаться предотвратить некоторые из этих состояний гонки. Но я не хочу создавать узкое место для всех... просто хочу, чтобы один и тот же вошедший в систему пользователь не запускал код одновременно или почти одновременно.
Поэтому я думаю о создании экземпляра объекта для каждого пользователя и сохранении его в кеше на основе их идентификатора пользователя. Затем я ищу этот объект, и если объект найден, я фиксирую его. Если не найден, я сначала создаю/кеширую его, а затем блокирую.
Имеет ли это смысл? Есть ли лучший способ выполнить то, что мне нужно?
Что-то вроде этого я думаю:
public class MyClass
{
private static object lockObject = new object(); // global locking object
public void Page_Load()
{
string cachekey = "preventdupes:" + UserId.ToString();
object userSpecificLock = null;
// This part would synchronize among all requests, but should be quick
// as it is simply trying to find out if a user-specific lock object
// exists, and if so, it gets it. Otherwise, it creates and stores it.
lock (lockObject)
{
userSpecificLock = HttpRuntime.Cache.Get(cachekey);
if (userSpecificLock == null)
{
userSpecificLock = new object();
// Cache the locking object on a sliding 30 minute window
HttpRuntime.Cache.Add(cachekey, userSpecificLock, null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
new TimeSpan(0, 30, 0),
System.Web.Caching.CacheItemPriority.AboveNormal, null);
}
}
// Now we have obtained an instance of an object specific to the user,
// and we'll lock the next block of code specifically to them.
lock (userSpecificLock)
{
try
{
// Perform some operations to check our database to see if the
// transaction already occurred for this user, and if not,
// perform the transaction, and then record it into our db.
}
catch (Exception)
{
// Rollback anything our code has done up until this exception,
// so that if the user tries again, it will work.
}
}
}
}
ConcurrentDictionary
UserId
в парыLock object
вместо прямого измененияHttpRuntime.Cache
. - person voithos   schedule 19.08.2014