I'm required to do not allow more than one invocation at a time for an API, based on single query param. Parallel invocation with different values of the query param must be allowed.
I invoke the api through
await client.GetAsync(QueryHelpers.AddQueryString(path, parameters))
So, there is an async invocation that do not allows me to use System.Threading.Monitor.TryEnter beacause when I try to release the lock I got the exception:
System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code.
Here's the snippet
try
{
Monitor.TryEnter(lockObj, timeout, ref lockTaken);
if (lockTaken)
{
List<PatientData> patients = await RetrievePatientsDataAsync(client, new Dictionary<string, string>
{
["customerNo"] = customerNo,
["offset"] = _lindeAPIOptions.Offset,
["pagesize"] = _lindeAPIOptions.Pagesize
});
data.Patients = patients;
return data;
}
}
finally
{
// Ensure that the lock is released.
if (lockTaken)
{
Monitor.Exit(lockObj);
}
}
The parameter is customerNo. In method RetrievePatientsDataAsync i call the aforementioned
await client.GetAsync(QueryHelpers.AddQueryString(path, parameters))
You could possibly keep a list of all the ids that are "locked", something like this:
The key part here is to not hold the lock while the actual method is running, or when doing any awaiting etc. You could probably do something similar with a ConcurrentDictionary, but the overhead of a lock should be low if there is low contention.