title: How to preserve await behavior with TaskCompletionSource.SetException?
body: <p>(This is a new attempt at this question which now demonstrates the issue better.)</p>
  
  <p>Let's say we have a faulted task (<code>var faultedTask = Task.Run(() =&gt; { throw new Exception("test"); });</code>) and we await it. <code>await</code> will unpack the <code>AggregateException</code> and throw the underlying exception. It will throw <code>faultedTask.Exception.InnerExceptions.First()</code>.</p>
  
  <p>According to the source code for <code>ThrowForNonSuccess</code> it will do this by executing any stored <code>ExceptionDispatchInfo</code> presumably to preserve nice stack traces. It will not unpack the <code>AggregateException</code> if there is no <code>ExceptionDispatchInfo</code>.</p>
  
  <p>This fact alone was surprising to me because the documentation states that the first exception is <em>always</em> thrown: <a href="https://msdn.microsoft.com/en-us/library/hh156528.aspx?f=255&amp;MSPPError=-2147217396">https://msdn.microsoft.com/en-us/library/hh156528.aspx?f=255&amp;MSPPError=-2147217396</a> It turns out that <code>await</code> can throw <code>AggregateException</code>, though, which is not documented behavior.</p>
  
  <p>This becomes a problem when we want to create a proxy task and set it's exception:</p>
  
  <pre><code>var proxyTcs = new TaskCompletionSource&lt;object&gt;();
  proxyTcs.SetException(faultedTask.Exception);
  await proxyTcs.Task;
  </code></pre>
  
  <p>This throws <code>AggregateException</code> whereas <code>await faultedTask;</code> would have thrown the test exception.</p>
  
  <p><strong>How can I create a proxy task that I can complete at will and that will mirror the exception behavior that the original task had?</strong></p>
  
  <p><strong>The original behavior is:</strong></p>
  
  <ol>
  <li><code>await</code> will throw the first inner exception.</li>
  <li>All exceptions are still available through <code>Task.Exception.InnerExceptions</code>. (An earlier version of this question left out this requirement.)</li>
  </ol>
  
  <p>Here's a test that summarizes the findings:</p>
  
  <pre><code>[TestMethod]
  public void ExceptionAwait()
  {
      ExceptionAwaitAsync().Wait();
  }
  
  static async Task ExceptionAwaitAsync()
  {
      //Task has multiple exceptions.
      var faultedTask = Task.WhenAll(Task.Run(() =&gt; { throw new Exception("test"); }), Task.Run(() =&gt; { throw new Exception("test"); }));
  
      try
      {
          await faultedTask;
          Assert.Fail();
      }
      catch (Exception ex)
      {
          Assert.IsTrue(ex.Message == "test"); //Works.
      }
  
      Assert.IsTrue(faultedTask.Exception.InnerExceptions.Count == 2); //Works.
  
      //Both attempts will fail. Uncomment attempt 1 to try the second one.
      await Attempt1(faultedTask);
      await Attempt2(faultedTask);
  }
  
  static async Task Attempt1(Task faultedTask)
  {
      var proxyTcs = new TaskCompletionSource&lt;object&gt;();
      proxyTcs.SetException(faultedTask.Exception);
  
      try
      {
          await proxyTcs.Task;
          Assert.Fail();
      }
      catch (Exception ex)
      {
          Assert.IsTrue(ex.Message == "test"); //Fails.
      }
  }
  
  static async Task Attempt2(Task faultedTask)
  {
      var proxyTcs = new TaskCompletionSource&lt;object&gt;();
      proxyTcs.SetException(faultedTask.Exception.InnerExceptions.First());
  
      try
      {
          await proxyTcs.Task;
          Assert.Fail();
      }
      catch (Exception ex)
      {
          Assert.IsTrue(ex.Message == "test"); //Works.
      }
  
      Assert.IsTrue(proxyTcs.Task.Exception.InnerExceptions.Count == 2); //Fails. Should preserve both exceptions.
  }
  </code></pre>
  
  <p>The motivation for this question is that I'm trying to construct a function that will copy the result of one task over to a <code>TaskCompletionSource</code>. This is a helper function that's used often when writing task combinator functions. It's important that API clients cannot detect the difference between the original task and a proxy task.</p>