You need to synchronize the access to CalculateSha256 method that only one thread will execute it at a time.
Since lock
statement does not play nicely with async you can use SemaphoreSlim
class.
Just add it as a static field to your controller:
private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
And use WaitAsync method in your action (and do not forget to release it when you finish, using finally block):
public async Task<string> Get(string value)
{
await _semaphoreSlim.WaitAsync();
try
{
return await CalculateSha256(value);
}
finally
{
_semaphoreSlim.Release();
}
}
If you find this approach useful and you do not like to reapeat the try finally block you can create a base controller class with a protected generic helper:
protected async Task<T> GetConsecutively(Func<Task<T>> taskFactory)
{
await _semaphoreSlim.WaitAsync();
try
{
return await taskFactory();
}
finally
{
_semaphoreSlim.Release();
}
}
And modify Get method to pass a lambda expression to it:
public async Task<string> Get(string value)
{
return await GetConsecutively(() => CalculateSha256(value));
}
Or alternatively use Stephen Cleary's AsyncLock
instead of SemaphoreSlim
which supports a high level API closer to the lock
statement:
private static readonly AsyncLock _asyncLock = new AsyncLock();
public async Task<string> Get(string value)
{
//Notice the use of using block
//instead of try and finally
using(await _asyncLock.LockAsync())
{
return await CalculateSha256(value);
}
}