У меня есть веб-метод загрузки транзакции (веб-службы ASMX), которые берут XML-файл, проверяют файл и сохраняют содержимое файла в базе данных SQL-сервера. мы заметили, что некоторые пользователи могут одновременно отправить один и тот же файл в одно и то же время. поэтому мы можем снова использовать те же коды в нашей базе данных (мы не можем использовать уникальный индекс в базе данных или делать что-либо на уровне базы данных, не спрашивайте меня почему). Я думал, что могу использовать оператор блокировки для строки идентификатора пользователя, но я не знаю, решит ли это проблему. или если я могу использовать обложенный объект для хранения всех запросов идентификатора пользователя и проверить, есть ли у нас 2 запроса от того же идентификатора пользователя, мы выполним первый и заблокируем второй запрос с сообщением об ошибке , поэтому, если у кого-нибудь есть идеи, пожалуйста, помогитеблокировать множественный запрос от одного и того же идентификатора пользователя к веб-методу C#
ответ
Блокировка строк неверна. Блокировка вашего веб-сервера плохая.
AsyncLocker
- удобный класс, который я написал, чтобы разрешить блокировку любого типа, который хорошо ведет себя как ключ в словаре. Он также требует асинхронной ожидании перед входом в критическую секцию (в отличие от нормального поведения блокировки замков):
public class AsyncLocker<T>
{
private LazyDictionary<T, SemaphoreSlim> semaphoreDictionary =
new LazyDictionary<T, SemaphoreSlim>();
public async Task<IDisposable> LockAsync(T key)
{
var semaphore = semaphoreDictionary.GetOrAdd(key,() => new SemaphoreSlim(1,1));
await semaphore.WaitAsync();
return new ActionDisposable(() => semaphore.Release());
}
}
Это зависит от следующих двух вспомогательных классов:
LazyDictionary:
public class LazyDictionary<TKey,TValue>
{
//here we use Lazy<TValue> as the value in the dictionary
//to guard against the fact the the initializer function
//in ConcurrentDictionary.AddOrGet *can*, under some conditions,
//run more than once per key, with the result of all but one of
//the runs being discarded.
//If this happens, only uninitialized
//Lazy values are discarded. Only the Lazy that actually
//made it into the dictionary is materialized by accessing
//its Value property.
private ConcurrentDictionary<TKey, Lazy<TValue>> dictionary =
new ConcurrentDictionary<TKey, Lazy<TValue>>();
public TValue GetOrAdd(TKey key, Func<TValue> valueGenerator)
{
var lazyValue = dictionary.GetOrAdd(key,
k => new Lazy<TValue>(valueGenerator));
return lazyValue.Value;
}
}
ActionDisposable:
public sealed class ActionDisposable:IDisposable
{
//useful for making arbitrary IDisposable instances
//that perform an Action when Dispose is called
//(after a using block, for instance)
private Action action;
public ActionDisposable(Action action)
{
this.action = action;
}
public void Dispose()
{
var action = this.action;
if(action != null)
{
action();
}
}
}
Теперь, если вы держите ул матический экземпляр этого где-то:
static AsyncLocker<string> userLock = new AsyncLocker<string>();
вы можете использовать его в async
методы, используя прелести IDisposable
возвратного типа LockAsync
«s, чтобы написать using
заявления, аккуратно облегает критическую секцию:
using(await userLock.LockAsync(userId))
{
//user with userId only allowed in this section
//one at a time.
}
Если нам нужно подождать до ввода, это будет сделано асинхронно, освобождая поток для обслуживания других запросов, вместо того, чтобы блокировать до тех пор, пока не закончится ожидание и потенциально испортит производительность вашего сервера под нагрузкой.
Конечно, если вам нужно масштабировать более чем на один веб-сервер, этот подход больше не будет работать, и вам нужно будет синхронизировать его с помощью другого средства (возможно, через БД).
спасибо за ваш быстрый ответ, позвольте мне попробовать это и дать вам мою обратную связь , – Sharif
На самом деле у меня около 2000 просмотров в секунду на этом веб-сервисе от разных клиентов. что мне нужно, чтобы заблокировать несколько запросов к одной и той же веб-службе от одного и того же клиента на основе идентификатора пользователя (все пользователи могут ударить по веб-методу один раз за раз) – Sharif
Отличный ответ spender !! –
Содержится в точном дубликате? Разрешены ли дубликаты? Если нет, вы можете просто отказаться от повторяющихся запросов (если они дважды отправят контент, но _far_, чтобы избежать блокировки) –
Никогда не блокируйте строки. Когда-либо. В самом деле. http://stackoverflow.com/questions/12804879/is-it-ok-to-use-a-string-as-a-lock-object – spender