title: Strategy for Managing Long-Running Tasks in ASP.NET Web Forms
body: <p>We have some logic to calculate an expensive value per user for our ASP.NET Web Forms application. Currently it sits in the <code>Page_Load</code> header user control that is on every page like this:</p>
  
  <pre><code>//note that we are not awaiting this
  Task.Factory.StartNew(() =&gt; CacheManager.GetExpensiveValue(UserId));
  </code></pre>
  
  <p>And then in the static <code>CacheManager.GetExpensiveValue(int userID)</code>:</p>
  
  <pre><code>private static object locker = new object();
  
  lock (locker)
  {
      if (!AlreadyDone(userID))
      {
          var expensiveValue = ReallyExpensiveMethod(userID);
          //our static cache wrapper class that uses an ObjectCache object
          OurCache.Add(userID, expensiveValue);
      }
      else
      {
          return OurCache.Get(userID);
      }
  }
  </code></pre>
  
  <p>This works, but when <code>ReallyExpensiveMethod()</code> takes a REALLY long time (I'm also working on improving the performance of the logic behind that), users will block on that <code>lock</code> when navigating between pages. </p>
  
  <p>My question is, how could I restructure this to not cause blocking? I've thought about utilizing a ConcurrentDictionary with the values in the dictionary being Task wrappers for <code>ReallyExpensiveMethod()</code> and the keys being the UserID to prevent duplicate work, but I'm unsure if that would actually get me anywhere. </p>
  
  <p>We currently are not using any asynchronous logic in this app, and I'm sure the powers-that-be would rather not introduce a change that would require adding <code>Async="true"</code> to every single page in the app since this header logic is in every page.</p>