0

In a .NET Core asp.net web application I'm building, tasks are initiated in a request; in certain scenarios, we want to await the completion of this task in another request.

To accomplish this, I've put in place a static dictionary that stores references to these tasks:

 public static volatile Dictionary<int, Task> MyTasks = new Dictionary<int, Task>();

Running tasks are awaited, if necessary, from separate requests:

 public static async Task GenerateMyData(int itemId, SomeOtherData data)
 {
     var curTask = MyTasks.Get(itemId); //<- extension method wrapper for TryGetValue
     if (curTask != null && !curTask.IsCompleted)
     {
         await curTask;
     }

     var newTask = Task.Run(async () =>
     {
          AddPrimaryData(itemId, data);
          await AddImageData(itemId, data);
          MyTasks[itemId] = null;
     });

     MyTasks[itemId] = newTask;

}

While it works in my development environment and as web-app under a light load, the more I read about async/await the more unsure I am if this will function as expected under a heavier load. Does this method appear to be safe for an asp.net core 2.1 web app?

Adam K
  • 153
  • 3
  • 8

1 Answers1

2

It's better to use the thread-safe ConcurrentDictionary<TKey,TValue> Class. Making a classic collection volatile alone doesn't make it thread-safe. You would have to enclose all the operations in a lock statement.

You add items with (ConcurrentDictionary<TKey,TValue> Class)

bool success = dict.TryAdd(itemId, data);

And retrieve them with

bool success = dict.TryGetValue(itemId, out data);

There are also methods like TryRemove and TryUpdate.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • Be aware that `TryGetValue` leaves the item in the collection, where another thread could find it. It would still work (a `Task` can be awaited more than once, and each time it will get the same value), but I'm not sure that's what you want. If it should only ever be found once, then use [`TryRemove`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentdictionary-2.tryremove), which will return the value and remove it from the collection. – Gabriel Luci Aug 10 '19 at 04:25